繁体   English   中英

Asp.Net Boilerplate .Net Core 2.0 AbpAuthorizationFilter - ChallengeResult / 未授权

[英]Asp.Net Boilerplate .Net Core 2.0 AbpAuthorizationFilter - ChallengeResult / Unauthorized

我正在运行带有Asp.Net Boilerplate 3.4.0 版Web 应用程序的Asp.Net Core 2.0

当我有一个经过身份验证的用户没有访问资源所需的权限时, AbpAuthorizationFilter通过Abp框架设置ChallengeResult 此行为会导致用户返回到默认登录页面。 如果用户通过身份验证,我想设置一个ForbidResult并将它们重定向到默认的 AccessDenied 页面。

查看我的选项后,我发现我有以下选项:

  1. 添加我自己的授权过滤器并在AddAbp()服务配置之前注册MvcOptions 过滤器将有条件地将结果设置为“挑战”或“禁止”
  2. 覆盖OnRedirectToLogin事件(即为经过身份验证的用户自定义)
  3. 覆盖HandleChallengeAsync处理程序(即,检查请求是否经过身份验证,并为未经身份验证的请求发出 ForbidResult 或 ChallengeResult)

我注意到在 ABP 的 .Net 框架版本中,在AbpMvcAuthorizeFilter (即HandleUnauthorizedRequest )中有可AbpMvcAuthorizeFilter方法; 但是,这不适用于 .Net Core 版本。 请参阅 GitHub 问题 1256 -> 使 AbpMvcAuthorizeFilter 和 AbpApiAuthorizeFilter 可覆盖

题:

是否还有其他人需要更改为未经授权的请求返回ChallengeResult的默认Abp行为? 如果是,您使用了什么解决方案? 我是否在Abp配置或 Asp.Net Core(除了上面列出的三个选项之外)中遗漏了一些可以让我更好地控制这种行为的东西?

如果我采用了一种解决方法,感觉就像控制这种行为的黑客一样。

选项1:

在我列出的三个选项中,选项似乎是处理此逻辑的最干净、最合适的地方。 它也不漂亮,因为我将复制整个AbpAuthorizationFilter以仅更改几行代码。

当前代码:

context.Result = new ChallengeResult();

提议的改变:

if (context.HttpContext.User.Identity.IsAuthenticated)
{
    //User is already logged in.. No need to redirect to the 
    //login page
    context.Result = new ForbidResult();
}
else
{
    context.Result = new ChallengeResult();
}

完整代码如下:

AbpAuthorizationFilter.cs请参阅 Catch 块行 - 58 - 77

选项 2:

选项二感觉很笨拙,因为我将引入OnRedirectToLogin事件的逻辑必须假设经过身份验证的用户已尝试访问未经授权的资源。 目前,我只看到CookieAuthenticationHandler通过HandleChallengeAsync方法在Events.RedirectToLogin中引发。 话虽如此,可以安全地假设此事件只会由ChallengeResult结果引发。 CookieAuthenticationHandler.cs

选项 3:

选项三将是最后一个选项(即不惜一切代价避免)

主要目标

主要目标是为尝试访问未授权资源的经过身份验证的用户提供更好的体验。 与其将用户重定向到登录页面,不如将用户重定向到未授权/禁止的页面,该页面清楚地表明他们未经授权。 这可能包括提示用户提供更高特权凭据的选项。 通过提示用户,它闻起来像一个ChallengeResult结果流,所以也许我只是回答了我自己的问题。 对于当前的行为,我没有太多关于“为什么”发布ChallengeResult上下文信息。 我会知道用户已登录并且引发了OnRedirectToLogin事件。 这可能足以为经过身份验证的用户自定义ChallengeResult的行为。 这开始感觉这是正确的解决方案。 关于使用这种方法的任何建议或反馈?

在这三个选项中,我选择了第二个选项(覆盖OnRedirectToLogin事件),原因如下:

  1. 引入最少的代码,无需复制整个授权过滤器,只需更改两行代码。
  2. 对挑战体验的更多控制(MVC 应用程序也是 OIDC 客户端),具有自己的一组角色和权限(请参阅下面的代码解决方案)
  3. 在此响应时, OnRedirectToLogin事件仅由HandleChallengeAsync中的HandleChallengeAsync 引发,因此感觉这是覆盖ChallengeResult行为的正确位置。

解决方案:

options.Events.OnRedirectToLogin = context =>
{
    if (context.HttpContext?.User?.Identity?.IsAuthenticated == false)
    {
        //The user is not authenticated... Use the "oidc" challenge scheme 
        //and send them to identity server.
        var task = context.HttpContext.ChallengeAsync("oidc");
        task.WaitAndUnwrapException();

        return Task.CompletedTask;
    }

    var accessDeniedPath = BuildRedirectUri(context.HttpContext, options.AccessDeniedPath);

    context.Response.Redirect(accessDeniedPath);
    context.Response.StatusCode = 302;

    return Task.CompletedTask;
};

边注:

应该注意的是, AbpAuthorizationFilter的默认行为并不反映 Asp.Net Core MVC 2.0 AuthorizeFilter的股票行为。 当经过身份验证的用户授权失败时,Asp.Net Core MVC 2.0 AuthorizeFilter返回 Forbid 结果。

Asp.Net Core MVC 的默认AuthorizeFilterAuthorizeFilter委托给IPolicyEvaluator 如果授权失败且用户通过认证,则设置 Forbid 结果;如果授权失败且用户未通过身份验证,则设置 Challenge 结果。

PolicyEvaluator.cs

var result = await _authorization.AuthorizeAsync(context.User, resource, policy);
if (result.Succeeded) 
{ 
    return PolicyAuthorizationResult.Success(); 
} 

// If authentication was successful, return forbidden, otherwise challenge 
return (authenticationResult.Succeeded)  
    ? PolicyAuthorizationResult.Forbid()  
    : PolicyAuthorizationResult.Challenge(); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM