[英]Return HTTP 403 using Authorize attribute in ASP.Net Core
使用 ASP.Net WebAPI 時,我曾經有一個自定義的Authorize
屬性,我會根據情況使用它來返回 HTTP 403
或401
。 例如,如果用戶未通過身份驗證,則返回401
; 如果用戶已通過身份驗證但沒有適當的權限,則返回403
。 有關更多討論, 請參見此處。
現在看來,在新的 ASP.Net Core 中,他們不希望您再覆蓋Authorize
屬性,而是支持基於策略的方法。 但是,Core MVC 似乎遭受與其前輩相同的“所有身份驗證錯誤僅返回401
”方法的困擾。
如何覆蓋框架以獲得我想要的行為?
在此處打開一個問題后,看起來這實際上應該起作用......有點。
在您的Startup.Configure
,如果您只調用app.UseMvc()
並且不注冊任何其他中間件,您將收到401
任何與身份驗證相關的錯誤(未經過身份驗證、經過身份驗證但沒有權限)。
但是,如果您注冊支持它的身份驗證中間件之一,您將正確獲得401
(未經身份驗證)和403
(無權限)。 對我來說,我使用了JwtBearerMiddleware
,它允許通過JSON Web Token進行身份驗證。 關鍵部分是在創建中間件時設置AutomaticChallenge
選項:
在Startup.Configure
:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
app.UseMvc();
AutomaticAuthenticate
將AutomaticAuthenticate
設置ClaimsPrincipal
以便您可以在控制器中訪問User
。 AutomaticChallenge
允許 auth 中間件在發生 auth 錯誤時修改響應(在這種情況下,適當地設置401
或403
)。
如果您有自己的身份驗證方案要實現,您將繼承AuthenticationMiddleware
和AuthenticationHandler
類似於JWT 實現的工作方式。
我最終用中間件來做:
public class AuthorizeCorrectlyMiddleware
{
readonly RequestDelegate next;
public AuthorizeCorrectlyMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
await next(context);
if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
{
if (context.User.Identity.IsAuthenticated)
{
//the user is authenticated, yet we are returning a 401
//let's return a 403 instead
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
}
}
}
}
它應該在調用app.UseMvc()
之前在Startup.Configure
中注冊。
我在 ASP.NET Core 中使用 IAuthorizationPolicyProvider遵循了自定義授權策略提供程序的指南,並且還想創建一個自定義響應。
我遵循的指南是自定義授權中間件的行為
我的代碼最終看起來像這樣:
public class GuidKeyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler
DefaultHandler = new AuthorizationMiddlewareResultHandler();
public async Task HandleAsync(
RequestDelegate requestDelegate,
HttpContext httpContext,
AuthorizationPolicy authorizationPolicy,
PolicyAuthorizationResult policyAuthorizationResult)
{
if (policyAuthorizationResult.Challenged && !policyAuthorizationResult.Succeeded && authorizationPolicy.Requirements.Any(requirement => requirement is GuidKeyRequirement))
{
httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return;
}
// Fallback to the default implementation.
await DefaultHandler.HandleAsync(requestDelegate, httpContext, authorizationPolicy,
policyAuthorizationResult);
}
}
啟動.cs:
services.AddSingleton<IAuthorizationMiddlewareResultHandler,
GuidKeyAuthorizationMiddlewareResultHandler>();
您還可以編輯AuthorizationHandler
並通過IHttpContextAccessor
訪問IHttpContextAccessor
。 然而,這感覺更像是一個黑客。
internal class GuidKeyAuthorizationHandler : AuthorizationHandler<GuidKeyRequirement>
{
private readonly ILogger<GuidKeyAuthorizationHandler> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
public GuidKeyAuthorizationHandler(ILogger<GuidKeyAuthorizationHandler> logger, IHttpContextAccessor httpContextAccessor)
{
_logger = logger;
_httpContextAccessor = httpContextAccessor;
}
// Check whether a given GuidKeyRequirement is satisfied or not for a particular context
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, GuidKeyRequirement requirement)
{
var httpContext = _httpContextAccessor.HttpContext; // Access context here
var key = System.Web.HttpUtility.ParseQueryString(httpContext.Request.QueryString.Value).Get("key");
if (!string.IsNullOrWhiteSpace(key))
{
// If the user guid key matches mark the authorization requirement succeeded
if (Guid.TryParse(key, out var guidKey) && guidKey == requirement.Key)
{
_logger.LogInformation("Guid key is correct");
if (requirement.RequireRefererHeader)
{
_logger.LogInformation("Require correct referer header");
httpContext.Request.Headers.TryGetValue("Referer", out var refererHeader);
if (requirement.RefererHeader == refererHeader)
{
_logger.LogInformation("Referer header is correct");
context.Succeed(requirement);
return Task.CompletedTask;
}
else
{
_logger.LogInformation($"Referer header {refererHeader} is not correct");
}
}
else
{
_logger.LogInformation("Correct referer header is not needed");
context.Succeed(requirement);
return Task.CompletedTask;
}
}
else
{
_logger.LogInformation($"Guid key {guidKey} is not correct");
}
}
else
{
_logger.LogInformation("No guid key present");
}
var msg = "Invalid Guid";
var bytes = Encoding.UTF8.GetBytes(msg);
httpContext.Response.StatusCode = 403;
httpContext.Response.ContentType = "application/json";
httpContext.Response.Body.WriteAsync(bytes, 0, bytes.Length);
return Task.CompletedTask;
}
}
在這里找到了解決方案:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.