ASP.net Core 2.0身份验证:ValidateSignature异常(IDX10503)

时间:2018-05-15 14:20:41

标签: c# authentication asp.net-core-2.0

我试图验证使用带有Bearer JWT-Token的.Net Core 2.0开发的API。但身份验证无效。为了更好地理解,我通过实现ISecurityTokenValidator创建了自己的Validator。例外情况如下 -

{
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: 
    IDX10503: Signaturevalidationfailed.Keystried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey,
    KeyId: Microsoft.IdentityModel.Tokens.SymmetricSecurityKey,
    KeyId: '.Exceptionscaught: ''.token: '{
        "alg": "HS256",
        "typ": "JWT"
        }.{
        "iss": "TH_STS",
        "aud": "http://sts-url.com/",
        "nbf": 1111111111,
        "exp": 2222222222,
        "unique_name": "username",
        "authmethod": "http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/password",
        "auth_time": "2018-05-14T15:31:19.64Z",
        "user": "{
            UserInfo: {
                AccountId:1,
                UserId:2
            }
        }",
        "email": "username@email.com"
    }'.
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Stringtoken, TokenValidationParametersvalidationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(Stringtoken, TokenValidationParametersvalidationParameters, SecurityToken&validatedToken)
at Api.Security.CustomTokenValidator.ValidateToken(StringsecurityToken, TokenValidationParametersvalidationParameters, SecurityToken&validatedToken)inD: \Api\Security\CustomTokenValidator.cs: line 33

}

以下是我的验证员

 public class CustomTokenValidator : ISecurityTokenValidator
{
    public bool CanReadToken(string securityToken)
    {
        try
        {
            var jwtToken = new JwtSecurityTokenHandler().ReadToken(securityToken);
            return jwtToken != null && jwtToken.ValidTo >= DateTime.UtcNow;
        }
        catch (SecurityTokenValidationException ex)
        {
            return false;
        }
        catch (Exception ex)
        {
            return false;
        }
    }

    public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters,
        out SecurityToken validatedToken)
    {
        var handler = new JwtSecurityTokenHandler();
        try
        {
            return handler.ValidateToken(securityToken, validationParameters, out validatedToken);
        }
        catch (Exception ex)
        {

        }

        validatedToken = null;
        return null;
    }

    public bool CanValidateToken { get; }
    public int MaximumTokenSizeInBytes { get; set; }
}

以下是Startup

的代码
 public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        SetupAuthentication(services);

        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials()
                    .Build());
        });

        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAuthentication();
        app.UseMvc();

        app.UseCors("CorsPolicy");
    }

    private void SetupAuthentication(IServiceCollection services)
    {
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(UpdateJwtBearerOptions);
    }

    private void UpdateJwtBearerOptions(JwtBearerOptions options)
    {
        options.RequireHttpsMetadata = false;
        options.SecurityTokenValidators.Add(new CustomTokenValidator());
        options.TokenValidationParameters = GetTokenValidationParameters();
    }
    private TokenValidationParameters GetTokenValidationParameters()
    {
        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateIssuerSigningKey = true,
            ValidateLifetime = true,
        };

        var token1 = ReadToken1();
        var token2 = ReadToken2();
        tokenValidationParameters.ValidIssuers = new List<string> { token1.Issuer, token2.Issuer };
        tokenValidationParameters.ValidAudiences = new List<string> { token1.Audience, token2.Audience };
        tokenValidationParameters.IssuerSigningKeys = new List<SecurityKey> { GetIssuerSigningKey(token1), GetIssuerSigningKey(token2) };

        return tokenValidationParameters;
    }

    private static SymmetricSecurityKey GetIssuerSigningKey(IdentityToken token)
    {
        return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.Key));
    }

    private IdentityToken ReadToken1()
    {
        return new IdentityToken
        {
            Audience = Configuration["IdentityToken:AudienceUris:0"],
            Issuer = Configuration["IdentityToken:Issuers:0:Issuer"],
            Key = Configuration["IdentityToken:Issuers:0:SymmetricKey"]
        };
    }
    private IdentityToken ReadToken2()
    {
        return new IdentityToken
        {
            Audience = Configuration["IdentityToken:AudienceUris:1"],
            Issuer = Configuration["IdentityToken:Issuers:1:Issuer"],
            Key = Configuration["IdentityToken:Issuers:1:SymmetricKey"]
        };
    }

}

public class IdentityToken
{
    public string Issuer { get; set; }
    public string Audience { get; set; }
    public string Key { get; set; }
}

当前MVC应用程序的配置如下

<system.identityModel>
    <identityConfiguration saveBootstrapContext="true">
        <audienceUris>
            <add value="http://url1.com/" />
            <add value="http://url2.com/" />
        </audienceUris>
        <securityTokenHandlers>
            <add type="System.IdentityModel.Tokens.JwtSecurityTokenHandler, System.IdentityModel.Tokens.Jwt, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
            <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089">
                <sessionTokenRequirement lifetime="00:30:00"></sessionTokenRequirement>
            </add>
            <securityTokenHandlerConfiguration>
                <issuerTokenResolver type="System.IdentityModel.Tokens.NamedKeyIssuerTokenResolver, System.IdentityModel.Tokens.JWT">
                    <securityKey symmetricKey="key0" name="TH_STS" />
                    <securityKey symmetricKey="key1" name="http://sts-url.com" />
                </issuerTokenResolver>
                <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
                    <authority name="TH_STS">
                        <keys>
                            <add symmetricKey="key0" />
                        </keys>
                        <validIssuers>
                            <add name="TH_STS" />
                        </validIssuers>
                    </authority>
                    <authority name="http://sts-url.com">
                        <keys>
                            <add symmetricKey="key1" />
                        </keys>
                        <validIssuers>
                            <add name="http://sts-url.com" />
                        </validIssuers>
                    </authority>
                </issuerNameRegistry>
            </securityTokenHandlerConfiguration>
        </securityTokenHandlers>
    </identityConfiguration>
</system.identityModel>

代码如下

 bool Validate(string token, out IList<ClaimsIdentity> validatedIdentity)
    {
        try
        {
            var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
            var jwtToken = handlers.ReadToken(token) as JwtSecurityToken;

            if (jwtToken == null || jwtToken.ValidTo < DateTime.UtcNow)
            {
                validatedIdentity = null;
                return false;
            }

            validatedIdentity = handlers.ValidateToken(jwtToken);
            return true;
        }
        catch (SecurityTokenValidationException ex)
        {
            validatedIdentity = null;
            return false;
        }
        catch (Exception ex)
        {
            validatedIdentity = null;
            return false;
        }
    }

我不知道我在这里缺少什么。我的代码中是否有任何配置问题?

1 个答案:

答案 0 :(得分:0)

例外情况表明它无法验证JWT令牌的Signature,但它可以读取HeaderPayload。代码使用config提供的对称密钥验证签名。

在旧配置中,issuerTokenResolverSystem.IdentityModel.Tokens.NamedKeyIssuerTokenResolver。从documentation of it,可以发现它正在使用Convert.FromBase64String( value )读取对称密钥。

在dot.Net Core 2.0中,我使用new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.Key));来读取密钥。

将其更改为new SymmetricSecurityKey(Convert.FromBase64String(key));可解决问题。