使用ASP.Net Core中的Authorize属性返回HTTP 403

Cha*_*had 21 asp.net-core-mvc asp.net-core

使用ASP.Net WebAPI时,我曾经使用过自定义Authorize属性来返回HTTP 403401根据情况.例如,如果用户未经过身份验证,则返回401; 如果用户已通过身份验证但没有相应的权限,请返回a 403.有关详细信息,请参阅此处.

现在看来,在新的ASP.Net Core中,他们不希望你再次覆盖该Authorize属性,而是倾向于采用基于策略的方法.然而,似乎Core MVC遭受了401与其前辈相同的"只返回所有auth错误"的方法.

如何覆盖框架以获得我想要的行为?

Cha*_*had 9

这里打开一个问题之后,看起来这实际上应该有用......有点儿.

在你的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)

AutomaticAuthenticateClaimsPrincipal自动设置,以便您可以User在控制器中访问.AutomaticChallenge允许auth中间件在auth错误发生时修改响应(在这种情况下设置401403适当).

如果您有自己的身份验证方案要实现,那么您将继承AuthenticationMiddlewareAuthenticationHandler类似于JWT实现的工作方式.

  • 我们如何在Identity Core 2中使用它?那里没有这样的选择 (3认同)
  • 我没有使用JwtBearerAuthentication,但是,使用cookie auth.设置AutomaticChallenge = true会导致授权失败时自动重定向.我不想重定向,但是,403.从我在文档中看到的情况来看,这是不可能的. (2认同)

Cha*_*had 8

我最终用中间件做了:

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().

  • 这是危险的,因为在使用 next(context) 调用下一个中间件/委托之后写入 HttpResponse(在本例中通过设置 statuscode)将会抛出异常,以防管道中的其他中间件已经开始写入响应。 (2认同)

Ogg*_*las 7

我遵循了在 ASP.NET Core 中使用 IAuthorizationPolicyProvider 的自定义授权策略提供程序指南,并且还想创建自定义响应。

https://learn.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-5.0

我遵循的指南是自定义 AuthorizationMiddleware 的行为

https://learn.microsoft.com/en-us/aspnet/core/security/authorization/customizingauthorizationmiddlewareresponse?view=aspnetcore-5.0

我的代码最终看起来像这样:

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)

在这里找到了该解决方案:

/sf/answers/4330276891/


归档时间:

查看次数:

14072 次

最近记录:

8 年,2 月 前