在身份验证失败时返回自定义状态码 .Net Core
Posted
技术标签:
【中文标题】在身份验证失败时返回自定义状态码 .Net Core【英文标题】:Return custom status code on authentication failure .Net Core 【发布时间】:2021-09-27 08:19:47 【问题描述】:我在 .Net 核心中有一个自定义身份验证方案,我想针对某些特定类型的身份验证失败返回特定响应(而不是仅返回 401)。我目前的做法是这样的:
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
var token = GetToken();
if (string.IsNullOrWhiteSpace(token))
return AuthenticateResult.NoResult();
var validationResult = _tokenContextProvider.Validate(); // validate
if (validationResult != TokenValidationResult.Ok)
await updateResponseCode(Context, validationResult);
return AuthenticateResult.Fail("Token invalid");
//success
var userContext = tokenContextProvider.GetUserContext();
var ticket = GetAuthenticationTicket(userContext);
return AuthenticateResult.Success(ticket);
private static async Task updateResponseCode(HttpContext context, TokenValidationResult validationResult)
if (!context.Response.HasStarted)
if (validationResult == TokenValidationResult.SpecialError)
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
var errorMessage = JsonConvert.SerializeObject(new
error = new
message = validationResult.Message
);
context.Response.Headers["Content-Type"] = "application/json";
await context.Response.WriteAsync(errorMessage, Encoding.UTF8);
这很好,并返回我想要的响应代码。但是,另一位中间件(我假设)随后尝试设置 StatusCode
并导致记录一些异常。
Microsoft.AspNetCore.Server.IIS.Core.IISHttpContext in ThrowResponseAlreadyStartedException
System.InvalidOperationException:无法设置 StatusCode,因为响应已经开始。
我可以“忽略”异常,但我宁愿找到一些更清晰支持的方法来执行此操作,这样我就不会因为这些异常而使日志混乱。
是否有其他方法可以更改身份验证失败后返回的响应?
【问题讨论】:
这不是身份验证方案的责任。通常的方法是提供可以在身份验证配置期间挂钩的事件。见CookieAuthenticationHandler
:source.dot.net/#Microsoft.AspNetCore.Authentication.Cookies/…
您找到解决方案了吗?
@MightyAtom 我确实找到了解决方案。我会发布我最终做了什么
【参考方案1】:
如果有人遇到类似的问题,我基本上采取了不同的方法。我没有试图强制身份验证处理程序做一些它不适合做的事情,而是将StatusCode
设置逻辑拉到它自己的中间件中。
在认证过程中,当我关心的事件发生时,我像这样向HttpContext
添加一个项目
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
var token = GetToken();
...
if (validationResult != TokenValidationResult.Ok)
Context.Items.Add("TokenValidationResult", validationResult);
return Task.FromResult(AuthenticateResult.Fail("Token invalid"));
然后中间件有机会在其他处理程序运行后运行
public async Task Invoke(HttpContext httpContext)
await _next(httpContext);
// context Item ready here
var tokenValidationResult = getTokenValidationResult(httpContext);
if (tokenValidationResult != null && tokenValidationResult != TokenValidationResult.Ok)
await updateResponseCode(httpContext, tokenValidationResult);
private static async Task updateResponseCode(HttpContext context, TokenValidationResult validationResult)
if (!context.Response.HasStarted)
if (validationResult == TokenValidationResult.SpecialError)
await setErrorMessageAndCode(context, HttpStatusCode.Gone, validationResult);
else
await setErrorMessageAndCode(context, HttpStatusCode.Forbidden, validationResult);
!context.Response.HasStarted
的检查仍然是必需的,但现在我可以动态更新状态代码而不会影响下游。我注册了中间件在身份验证之前运行(所以它在退出的路上运行)
app.UseCustomJwtStatusCodes();
app.UseAuthentication();
app.UseAuthorization();
这对我有用,允许我设置错误代码而不会干扰任何其他中间件。
【讨论】:
以上是关于在身份验证失败时返回自定义状态码 .Net Core的主要内容,如果未能解决你的问题,请参考以下文章
使用 Laravel 和 Passport 在身份验证失败时响应状态码 401?
Firebase 电话身份验证在已投入生产的应用程序上失败,状态码为 17028
用户未经授权时的 Laravel 护照自定义错误消息和状态码