Oauth 2.0 IDX10503:签名验证失败

Oauth 2.0 IDX10503:签名验证失败,oauth-2.0,asp.net-core,Oauth 2.0,Asp.net Core,在应用程序重新启动或发布后,我收到了以下带有有效令牌的错误 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"

在应用程序重新启动或发布后,我收到了以下带有有效令牌的错误

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}'
这是生成密钥的函数

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();
    }

}
//POST:/token
[HttpPost()]
公共异步任务令牌([FromBody]登录模型)
{
如果(!ModelState.IsValid)
返回HttpBadRequest();
JwtSecurityTokenHandler=_bearerOptions.SecurityTokenValidators.OfType().First();
尝试
{
var user=wait\u Repo.GetDetailAsync(model.Email);
如果(!model.Password.Equals(user.Password))
返回HttpUnauthorized();
JwtSecurityToken securityToken=handler.CreateToken
(
发卡机构:_bearerOptions.TokenValidationParameters.ValidIssuer,
受众:_bearerOptions.TokenValidationParameters.Validudience,
签名凭证:\ u签名凭证,
主题:新索赔实体(新索赔[]{new索赔(ClaimTypes.Name,user.Email)}),
过期:DateTime.Now.AddMinutes(2)
);
字符串令牌=handler.WriteToken(securityToken);
返回新的ObjectResult(新的TokenModel(){AccessToken=token,TokenType=“bearer”});
}
捕获(例外情况除外)
{
//TODO:在此处添加日志逻辑
返回HttpUnauthorized();
}
}

如果您每次(重新)启动服务器时都要生成一个新的RSA密钥,那么这并不奇怪:使用
密钥a
签名的令牌无法使用
密钥B
进行验证。为了让您的场景正常工作,您需要将RSA密钥存储在某个位置,并在启动时使用相同的密钥

一种方法是调用
rsa.ExportParameters(true)
并将不同的参数存储在某处,这样您就可以使用
rsa.ImportParameters(…)
轻松检索和导入它们


但您最好的选择是使用
AspNet.Security.OpenIdConnect.Server
,它将在最新版本中自动为您生成并存储RSA密钥:

Startup.cs
公共类启动{
public void配置服务(IServiceCollection服务){
services.AddAuthentication();
services.AddCaching();
}
公共void配置(IApplicationBuilder应用程序){
//添加一个新的中间件来验证OIDC服务器颁发的访问令牌。
app.UseJwtBearerAuthentication(选项=>{
options.AutomaticAuthentication=true;
options.Authority=“资源\服务器\ 1”;
options.RequireHttpsMetadata=false;
});
//添加一个新的中间件来发布令牌。
app.UseOpenIdConnectServer(选项=>{
options.AllowInsecureHttp=true;
options.Provider=新的OpenIdConnectServerProvider{
//重写OnValidateClientAuthentication以跳过客户端身份验证。
OnValidateClientAuthentication=上下文=>{
//调用已跳过(),因为JS应用程序无法对其凭据保密。
context.Skipped();
返回Task.FromResult(空);
},
//重写OnGrantResourceOwnerCredentials以支持授予类型=密码。
OnGrantResourceOwnerCredentials=上下文=>{
//在此处执行凭据验证。
//注意:您可以通过消息调用Rejected()
//以指示身份验证失败。
var identity=newclaimsidentity(OpenIdConnectDefaults.AuthenticationScheme);
identity.AddClaim(ClaimTypes.NameIdentifier,“todo”);
//默认情况下,不会在访问和标识令牌中序列化声明。
//使用重载获取“目的地”以确保您的索赔
//正确地插入到相应的令牌中。
identity.AddClaim(“urn:customclaim”、“value”、“token id_token”);
var票证=新的身份验证票证(
新索赔人(身份),
新建AuthenticationProperties(),
context.Options.AuthenticationScheme);
//使用资源服务器列表调用SetResources
//应为颁发访问令牌。
SetResources(新[]{“资源服务器1”});
//使用要授予的作用域列表调用SetScopes
//(指定脱机_访问以发出刷新令牌)。
票证设置范围(新[]{“配置文件”,“脱机访问”});
上下文。已验证(票证);
返回Task.FromResult(空);
}
}
});
app.UseMvc();
}
}
project.json
    {
      "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"
      }
    }