Ich habe diese Frage beantwortet: So sichern Sie eine ASP.NET-Web-API vor 4 Jahren mit HMAC.
Jetzt haben sich viele Dinge in Bezug auf die Sicherheit geändert, insbesondere JWT wird immer beliebter. Hier werde ich versuchen zu erklären, wie man JWT so einfach und grundlegend wie möglich verwendet, damit wir uns nicht aus dem Dschungel von OWIN, Oauth2, ASP.NET Identity ... :) verlieren.
Wenn Sie das JWT-Token nicht kennen, müssen Sie sich Folgendes genauer ansehen:
https://tools.ietf.org/html/rfc7519
Grundsätzlich sieht ein JWT-Token folgendermaßen aus:
<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>
Beispiel:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1NzI0LCJleHAiOjE0Nzc1NjY5MjQsImlhdCI6MTQ3NzU2NTcyNH0.6MzD1VwA5AcOcajkFyKhLYybr3h13iZjDyHm9zysDFQ
Ein JWT-Token besteht aus drei Abschnitten:
- Header: JSON-Format, das in Base64 codiert ist
- Ansprüche: JSON-Format, das in Base64 codiert ist.
- Signatur: Erstellt und signiert basierend auf Header und Ansprüchen, die in Base64 codiert sind.
Wenn Sie die Website jwt.io mit dem obigen Token verwenden, können Sie das Token dekodieren und wie folgt anzeigen :
Technisch gesehen verwendet JWT eine Signatur, die von Headern und Ansprüchen mit dem in den Headern angegebenen Sicherheitsalgorithmus signiert ist (Beispiel: HMACSHA256). Daher muss JWT über HTTPs übertragen werden, wenn Sie vertrauliche Informationen in Ansprüchen speichern.
Um die JWT-Authentifizierung verwenden zu können, benötigen Sie keine OWIN-Middleware, wenn Sie über ein älteres Web-API-System verfügen. Das einfache Konzept besteht darin, ein JWT-Token bereitzustellen und das Token zu validieren, wenn die Anforderung eingeht. Das ist es.
Zurück zur Demo, um JWT-Token leicht zu halten, speichere ich nur username
und expiration time
in JWT. Auf diese Weise müssen Sie jedoch eine neue lokale Identität (Principal) neu erstellen, um weitere Informationen hinzuzufügen, z. B.: Rollen .., wenn Sie eine Rollenautorisierung durchführen möchten. Wenn Sie jedoch weitere Informationen zu JWT hinzufügen möchten, liegt es an Ihnen: Es ist sehr flexibel.
Anstatt die OWIN-Middleware zu verwenden, können Sie einfach einen JWT-Token-Endpunkt bereitstellen, indem Sie die Aktion des Controllers verwenden:
public class TokenController : ApiController
{
// This is naive endpoint for demo, it should use Basic authentication
// to provide token or POST request
[AllowAnonymous]
public string Get(string username, string password)
{
if (CheckUser(username, password))
{
return JwtManager.GenerateToken(username);
}
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
public bool CheckUser(string username, string password)
{
// should check in the database
return true;
}
}
Dies ist eine naive Handlung; In der Produktion sollten Sie eine POST-Anforderung oder einen Basisauthentifizierungsendpunkt verwenden, um das JWT-Token bereitzustellen.
Wie wird das Token basierend auf generiert username
?
Sie können das System.IdentityModel.Tokens.Jwt
von Microsoft aufgerufene NuGet-Paket verwenden , um das Token zu generieren, oder sogar ein anderes Paket, wenn Sie möchten. In der Demo verwende ich HMACSHA256
mit SymmetricKey
:
/// <summary>
/// Use the below code to generate symmetric Secret Key
/// var hmac = new HMACSHA256();
/// var key = Convert.ToBase64String(hmac.Key);
/// </summary>
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";
public static string GenerateToken(string username, int expireMinutes = 20)
{
var symmetricKey = Convert.FromBase64String(Secret);
var tokenHandler = new JwtSecurityTokenHandler();
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
}),
Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(symmetricKey),
SecurityAlgorithms.HmacSha256Signature)
};
var stoken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(stoken);
return token;
}
Der Endpunkt für die Bereitstellung des JWT-Tokens ist fertig. Wie kann nun die JWT validiert werden, wenn die Anfrage eingeht? In der Demo habe ich gebaut,
JwtAuthenticationAttribute
welche erbt IAuthenticationFilter
(mehr Details zum Authentifizierungsfilter hier ).
Mit diesem Attribut können Sie jede Aktion authentifizieren: Sie müssen dieses Attribut nur für diese Aktion festlegen.
public class ValueController : ApiController
{
[JwtAuthentication]
public string Get()
{
return "value";
}
}
Sie können auch OWIN Middleware oder DelegateHander verwenden, wenn Sie alle eingehenden Anforderungen für Ihre WebAPI überprüfen möchten (nicht spezifisch für Controller oder Aktion).
Nachfolgend finden Sie die Kernmethode des Authentifizierungsfilters:
private static bool ValidateToken(string token, out string username)
{
username = null;
var simplePrinciple = JwtManager.GetPrincipal(token);
var identity = simplePrinciple.Identity as ClaimsIdentity;
if (identity == null)
return false;
if (!identity.IsAuthenticated)
return false;
var usernameClaim = identity.FindFirst(ClaimTypes.Name);
username = usernameClaim?.Value;
if (string.IsNullOrEmpty(username))
return false;
// More validate to check whether username exists in system
return true;
}
protected Task<IPrincipal> AuthenticateJwtToken(string token)
{
string username;
if (ValidateToken(token, out username))
{
// based on username to get more information from database
// in order to build local identity
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
// Add more claims if needed: Roles, ...
};
var identity = new ClaimsIdentity(claims, "Jwt");
IPrincipal user = new ClaimsPrincipal(identity);
return Task.FromResult(user);
}
return Task.FromResult<IPrincipal>(null);
}
Der Workflow besteht darin, mithilfe der JWT-Bibliothek (NuGet-Paket oben) das JWT-Token zu validieren und dann zurückzukehren ClaimsPrincipal
. Sie können weitere Überprüfungen durchführen, z. B. prüfen, ob Benutzer auf Ihrem System vorhanden sind, und bei Bedarf weitere benutzerdefinierte Überprüfungen hinzufügen. Der Code zum Validieren des JWT-Tokens und zum Zurückerhalten des Principals:
public static ClaimsPrincipal GetPrincipal(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
if (jwtToken == null)
return null;
var symmetricKey = Convert.FromBase64String(Secret);
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
return principal;
}
catch (Exception)
{
//should write log
return null;
}
}
Wenn das JWT-Token validiert ist und der Principal zurückgegeben wird, sollten Sie eine neue lokale Identität erstellen und weitere Informationen einfügen, um die Rollenautorisierung zu überprüfen.
Denken Sie daran, config.Filters.Add(new AuthorizeAttribute());
im globalen Bereich eine Standardautorisierung hinzuzufügen , um anonyme Anforderungen an Ihre Ressourcen zu vermeiden.
Sie können Postman verwenden, um die Demo zu testen:
Token anfordern (naiv wie oben erwähnt, nur zur Demo):
GET http://localhost:{port}/api/token?username=cuong&password=1
Fügen Sie das JWT-Token für eine autorisierte Anforderung in den Header ein. Beispiel:
GET http://localhost:{port}/api/value
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s
Die Demo finden Sie hier: https://github.com/cuongle/WebApi.Jwt
hmac = new HMACSHA256();var key = Convert.ToBase64String(hmac.Key);
Ich habe es mit minimalem Aufwand geschafft (genauso einfach wie mit ASP.NET Core).
Dafür benutze ich OWIN
Startup.cs
Datei undMicrosoft.Owin.Security.Jwt
Bibliothek.Damit die App erscheint, müssen
Startup.cs
wir Folgendes ändernWeb.config
:So
Startup.cs
sollte es aussehen:Viele von euch verwenden heutzutage ASP.NET Core. Wie Sie sehen, unterscheidet es sich nicht wesentlich von dem, was wir dort haben.
Es hat mich zuerst wirklich verwirrt, ich habe versucht, benutzerdefinierte Anbieter usw. zu implementieren. Aber ich habe nicht erwartet, dass es so einfach ist.
OWIN
nur rockt!Nur eine Sache zu erwähnen - nachdem ich die OWIN-Startbibliothek aktiviert habe,
NSWag
funktioniert sie nicht mehr für mich (z. B. möchten einige von Ihnen möglicherweise automatisch Typoskript-HTTP-Proxys für die Angular-App generieren).Die Lösung war auch sehr einfach - ich ersetzte
NSWag
durchSwashbuckle
und hatte keine weiteren Probleme.Ok, jetzt
ConfigHelper
Code teilen :Ein weiterer wichtiger Aspekt: Ich habe JWT-Token über den Authorization- Header gesendet , sodass der Typoskript-Code für mich wie folgt aussieht:
(Der folgende Code wird von NSWag generiert. )
Siehe Überschriften Teil -
"Authorization": "Bearer " + localStorage.getItem('token')
quelle
I replaced NSWag with Swashbuckle and didn't have any further issues.
Hat Swashbuckle die Fähigkeit, Typoskriptdateien zu generieren, oder haben Sie diese selbst hinzugefügt?Hier ist eine sehr minimale und sichere Implementierung einer anspruchsbasierten Authentifizierung mithilfe eines JWT-Tokens in einer ASP.NET Core-Web-API.
Zunächst müssen Sie einen Endpunkt verfügbar machen, der ein JWT-Token mit einem Benutzer zugewiesenen Ansprüchen zurückgibt:
jetzt müssen Sie Authentifizierung auf Ihre Dienste in Ihrer hinzufügen
ConfigureServices
in Ihrem startup.cs JWT - Authentifizierung als Standard - Authentifizierungsdienst wie folgt hinzuzufügen:Jetzt können Sie Ihren Autorisierungsdiensten folgende Richtlinien hinzufügen:
ALTERNATIV können Sie auch (nicht erforderlich) alle Ihre Ansprüche aus Ihrer Datenbank ausfüllen , da diese beim Start Ihrer Anwendung nur einmal ausgeführt werden, und sie Richtlinien wie diesen hinzufügen:
Jetzt können Sie den Richtlinienfilter auf eine der Methoden anwenden, für die Sie wie folgt autorisiert werden möchten:
Hoffe das hilft
quelle
Ich denke, Sie sollten einen 3D-Party-Server verwenden, um das JWT-Token zu unterstützen, und es gibt keine sofort einsatzbereite JWT-Unterstützung in WEB API 2.
Es gibt jedoch ein OWIN-Projekt zur Unterstützung eines Formats eines signierten Tokens (nicht JWT). Es funktioniert als reduziertes OAuth-Protokoll und bietet nur eine einfache Form der Authentifizierung für eine Website.
Mehr dazu können Sie zB hier lesen .
Es ist ziemlich lang, aber die meisten Teile sind Details mit Controllern und ASP.NET-Identität, die Sie möglicherweise überhaupt nicht benötigen. Am wichtigsten sind
Dort können Sie lesen, wie Sie einen Endpunkt (z. B. "/ token") einrichten, auf den Sie vom Frontend aus zugreifen können (und Details zum Format der Anforderung).
Weitere Schritte enthalten Details zum Verbinden dieses Endpunkts mit der Datenbank usw. und Sie können die gewünschten Teile auswählen.
quelle
In meinem Fall wird das JWT von einer separaten API erstellt, sodass ASP.NET es nur dekodieren und validieren muss. Im Gegensatz zur akzeptierten Antwort verwenden wir RSA, einen nicht symmetrischen Algorithmus, sodass die
SymmetricSecurityKey
oben genannte Klasse nicht funktioniert.Hier ist das Ergebnis.
quelle