.NET Core在生产环境中如何处理JSON Web令牌(JWT)身份验证时遇到问题。我正在使用邮递员进行测试。如果我使用有效令牌调用我的API,它将正常工作并返回API端点的预期响应。但是,如果令牌已过期,那么我将无法获得预期的HTTP401。实际上,我没有任何响应,它只是悄无声息地失败了。我的生产配置似乎无法正常工作。如果我在本地开发环境中对此进行测试,则不会有任何问题,并且过期的令牌会收到401未经授权的HTTP响应,如预期的那样。
我的Web应用程序对通过网站登录的用户使用cookie身份验证,对于连接到API的用户使用JWT身份验证。这是JWT身份验证的配置。这在Startup.cs中。这是services.Authentication的JWT配置部分。首先设置cookie身份验证,它是默认的身份验证方案。
.AddJwtBearer(options =>{
options.RequireHttpsMetadata = !_hostingEnvironment.IsDevelopment();
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Settings.Api.JwtBearer.TokenValidation.ValidIssuer,
ValidAudience = Settings.Api.JwtBearer.TokenValidation.ValidAudience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Settings.Api.JwtBearer.TokenValidation.IssuerSigningKey))
};
options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
context.Response.ContentType = "application/json; charset=utf-8";
var message = _hostingEnvironment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
var result = JsonConvert.SerializeObject(new { message });
return context.Response.WriteAsync(result);
}
};});
这是Startup.cs中的其他相关配置:
public void Configure(IApplicationBuilder app, IHostingEnvironment env){
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error/Exception");
app.UseStatusCodePagesWithReExecute("/Error/{0}");
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseCors(Constants.Security.Cors.PolicyName);
app.UseAuthentication();
app.UseMvc(ConfigureRoutes);}
` 我花了很多时间进行“配置”设置并在生产中进行了测试,但是当令牌认证失败时,我总是最终无响应。由于它在我的本地开发环境中可以正常工作,因此它必须表示我的生产配置有问题,但是我很困惑,没有想法。有关更多信息,下面是错误日志中的错误示例:
信息: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [1] 验证令牌失败。 Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223:生命周期验证失败。令牌已过期。有效: '[[PII隐藏]]',当前时间:'[[PII隐藏]]'。在 Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable
1 notBefore, Nullable
1已过期,SecurityToken securityToken, TokenValidationParametersvalidationParameters) System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable1 notBefore, Nullable
1到期,JwtSecurityToken jwtToken, TokenValidationParametersvalidationParameters) System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken,TokenValidationParametersvalidationParameters) System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(字符串 令牌,TokenValidationParametersvalidationParameters,SecurityToken& validatedToken) Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__6.MoveNext() 信息: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [7] 承载未认证。失败消息:IDX10223:生命周期验证失败。令牌已过期。 ValidTo:'[PII是 隐藏]],目前时间:[[PII隐藏]。信息: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService [2] 授权失败。信息:Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker [3] 筛选器“ Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter”上的请求授权失败。信息: Microsoft.AspNetCore.Mvc.ChallengeResult [1] 使用身份验证方案(Bearer)执行ChallengeResult。信息:Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker [2] 在109.4625毫秒内执行了操作Web.Controllers.ApiController.Users(Web)信息:Microsoft.AspNetCore.Routing.EndpointMiddleware [1] 执行的端点'Web.Controllers.ApiController.Users(Web)'失败:Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware [1] 执行请求时发生未处理的异常。 System.InvalidOperationException:无法设置StatusCode,因为 响应已经开始。在 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 价值) Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 价值) Microsoft.AspNetCore.Http.Internal.DefaultHttpResponse.set_StatusCode(Int32 价值) Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__7.MoveNext()
预先感谢您提供有关解决此问题的任何想法。
答案 0 :(得分:1)
因此,我找到了一个局部解决方案,至少可以使我不受阻碍,因此我可以继续进行API开发。尝试更改上下文。JwtBearerEvents OnAuthenticationFailed中的响应在我的生产环境中不起作用(尽管在我的本地计算机上可以正常工作)。我尝试了很多变体,但最后唯一可行的方法是从Startup.cs中删除整个代码块:
options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
context.Response.ContentType = "application/json; charset=utf-8";
var message = _hostingEnvironment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
var result = JsonConvert.SerializeObject(new { message });
return context.Response.WriteAsync(result);
}
};
一旦这样做,在Postman中进行测试时,我便开始获得401代码以进行失败的令牌验证,这是一件好事,而且是预期的行为。但是,在响应的正文中,默认错误页面HTML也会被返回。
要解决这个问题,我必须修改Startup.cs中的Configure方法,以便UseStatusCodePagesWithReExecute忽略API:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error/Exception");
app.UseWhen(context => !context.Request.Path.Value.StartsWith("/api"), builder =>
{
builder.UseStatusCodePagesWithReExecute("/Error/{0}");
});
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseCors(Constants.Security.Cors.PolicyName);
app.UseAuthentication();
app.UseMvc(ConfigureRoutes);
}
这有效,但我不喜欢它。感觉像一个黑客。现在,我得到了401,用于令牌身份验证失败,体内没有任何东西。就像我之前提到的那样,这使我不受阻碍,但是我仍然想在响应中返回自定义错误消息。
所以,我的下一个问题是,如果我不能使用JwtBearerEvents OnAuthenticationFailed添加消息,那么添加错误消息的正确位置在哪里?