我从Matt Dekrey的精彩答案中得到灵感,创建了一个完全可用的基于令牌的身份验证示例,可用于与ASP.NET Core(1.0.1)配合使用。您可以在此GitHub存储库中找到完整代码(还有针对1.0.0-rc1,beta8,beta7 ),但简而言之,重要步骤如下:
为您的应用程序生成密钥
在我的示例中,我每次启动应用程序时都会生成一个随机密钥。您需要生成并存储某个密钥,并将其提供给您的应用程序。请查看此文件以了解如何生成随机密钥以及如何从.json文件中导入。如@kspearrin的评论所建议的那样,Data Protection API似乎是管理密钥“正确”的理想选择,但我尚未弄清楚是否可能。如果您想出来,请提交一个拉取请求!
Startup.cs - ConfigureServices
在这里,我们需要加载用于签署令牌的私钥,我们还将使用它来验证表示的令牌。我们将密钥存储在类级别变量key中,并在下面的Configure方法中重复使用它。TokenAuthOptions是一个简单的类,其中包含了我们在TokenController中创建密钥所需的签名标识、受众和发行者。
RSAParameters keyParams = RSAKeyUtils.GetRandomKey();
key = new RsaSecurityKey(keyParams);
tokenOptions = new TokenAuthOptions()
{
Audience = TokenAudience,
Issuer = TokenIssuer,
SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.Sha256Digest)
};
services.AddSingleton<TokenAuthOptions>(tokenOptions);
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
我们还设置了授权策略,以便在我们希望保护的端点和类上使用[Authorize("Bearer")]
。
Startup.cs - Configure
在这里,我们需要配置JwtBearerAuthentication:
app.UseJwtBearerAuthentication(new JwtBearerOptions {
TokenValidationParameters = new TokenValidationParameters {
IssuerSigningKey = key,
ValidAudience = tokenOptions.Audience,
ValidIssuer = tokenOptions.Issuer,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(0)
}
});
TokenController
在令牌控制器中,您需要拥有一种使用在Startup.cs中加载的密钥生成签名密钥的方法。我们已经在Startup中注册了一个TokenAuthOptions实例,因此我们需要在TokenController的构造函数中注入它:
[Route("api/[controller]")]
public class TokenController : Controller
{
private readonly TokenAuthOptions tokenOptions;
public TokenController(TokenAuthOptions tokenOptions)
{
this.tokenOptions = tokenOptions;
}
...
然后您需要在登录端点的处理程序中生成令牌,在我的示例中,我正在使用 if 语句获取用户名和密码并进行验证,但您需要做的关键是创建或加载基于声明的标识,并为其生成令牌:
public class AuthRequest
{
public string username { get; set; }
public string password { get; set; }
}
[HttpPost]
public dynamic Post([FromBody] AuthRequest req)
{
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();
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);
}
就是这样了。只需将 [Authorize("Bearer")]
添加到您想要保护的任何方法或类中,如果尝试在没有token的情况下访问,则应该会收到错误提示。如果您想返回401而不是500错误,则需要注册自定义异常处理程序 就像我在这里的示例中所做的那样。