c# - Asp.Net Boilerplate .Net Core 2.0 AbpAuthorizationFilter - ChallengeResult / 未授权
问题描述
我正在运行带有Asp.Net Boilerplate 3.4.0 版Web 应用程序的Asp.Net Core 2.0 。
当我有一个经过身份验证的用户没有访问资源所需的权限时,aChallengeResult
由AbpAuthorizationFilter
通过Abp框架设置。此行为会导致用户返回到默认登录页面。如果用户通过身份验证,我想设置 aForbidResult
并将它们重定向到默认的 AccessDenied 页面。
在查看了我的选项后,我发现我有以下选项:
- 添加我自己的授权过滤器并在服务配置
MvcOptions
之前注册。AddAbp()
过滤器将有条件地将结果设置为挑战或禁止 - 覆盖
OnRedirectToLogin
事件(即,为经过身份验证的用户自定义) - 覆盖
HandleChallengeAsync
处理程序(即检查请求是否经过身份验证,并为未经身份验证的请求发出 ForbidResult 或 ChallengeResult)
AbpMvcAuthorizeFilter
我注意到在 ABP 的 .Net 框架版本中, (ie, )中有可覆盖的方法HandleUnauthorizedRequest
;但是,这不适用于 .Net Core 版本。请参阅 GitHub 问题 1256 ->
使 AbpMvcAuthorizeFilter 和 AbpApiAuthorizeFilter 可覆盖
问题:
是否有其他人需要更改默认的Abp行为,即为ChallengeResult
未经授权的请求返回 a?如果是,您使用了什么解决方案?我是否在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
必须假设经过身份验证的用户试图访问未经授权的资源。目前,我只看到通过方法Events.RedirectToLogin
提出的问题。话虽如此,可以放心地假设此事件只会由结果引发。CookieAuthenticationHandler.csCookieAuthenticationHandler
HandleChallengeAsync
ChallengeResult
选项 3:
选项三将是最后一个选项(即不惜一切代价避免)
主要目标
主要目标是为尝试访问未经授权资源的经过身份验证的用户提供更好的体验。与其将用户重定向到登录页面,不如将用户重定向到一个未授权/禁止的页面,该页面清楚地表明他们没有被授权。这可能包括提示用户提供更高特权凭据的选项。通过提示用户,它闻起来像一个ChallengeResult
结果流,所以也许我只是回答了我自己的问题。对于当前的行为,我没有太多关于“为什么”发布的上下文信息ChallengeResult
。我会知道用户已登录并且OnRedirectToLogin
事件已引发。这可能是足够的信息来自定义的行为ChallengeResult
对于经过身份验证的用户。这开始感觉这是正确的解决方案。关于使用这种方法的任何建议或反馈?
解决方案
在三个选项中,我选择了第二个选项(覆盖OnRedirectToLogin
事件),原因如下:
- 在不复制整个授权过滤器的情况下引入了最少的代码,只更改了两行代码。
- 使用自己的角色和权限集更好地控制挑战体验(MVC 应用程序也是 OIDC 客户端)(请参阅下面的代码解决方案)
- 在此响应时,
OnRedirectToLogin
事件仅由CookieAuthenticationHandlerHandleChallengeAsync
中的引发,因此这感觉像是覆盖行为的正确位置。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 默认AuthorizeFilter
将授权委托给 IPolicyEvaluator
. 如果授权失败且用户通过身份验证,则设置 Forbid 结果,或者如果授权失败且用户未通过身份验证,则设置 Challenge 结果。
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();
推荐阅读
- php - 如何在首页(wordpress)上仅显示来自post_type的一篇文章
- javascript - 模态弹出窗口的关闭动画
- angular - 如果用户正在访问它,则在我的网站中显示自定义通知,并且仅当用户没有关注我的网站选项卡时才显示推送通知
- common-lisp - 在 commonlisp 的嵌套列表中替换字符串
- testing - 在 Cucumber 中,Before 和 After 钩子在哪里
- c# - 语句执行但不将文本附加到 TextBox
- swift - SwiftUI 状态初始化器之间的区别
- python - 从另一个数组python为每个元素创建数组
- jquery - jquery需要在点击时切换文本并在第二次点击时再次切换回来
- java - Heroku 构建失败,因为缺少 npm