IDX10503:签名验证失败

时间:2015-10-15 02:53:40

标签: 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","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();
    }

}

1 个答案:

答案 0 :(得分:3)

如果您每次(重新)启动服务器时都生成新的RSA密钥,那就不足为奇了:使用KEY A无法验证使用KEY B签名的令牌。为了使您的方案正常工作,您需要将RSA密钥存储在某处并在启动期间使用相同的密钥。

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

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

Startup.cs

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

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"
  }
}