wake-up-neo.net

Wie erhalte ich den aktuellen Benutzer in der .NET Core Web API (von JWT Token)

Nach vielen Schwierigkeiten (und vielen Anleitungen, Anleitungen usw.) gelang es mir, eine kleine .NET Core REST - Web-API mit einem Auth-Controller einzurichten, der JWT-Token ausgibt, wenn Benutzername und Kennwort gespeichert sind.

Das Token speichert die Benutzer-ID als Unteranspruch.

Es ist mir auch gelungen, die Web-API einzurichten, um diese Token zu überprüfen, wenn eine Methode die Autorisierungsanmerkung verwendet.

  app.UseJwtBearerAuthentication (...)

Nun meine Frage: Wie lese ich die Benutzer-ID (die im Antragsanspruch gespeichert ist) in meinen Controllern (in einer Web-API)?

Es ist im Grunde diese Frage ( Wie bekomme ich aktuelle Benutzer in ASP .NET Core ), aber ich brauche eine Antwort für eine Web-API. Und ich habe keinen UserManager. Also muss ich den Sachverhalt von irgendwo lesen.

16
monty

Sie können diese Methode verwenden:

var email = User.FindFirst("sub")?.Value;

In meinem Fall verwende ich die E-Mail als eindeutigen Wert

11
Ateik

Die akzeptierte Antwort hat bei mir nicht funktioniert. Ich bin nicht sicher, ob das von mir verursacht wird, wenn ich .NET Core 2.0 oder etwas anderes verwendet, aber es sieht so aus, als würde das Framework den Antragsanspruch auf einen NameIdentifier-Anspruch zuordnen. Also hat folgendes für mich funktioniert:

string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

Beachten Sie, dass davon ausgegangen wird, dass der Antrag sub Claim in der JWT festgelegt ist und dessen Wert die ID des Benutzers ist.

Standardmäßig ordnet der JWT-Authentifizierungshandler in .NET den Unteranspruch eines JWT-Zugriffstokens dem System.Security.Claims.ClaimTypes.NameIdentifier-Anspruchstyp zu. [Quelle]

Es gibt auch einen Diskussionsthread auf GitHub , in dem sie zu dem Schluss kommen, dass dieses Verhalten verwirrend ist.

15
Honza Kalfus

Es sieht so aus, als würden sich viele Leute mit dieser Frage befassen. Ich möchte daher einige weitere Informationen mitteilen, die ich gelernt habe, seit ich die Frage vor einiger Zeit gestellt habe. Es macht einige Dinge klarer (zumindest für mich) und war nicht so offensichtlich (für mich als .NET-Neuling).

Wie Marcus Höglund in den Kommentaren erwähnt:

Dies sollte für "Web-API" identisch sein. In ASP.NET Core werden Mvc und Web-API zusammengeführt, um denselben Controller zu verwenden.

Das ist definitiv wahr und absolut richtig.


Weil es in .NET und .NET Core alle gleich ist.

Damals war ich neu in .NET Core und in der gesamten .NET-Welt. Die wichtige fehlende Information war, dass in .NET und .NET Core die gesamte Authentifizierung auf den Namespace System.Security.Claims mit ClaimsIdentity, ClaimsPrinciple und Claims.Properties reduziert werden kann. Daher wird es in beiden .NET Core-Controllertypen (API und MVC oder Razor oder ...) verwendet und ist über HttpContext.User Zugänglich.

Eine wichtige Randnotiz, die in allen Tutorials übersehen wurde.

Wenn Sie also mit JWT-Token in .NET etwas anfangen, vergessen Sie nicht, sich auch mit ClaimsIdentity , ClaimsPrinciple und Claim.Properties . Darum geht es. Jetzt weißt du es. Es wurde von Heringer in einem der Kommentare darauf hingewiesen.


[~ # ~] alle [~ # ~] anspruchsbasierten Authentifizierungs-Middlewares füllen (falls korrekt implementiert) den HttpContext.User mit dem Ansprüche während der Authentifizierung erhalten.

Soweit ich das jetzt verstehe, kann man sich auf die Werte im HttpContext.User Verlassen. Aber warten Sie , um zu wissen, was Sie bei der Auswahl der Middleware beachten müssen. Es gibt bereits viele verschiedene Authentifizierungs-Middleware (zusätzlich zu .UseJwtAuthentication()).

Mit kleinen benutzerdefinierten Erweiterungsmethoden können Sie jetzt die aktuelle Benutzer-ID (genauer gesagt den Betreff) auf diese Weise ermitteln

 public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value; }

Oder du verwendest die Version in der Antwort von Ateik .


ABER WARTEN : Es gibt eine seltsame Sache

Das nächste, was mich damals verwirrte, war: Laut OpenID Connect-Spezifikation habe ich nach einem "Unter" -Anspruch (dem aktuellen Benutzer) gesucht, ihn aber nicht gefunden. Wie konnte Honza Kalfus in seiner Antwort nicht tun.

Warum?

Weil Microsoft "manchmal" "ein bisschen" anders ist. Oder zumindest machen sie ein bisschen mehr (und unerwartete) Dinge. Zum Beispiel die in der ursprünglichen Frage erwähnte offizielle Microsoft JWT Bearer-Authentifizierungs-Middleware. Microsoft hat beschlossen, Ansprüche (die Namen der Ansprüche) in alle offiziellen Authentifizierungs-Middlewares umzuwandeln (aus Kompatibilitätsgründen, die ich nicht näher kenne).

Sie werden keine "Unter" -Ansprüche finden (obwohl es sich um die einzige von OpenID Connect angegebene Forderung handelt). Weil es in diese ausgefallenen ClaimTypes konvertiert wurde. Es ist nicht alles schlecht, es ermöglicht Ihnen das Hinzufügen von Zuordnungen, wenn Sie verschiedene Ansprüche in einen eindeutigen internen Namen abbilden müssen.

Entweder bleiben Sie bei der Microsoft-Benennung (und müssen beachten, dass Sie eine Nicht-Microsoft-Middleware hinzufügen/verwenden), oder Sie finden heraus, wie Sie die Claim-Zuordnung für die Microsoft-Middleware ändern können.

Im Falle der JwtBearerAuthentication ist dies erledigt (tun Sie dies frühzeitig in StartUp oder zumindest vor dem Hinzufügen der Middleware):

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

Wenn Sie bei den Microsoft-Bezeichnungen bleiben möchten, behaupten Sie das Thema (schlagen Sie mich nicht, ich bin mir im Moment nicht sicher, ob Name die richtige Zuordnung ist):

    public static string SubjectId(this ClaimsPrincipal user) { return user?.Claims?.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier, StringComparison.OrdinalIgnoreCase))?.Value; }

Beachten Sie, dass die anderen Antworten die fortgeschrittenere und bequemere Methode FindFirst verwenden. Obwohl meine Codebeispiele es ohne diese zeigen, sollten Sie mit ihnen gehen.

So werden alle Ihre Ansprüche gespeichert und sind (über den einen oder anderen Namen) im HttpContext.User Zugänglich.


Aber wo ist mein Token?

Ich weiß es nicht für die andere Middleware, aber die JWT-Bearer-Authentifizierung ermöglicht das Speichern des Tokens für jede Anforderung. Dies muss jedoch aktiviert werden (in StartUp.ConfigureServices(...).

services
  .AddAuthentication("Bearer")
  .AddJwtBearer("Bearer", options => options.SaveToken = true);

Auf das eigentliche Token (in seiner kryptischen Form) als String (oder Null) kann dann über zugegriffen werden

HttpContext.GetTokenAsync("Bearer", "access_token")

Es gibt eine ältere Version dieser Methode (dies funktioniert für mich in .NET Core 2.2 ohne veraltete Warnung).

Wenn Sie Werte aus dieser Zeichenfolge analysieren und extrahieren müssen, hilft möglicherweise die Frage , wie das JWT-Token dekodiert werden kann.


Nun, ich hoffe, diese Zusammenfassung hilft Ihnen auch.

5
monty

Ich habe den HttpContext benutzt und es funktioniert gut:

var email = string.Empty;
if (HttpContext.User.Identity is ClaimsIdentity identity)
{
    email = identity.FindFirst(ClaimTypes.Name).Value;
}
1
Wariored

Wenn Sie Name verwenden, um die ID hier zu speichern:

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
    Expires = DateTime.UtcNow.AddDays(7),
    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};

In jeder Controller-Methode können Sie die ID des aktuellen Benutzers herunterladen, indem Sie:

var claimsIdentity = this.User.Identity as ClaimsIdentity;
var userId = claimsIdentity.FindFirst(ClaimTypes.Name)?.Value;
1
ImpoUserC

sie können dies mit tun.

User.Identity.Name

0