Code-Design Frage, Singleton Klasse oder doch ganz anders?

  • ASP.NET

Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von seh.

    Code-Design Frage, Singleton Klasse oder doch ganz anders?

    Hallo,

    ich bin aktuell dabei mich ein wenig in die API-Entwicklung mit ASP.Net ,(Core) um genau zu sein, einzuarbeiten.

    Ich bastle aktuell eine Art Authentifizierungssystem. Man loggt sich z.B. mit Benutzer und Passwort ein, und mit EF-Core gleiche ich die Daten mit der Datenbank ab.
    Jetzt möchte ich, falls eine Authentifizierung mit Benutzer und Passwort erfolgreich war, einen Token (Guid) generieren der solange gültig ist, wie der ASP.NET API Server läuft.
    Den Token benutzt man, um später einen anderen API Endpunkt aufzurufen und sich bei diesem zu authentifizieren.

    Meine Idee also: Eine Klasse TokenManager basteln, die ein Dictionary<DbUser, Guid> enthält und diese als Singleton im Service Provider registrieren.
    Authentifiziert sich ein Benutzer also mit Benutzername und Passwort erfolgreich, wird diese Benutzer-Entität (DbUser) in dem TokenManager im Dictionary zusammen mit einem neu-generierten Guid festgehalten.

    Authentifiziert sich ein Benutzer mit dem Token bei einem anderen Endpunkt der API, soll in diesem Endpunkt auch wieder per Singleton auf den TokenManager zugegriffen werden und das Dictionary eben nach dem Guid durchsucht werden. Wird der Token gefunden, ist die Authentifizierung erfolgreich, wenn nicht, dann nicht und es kann entsprechend reagiert werden.

    Auf diese Weise habe ich es schon ausprobiert, leider musste ich feststellen, dass es nicht möglich ist meinen DbContext in einer Singleton Klasse per Dependency Injection zu injizieren.
    Was Dependency Injection angeht bin ich auch noch nicht so bewandert. Ich weiß es gibt verschiedene Arten von DI. Ich habe versucht die Construktor DI zu nutzen

    Meine Singleton Klasse TokenManager hat im Konstruktor den DbContext Parameter. Leider bekomme ich dann aber immer folgende Fehlermeldung: System.InvalidOperationException: Cannot consume scoped service 'API.Contexts.MyContext' from singleton 'API.Services.TokenManager'.
    Wenn ich statt AddSingleton, AddTransient benutze, funktioniert die DI prima und ich kann den DbContext nutzen. Nur bei Singleton geht es nicht. Transient nutzt mir aber nichts, weil das Objekt dann ja immer neu erstellt wird und die Tokens dann futsch sind.

    Ich könnte jetzt natürlich anfangen und den TokenManager nicht als Service registrieren sondern einfach eine statische Singleton-Variable selbst anzulegen, aber ich will mal wissen was ihr davon haltet und ob es vielleicht eine einfachere bzw. sauberere Lösung gibt.

    Danke im Voraus und für's lange durchlesen.

    Gruß seh
    Leider kann ich dir zum eigentlichen Problem nicht wirklich weiterhelfen. Aber ich möchte folgendes trotzdem gesagt haben:

    Disclaimer:
    Ich hatte zwar Computer Security im Studium, aber das macht mich nicht automatisch zu einem Profi auf dem Gebiet. Die nachfolgenden Aussagen sind deshalb als eine auf Sachkenntnis gestützte Vermutung zu betrachten.

    So ein Token darf nicht vorhersehbar sein. Eine GUID ist, besonders wenn es die Version mit Zeit und MAC-Adresse ist, nicht kryptographisch sicher. Das heißt, ich kann das mit machbarem Aufwand vorhersagen. Also wenn Alice sich bei dir anmeldet und du GUID 0feae918-d193-4033-91a8-0eddb423c13d zurücksendest, ich das vorhersagen kann und dir dann Anfragen mit genau dieser GUID schicke, dann kann ich mich als Alice ausgeben.

    Ein Token muss also eine Kombination aus etwas Eindeutigem und etwas nicht-vorhersehbarem sein.
    Das Eindeutige kann wirklich eine GUID sein, oder auch z.B. eine inkrementierende Datenbanknummer.
    Das nicht-vorhersehbare muss eine kryptographisch sichere Zufallszahl mit ausreichender Länge sein. Hier bietet sich z.B. der System.Security.Cryptography.RNGCryptoServiceProvider an.

    Das Eindeutige kann ich vorhersehen, aber das ist nicht schlimm. Sogar wenn ich herausbekommen habe, dass Alice den eindeutigen Teil 0feae918-d193-4033-91a8-0eddb423c13d zugesendet bekommen hat, kann ich damit alleine nichts anfangen, weil mir noch der nicht-vorhersehbare Teil fehlt. Und den kann ich per Definition nicht vorhersagen.
    Und nur der nicht-vorhersehbare Teil reicht nicht als Token aus, weil es Duplikate geben kann (was bei großen Zufallszahlen zwar sehr unwahrscheinlich ist, aber doch passieren kann).
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Vielen Dank für die Erläuterung. Das macht auf jeden Fall Sinn. Dann weiß ich das für die Zukunft. Guid ist mir beim programmieren gerad so eingefallen weil ich da nicht extra selbst was generieren muss.

    Ich bastle dieses Verfahren auch nur zur Übung nach, ich habe nicht vor das für etwas anderes zu benutzen.

    Gruß seh