AuthorizeFilter 失败时如何返回 403 而不是重定向访问被拒绝

Posted

技术标签:

【中文标题】AuthorizeFilter 失败时如何返回 403 而不是重定向访问被拒绝【英文标题】:How to return 403 instead of redirect to access denied when AuthorizeFilter fails 【发布时间】:2019-06-24 22:42:36 【问题描述】:

在 Startup.ConfigureServices() 我这样配置授权过滤器:

services.AddMvc(options =>

    options.Filters.Add(new AuthorizeFilter(myAuthorizationPolicy));
)

我使用 cookie 身份验证或基于配置的 AAD 身份验证:

if (useCookieAuth)

    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie();

else

    services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
       .AddAzureAD(options => Configuration.Bind("Authentication:AzureAd", options));

现在,当我访问一个页面并且 myAuthorizationPolicy 失败时,我被重定向到“Account/AccessDenied?ReturnUrl=%2F”,但我想返回 403。

【问题讨论】:

【参考方案1】:
public class AuthorizeOrForbidAttribute : AuthorizeAttribute

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        
            filterContext.Result = new HttpStatusCodeResult(403);
        

    

试试上面的过滤器。

【讨论】:

我应该在哪里使用这个? options.Filters.Add(new AuthorizeFilter(myAuthorizationPolicy));你可以发送 myAuthorizationPolicy 方法吗?我得先看看这个方法。 如果 myAuthorizationPolicy 方法中没有任何代码,请创建一个类似上述代码的类。并删除您的代码 options.Filters.Add(new AuthorizeFilter(myAuthorizationPolicy)); .然后添加这一行 options.Filters.Add(new AuthorizeOrForbidAttribute());【参考方案2】:

看来你必须重写 OnRedirectToAccessDenied

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options => 
        options.Events.OnRedirectToAccessDenied = context => 
             context.Response.StatusCode = 403;
             return Task.CompletedTask;
        ;
    );

【讨论】:

是的,但是 AAD 身份验证呢? 更有可能您必须创建自己的 AddAzureAD(),因为它似乎还无法配置...... 类似于 public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action configureOptions) builder.Services.Configure(configureOptions); builder.Services.AddSingleton, ConfigureAzureOptions>(); builder.AddOpenIdConnect(options => options.Events = new OpenIdConnectEvents OnRedirectToIdentityProvider = RedirectToIdentityProvider ; );返回建设者; 效果不错!!它缺少返回 Task.CompletedTask @BorisSokolov:当然可以。我做到了:***.com/questions/63191785/…【参考方案3】:

您可以结合您的策略创建自定义 Authorization Filter

public class MyAuthorizeFilter: IAsyncAuthorizationFilter

    public MyAuthorizeFilter(string policy)
    
        Policy = policy;
    

    public string Policy  get; set; 
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    
        var user = context.HttpContext.User;

        var authZService = context.HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
        var accessable = await authZService.AuthorizeAsync(user, null, this.Policy);
        if (!accessable.Succeeded)
        
            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
        

    

现在你可以使用授权过滤器来拦截请求了:

[MyAuthorizeFilter("MyPolicy")]
public IActionResult Index()

或全局:

services.AddMvc(options =>
        
            options.Filters.Add(new MyAuthorizeFilter("MyPolicy"));              
        );

当然,我们需要先注册策略。

services.AddAuthorization(o => 
            o.AddPolicy("MyPolicy", pb => 
                pb.RequireAuthenticatedUser();
                //...
            );
        );

【讨论】:

【参考方案4】:

我最近遇到了这个问题,并且能够在以下位置找到有关如何覆盖 AzureADB2C 中默认 cookie 行为的说明:

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/azure-ad-b2c?view=aspnetcore-3.1#configure-the-underlying-openidconnectoptionsjwtbearercookie-options

这是一个实现该覆盖以返回简单 403 而不是重定向的示例:

services
    .AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
    .AddAzureADB2C();

services.Configure<CookieAuthenticationOptions> (AzureADB2CDefaults.CookieScheme, options =>

    // Stop AzureADB2C from redirecting 403's, which it does by default.  We just want to return the 403.
    options.Events.OnRedirectToAccessDenied = new Func<RedirectContext<CookieAuthenticationOptions>, Task>(context =>
    
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        return context.Response.CompleteAsync();
    );
);

希望这对某人有所帮助。

【讨论】:

【参考方案5】:

对于那些使用 Azure AD 并在他们的ConfigureServices 中使用的人(咳嗽我):

services.AddMicrosoftIdentityWebAppAuthentication(Configuration);

解决方法如下:

        services.Configure<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme, options =>
        
            options.Events.OnRedirectToAccessDenied = new Func<RedirectContext<CookieAuthenticationOptions>, Task>(context =>
            
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                return context.Response.CompleteAsync();
            );
        );

这样,ASP.NET 将不再重定向到AccessDenied,而是返回403

更多细节可以在这里找到:https://blog.johnnyreilly.com/2020/12/21/how-to-make-azure-ad-403/(但我希望你真正需要的只是这个答案)

【讨论】:

我试过这个,但由于某种原因它不起作用(函数中的断点没有被触发)。我仍然被重定向到 ADB2C 登录页面。关于它可能是什么的任何线索?

以上是关于AuthorizeFilter 失败时如何返回 403 而不是重定向访问被拒绝的主要内容,如果未能解决你的问题,请参考以下文章

请求正常时如何返回json对象,SpringBoot失败时如何返回json错误对象

如何设置 SBT 构建以在 Jenkins 测试失败时返回零退出代码?

在clickhouse中,投射失败时如何返回null而不是抛出异常?

当我的 linting 脚本返回错误时,如何让我的 Azure DevOps Pipeline 构建失败?

如何在打字稿中声明成功/失败返回类型

当 mkdir 从 PHP 失败时如何找到原因?