在应用程序重新启动或发布后,我收到有效令牌的以下错误
IDX10503: Signature validation failed. Keys tried: 'System.IdentityModel.Tokens.RsaSecurityKey
Exceptions caught:
token: '{"typ":"JWT","alg":"RS256","kid":null}.{"unique_name":"test@test.com","iss":"XXXXXX","aud":"XXXXX","exp":1444876186}'
这是生成KEY的函数
private void generateRsaKeys()
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048))
{
key = new RsaSecurityKey(rsa.ExportParameters(true));
credentials = new SigningCredentials (key,SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest);
rsa.PersistKeyInCsp = true;
}
}
这是配置的完成方式
services.ConfigureOAuthBearerAuthentication(options =>
{
options.AutomaticAuthentication = true;
options.TokenValidationParameters.IssuerSigningKey = generateRsaKeys();
options.TokenValidationParameters.ValidAudience = audience;
options.TokenValidationParameters.ValidIssuer = issuer;
});
app.UseStaticFiles();
app.UseOAuthBearerAuthentication();
// Add MVC to the request pipeline.
app.UseMvc();
这是我控制器上的操作
// POST: /token
[HttpPost()]
public async Task<IActionResult> Token([FromBody] LoginModel model)
{
if (!ModelState.IsValid)
return HttpBadRequest();
JwtSecurityTokenHandler handler = _bearerOptions.SecurityTokenValidators.OfType<JwtSecurityTokenHandler>().First();
try
{
var user = await _Repo.GetDetailAsync(model.Email);
if (!model.Password.Equals(user.Password))
return HttpUnauthorized();
JwtSecurityToken securityToken = handler.CreateToken
(
issuer: _bearerOptions.TokenValidationParameters.ValidIssuer,
audience: _bearerOptions.TokenValidationParameters.ValidAudience,
signingCredentials: _signingCredentials,
subject: new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, user.Email) }),
expires: DateTime.Now.AddMinutes(2)
);
string token = handler.WriteToken(securityToken);
return new ObjectResult(new TokenModel() { AccessToken = token, TokenType = "bearer" });
}
catch (Exception ex)
{
// TODO: add loggin logic here
return HttpUnauthorized();
}
}
答案 0 :(得分:3)
如果您每次(重新)启动服务器时都生成新的RSA密钥,那就不足为奇了:使用KEY A
无法验证使用KEY B
签名的令牌。为了使您的方案正常工作,您需要将RSA密钥存储在某处并在启动期间使用相同的密钥。
一种方法是调用rsa.ExportParameters(true)
并在某处存储不同的参数,以便您可以使用rsa.ImportParameters(...)
轻松检索和导入它们。
但您最好的选择是使用AspNet.Security.OpenIdConnect.Server
,它将在上一版本中为您自动生成并存储RSA密钥:
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddAuthentication();
services.AddCaching();
}
public void Configure(IApplicationBuilder app) {
// Add a new middleware validating access tokens issued by the OIDC server.
app.UseJwtBearerAuthentication(options => {
options.AutomaticAuthentication = true;
options.Authority = "resource_server_1";
options.RequireHttpsMetadata = false;
});
// Add a new middleware issuing tokens.
app.UseOpenIdConnectServer(options => {
options.AllowInsecureHttp = true;
options.Provider = new OpenIdConnectServerProvider {
// Override OnValidateClientAuthentication to skip client authentication.
OnValidateClientAuthentication = context => {
// Call Skipped() since JS applications cannot keep their credentials secret.
context.Skipped();
return Task.FromResult<object>(null);
},
// Override OnGrantResourceOwnerCredentials to support grant_type=password.
OnGrantResourceOwnerCredentials = context => {
// Do your credentials validation here.
// Note: you can call Rejected() with a message
// to indicate that authentication failed.
var identity = new ClaimsIdentity(OpenIdConnectDefaults.AuthenticationScheme);
identity.AddClaim(ClaimTypes.NameIdentifier, "todo");
// By default, claims are not serialized in the access and identity tokens.
// Use the overload taking a "destination" to make sure your claims
// are correctly inserted in the appropriate tokens.
identity.AddClaim("urn:customclaim", "value", "token id_token");
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
context.Options.AuthenticationScheme);
// Call SetResources with the list of resource servers
// the access token should be issued for.
ticket.SetResources(new[] { "resource_server_1" });
// Call SetScopes with the list of scopes you want to grant
// (specify offline_access to issue a refresh token).
ticket.SetScopes(new[] { "profile", "offline_access" });
context.Validated(ticket);
return Task.FromResult<object>(null);
}
}
});
app.UseMvc();
}
}
{
"dependencies": {
"Microsoft.AspNet.Server.WebListener": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-rc1-final",
"AspNet.Security.OpenIdConnect.Server": "1.0.0-beta4"
}
}