Ausgehend von Matt Dekreys fabelhafter Antwort habe ich ein voll funktionsfähiges Beispiel für die tokenbasierte Authentifizierung erstellt, das gegen ASP.NET Core (1.0.1) arbeitet. Den vollständigen Code finden Sie in diesem Repository auf GitHub (alternative Zweige für 1.0.0-rc1 , Beta8 , Beta7) ). , die wichtigsten Schritte sind:
Generieren Sie einen Schlüssel für Ihre Anwendung
In meinem Beispiel generiere ich bei jedem Start der App einen zufälligen Schlüssel. Sie müssen einen generieren, irgendwo speichern und Ihrer Anwendung zur Verfügung stellen. In dieser Datei erfahren Sie, wie ich einen zufälligen Schlüssel generiere und wie Sie ihn aus einer JSON-Datei importieren können . Wie in den Kommentaren von @kspearrin vorgeschlagen, scheint die Datenschutz-API ein idealer Kandidat für die "korrekte" Verwaltung der Schlüssel zu sein, aber ich habe noch nicht herausgefunden, ob dies möglich ist. Bitte senden Sie eine Pull-Anfrage, wenn Sie es ausarbeiten!
Startup.cs - ConfigureServices
Hier müssen wir einen privaten Schlüssel laden, mit dem unsere Token signiert werden sollen, mit dem wir auch die Token überprüfen, wenn sie präsentiert werden. Wir speichern den Schlüssel in einer Variablen auf Klassenebene, key
die wir in der folgenden Configure-Methode wiederverwenden. TokenAuthOptions ist eine einfache Klasse, die die Signaturidentität, die Zielgruppe und den Aussteller enthält, die wir im TokenController zum Erstellen unserer Schlüssel benötigen.
// Replace this with some sort of loading from config / file.
RSAParameters keyParams = RSAKeyUtils.GetRandomKey();
// Create the key, and a set of token options to record signing credentials
// using that key, along with the other parameters we will need in the
// token controlller.
key = new RsaSecurityKey(keyParams);
tokenOptions = new TokenAuthOptions()
{
Audience = TokenAudience,
Issuer = TokenIssuer,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.Sha256Digest)
};
// Save the token options into an instance so they're accessible to the
// controller.
services.AddSingleton<TokenAuthOptions>(tokenOptions);
// Enable the use of an [Authorize("Bearer")] attribute on methods and
// classes to protect.
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
Wir haben auch eine Autorisierungsrichtlinie eingerichtet, die es uns ermöglicht, sie [Authorize("Bearer")]
auf den Endpunkten und Klassen zu verwenden, die wir schützen möchten.
Startup.cs - Konfigurieren
Hier müssen wir die JwtBearerAuthentication konfigurieren:
app.UseJwtBearerAuthentication(new JwtBearerOptions {
TokenValidationParameters = new TokenValidationParameters {
IssuerSigningKey = key,
ValidAudience = tokenOptions.Audience,
ValidIssuer = tokenOptions.Issuer,
// When receiving a token, check that it is still valid.
ValidateLifetime = true,
// This defines the maximum allowable clock skew - i.e.
// provides a tolerance on the token expiry time
// when validating the lifetime. As we're creating the tokens
// locally and validating them on the same machines which
// should have synchronised time, this can be set to zero.
// Where external tokens are used, some leeway here could be
// useful.
ClockSkew = TimeSpan.FromMinutes(0)
}
});
TokenController
Im Token-Controller benötigen Sie eine Methode zum Generieren signierter Schlüssel mit dem in Startup.cs geladenen Schlüssel. Wir haben eine TokenAuthOptions-Instanz in Startup registriert, daher müssen wir diese in den Konstruktor für TokenController einfügen:
[Route("api/[controller]")]
public class TokenController : Controller
{
private readonly TokenAuthOptions tokenOptions;
public TokenController(TokenAuthOptions tokenOptions)
{
this.tokenOptions = tokenOptions;
}
...
Dann müssen Sie das Token in Ihrem Handler für den Anmeldeendpunkt generieren. In meinem Beispiel nehme ich einen Benutzernamen und ein Kennwort und überprüfe diese mithilfe einer if-Anweisung. Der Schlüssel, den Sie tun müssen, ist jedoch, Ansprüche zu erstellen oder zu laden -basierte Identität und generieren Sie das Token dafür:
public class AuthRequest
{
public string username { get; set; }
public string password { get; set; }
}
/// <summary>
/// Request a new token for a given username/password pair.
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpPost]
public dynamic Post([FromBody] AuthRequest req)
{
// Obviously, at this point you need to validate the username and password against whatever system you wish.
if ((req.username == "TEST" && req.password == "TEST") || (req.username == "TEST2" && req.password == "TEST"))
{
DateTime? expires = DateTime.UtcNow.AddMinutes(2);
var token = GetToken(req.username, expires);
return new { authenticated = true, entityId = 1, token = token, tokenExpires = expires };
}
return new { authenticated = false };
}
private string GetToken(string user, DateTime? expires)
{
var handler = new JwtSecurityTokenHandler();
// Here, you should create or look up an identity for the user which is being authenticated.
// For now, just creating a simple generic identity.
ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user, "TokenAuth"), new[] { new Claim("EntityID", "1", ClaimValueTypes.Integer) });
var securityToken = handler.CreateToken(new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor() {
Issuer = tokenOptions.Issuer,
Audience = tokenOptions.Audience,
SigningCredentials = tokenOptions.SigningCredentials,
Subject = identity,
Expires = expires
});
return handler.WriteToken(securityToken);
}
Und das sollte es sein. Fügen [Authorize("Bearer")]
Sie einfach eine Methode oder Klasse hinzu, die Sie schützen möchten, und Sie sollten eine Fehlermeldung erhalten, wenn Sie versuchen, ohne vorhandenes Token darauf zuzugreifen. Wenn Sie einen 401-Fehler anstelle eines 500-Fehlers zurückgeben möchten, müssen Sie einen benutzerdefinierten Ausnahmebehandler registrieren, wie ich ihn in meinem Beispiel hier habe .