我试图验证使用带有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;
}
}
我不知道我在这里缺少什么。我的代码中是否有任何配置问题?
答案 0 :(得分:0)
例外情况表明它无法验证JWT令牌的Signature
,但它可以读取Header
和Payload
。代码使用config提供的对称密钥验证签名。
在旧配置中,issuerTokenResolver
为System.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));
可解决问题。