Cha*_*had 21 asp.net-core-mvc asp.net-core
使用ASP.Net WebAPI时,我曾经使用过自定义Authorize属性来返回HTTP 403或401根据情况.例如,如果用户未经过身份验证,则返回401; 如果用户已通过身份验证但没有相应的权限,请返回a 403.有关详细信息,请参阅此处.
现在看来,在新的ASP.Net Core中,他们不希望你再次覆盖该Authorize属性,而是倾向于采用基于策略的方法.然而,似乎Core MVC遭受了401与其前辈相同的"只返回所有auth错误"的方法.
如何覆盖框架以获得我想要的行为?
在这里打开一个问题之后,看起来这实际上应该有用......有点儿.
在你的Startup.Configure,如果你只是打电话app.UseMvc()而不注册任何其他中间件,你将获得401任何与auth相关的错误(未经过身份验证,经过身份验证但没有权限).
但是,如果您注册了一个支持它的身份验证中间件,那么您将获得401未经身份验证且403无权限的正确访问.对我来说,我使用了JwtBearerMiddleware允许通过JSON Web令牌进行身份验证的方法.关键部分是AutomaticChallenge在创建中间件时设置选项:
在Startup.Configure:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
app.UseMvc();
Run Code Online (Sandbox Code Playgroud)
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
应该Startup.Configure在打电话之前注册app.UseMvc().
我遵循了在 ASP.NET Core 中使用 IAuthorizationPolicyProvider 的自定义授权策略提供程序指南,并且还想创建自定义响应。
我遵循的指南是自定义 AuthorizationMiddleware 的行为
我的代码最终看起来像这样:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
启动.cs:
services.AddSingleton<IAuthorizationMiddlewareResultHandler,
GuidKeyAuthorizationMiddlewareResultHandler>();
Run Code Online (Sandbox Code Playgroud)
您还可以通过 编辑AuthorizationHandler并访问 httpContext 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;
}
}
Run Code Online (Sandbox Code Playgroud)
在这里找到了该解决方案:
| 归档时间: |
|
| 查看次数: |
14072 次 |
| 最近记录: |