ASP.NET JWT:签名验证失败。没有提供安全密钥来验证签名
Posted
技术标签:
【中文标题】ASP.NET JWT:签名验证失败。没有提供安全密钥来验证签名【英文标题】:ASP.NET JWT: Signature validation failed. No security keys were provided to validate the signature 【发布时间】:2018-09-10 15:54:59 【问题描述】:我一直在 F# 中制作一个 web api,主要遵循本指南:https://www.blinkingcaret.com/2017/09/06/secure-web-api-in-asp-net-core/。但是,每当我尝试在我的 aspnet webapi 中访问经过身份验证的端点时,我都会收到此错误:
Failed to validate the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiciIsImV4cCI6IjE1MjI2MzUwNDMiLCJuYmYiOiIxNTIyNTQ4NjQzIn0.VofLygSMitkmEsTBFNG-7-3jMAZYkyvfwc2UIs7AIyw.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__6.MoveNext()
我在这里发现了类似的问题,但没有一个解决方案对我有帮助。我的Startup.fs
看起来像:
type Startup private () =
new (configuration: IConfiguration) as this =
Startup() then
this.Configuration <- configuration
// This method gets called by the runtime. Use this method to add services to the container.
member this.ConfigureServices(services: IServiceCollection) =
// Add framework services
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(fun options ->
options.TokenValidationParameters = TokenValidationParameters (
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
ValidateLifetime = false, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.FromMinutes(5.0) //5 minute tolerance for the expiration date
) |> ignore
) |> ignore
services.AddMvc() |> ignore
services.AddSwaggerGen (fun c -> c.SwaggerDoc("v1", Swagger.Info())) |> ignore
services.AddCors() |> ignore
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
member this.Configure(app: IApplicationBuilder, env: IHostingEnvironment) =
app.UseExceptionHandler(
fun options ->
options.Run(
fun context ->
let ex = context.Features.Get<IExceptionHandlerFeature>()
match ex.Error with
| HttpCodedException (code, message) ->
printfn "code: %i, msg: %s" (int code) message
context.Response.StatusCode <- int code
context.Response.WriteAsync(message)
| exn -> raise (exn)
)
) |> ignore
// let cors = Action<CorsPolicyBuilder> (fun builder -> builder.WithOrigins("http://localhost:3000").AllowAnyHeader().AllowAnyMethod() |> ignore)
app.UseCors(fun policy ->
policy.AllowAnyHeader()
.AllowAnyOrigin()
.AllowCredentials()
.AllowAnyMethod()
.Build() |> ignore
) |> ignore
app.UseAuthentication() |> ignore
app.UseMvc() |> ignore
member val Configuration : IConfiguration = null with get, set
我已经尝试关闭基本上所有的验证,所以我很困惑为什么这仍然失败。如果有帮助,我生成令牌的地方如下所示:
let GenerateToken (username) =
let claims = [|
Claim (ClaimTypes.Name, username)
Claim (JwtRegisteredClaimNames.Exp, DateTimeOffset(DateTime.Now.AddDays(1.0)).ToUnixTimeSeconds().ToString())
Claim (JwtRegisteredClaimNames.Nbf, DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString())
|]
let cred =
new SigningCredentials(
SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
SecurityAlgorithms.HmacSha256
)
let token = JwtSecurityToken(JwtHeader(cred), JwtPayload(claims))
JwtSecurityTokenHandler().WriteToken(token)
希望有人能看到我做错了什么。
【问题讨论】:
【参考方案1】:这对我来说效果很好。
JWT 身份验证设置
services.AddAuthentication(options =>
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(options =>
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("thisKeyIs32CharactersLong1234567"))
ValidateIssuer = true,
ValidIssuer = "MyIssuer",
ValidateAudience = true,
ValidAudience = "MyAudience",
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
;
);
然后创建实际的令牌
var handler = new JwtSecurityTokenHandler();
var securityToken = handler.CreateToken(
new SecurityTokenDescriptor
Issuer = "MyIssuer",
Audience = "MyAudience",
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes("thisKeyIs32CharactersLong1234567")), SecurityAlgorithms.HmacSha512Signature),
Subject = new ClaimsIdentity(
new[]
new Claim(ClaimTypes.Name, "My Name"),
new Claim(ClaimTypes.Sid, "My UID"),
new Claim(ClaimTypes.GroupSid, "My GID")
,
Expires = DateTime.Now + TimeSpan.FromMinutes("30")
);
// Save token
handler.WriteToken(securityToken);
希望对你有帮助。
【讨论】:
很好的答案,但需要注意的是,对于生产环境,RequireHttpsMetadata 应该设置为 true。【参考方案2】:终于想通了。 F# 不使用=
进行赋值,它使用<-
。因此需要将我的服务 AddAuthenticaton 调用更改为:
services.AddAuthentication(fun options ->
options.DefaultScheme <- JwtBearerDefaults.AuthenticationScheme
options.DefaultAuthenticateScheme <- JwtBearerDefaults.AuthenticationScheme
options.DefaultChallengeScheme <- JwtBearerDefaults.AuthenticationScheme
).AddJwtBearer(fun options ->
options.TokenValidationParameters <- TokenValidationParameters (
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = false,
IssuerSigningKey = SymmetricSecurityKey(Encoding.UTF8.GetBytes("the secret that needs to be at least 16 characeters long for HmacSha256")),
ValidateLifetime = false, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.FromMinutes(5.0), //5 minute tolerance for the expiration date
ValidateActor = false,
ValidateTokenReplay = false
)
) |> ignore
现在一切正常。
【讨论】:
刚刚做了同样的事情。疯狂的是我花了多长时间才意识到。感谢您的帮助!以上是关于ASP.NET JWT:签名验证失败。没有提供安全密钥来验证签名的主要内容,如果未能解决你的问题,请参考以下文章
ASP.net Core 2.0 AzureAd Bearer JWT-Token Auth 在验证签名时不会失败
ASP.NET Core 5 JWT 身份验证失败,响应代码为 401
JwtSecurityTokenHandler ValidateToken:“签名验证失败。没有提供安全密钥来验证签名”