如何在授权过程(策略或中间件)中检查自定义属性?

时间:2018-08-03 07:43:54

标签: c# asp.net-core-2.1

主要目标是当OIDC用户拥有类型为“ BlockedFrom”的自定义声明时阻止访问门户,该声明已添加在ClaimsTransformation中。

我已经通过Startup.Configure方法的中间件解决了它。一般原因是保留原始请求URL,而不重定向到/ Account / AccessDenied页面。

app.Use((context, next) =>
{
    var user = context.User;

    if (user.IsAuthenticated())
    {
        // Do not rewrite path when it marked with custom [AllowBlockedAttribute]!
        // /Home/Logout, for example. But how?
        //
        if (user.HasClaim(x => x.Type == UserClaimTypes.BlockedFrom))
        {
            // Rewrite to run specific method of HomeController for blocked users
            // with detailed message.
            //
            context.Request.Path = GenericPaths.Blocked;
        }
    }

    return next();
});

但是有一个意外结果:Logout的{​​{1}}方法也被阻止了。用户被阻止时无法注销,哈哈! 首先想到的是-检查自定义属性,例如HomeController。中间件中的硬编码路径常量看起来很疯狂。如何在中间件中访问调用方法的属性?

另一种(也是更优雅的)方法是将此逻辑放到自定义[AllowBlockedAttribute]中,并在BlockedHandler : AuthorizationHandler<BlockedRequirement>方法的MVC选项中将其分配为常规策略:

Startup.ConfigureServices

services.AddSingleton<IAuthorizationHandler, BlockedHandler>(); services.AddMvc(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddRequirements(new BlockedRequirement()) .Build(); // Set the default authentication policy to require users to be authenticated. // options.Filters.Add(new AuthorizeFilter(policy)); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 的假设实现:

BlockedHandler

好的,现在我们可以处理自定义属性了。似乎AuthorizationHandler并不是告诉HttpContext无需重定向即可更改其RequestPath的最佳位置。在哪里可以做到?

2 个答案:

答案 0 :(得分:1)

我已经在框架源代码中进行了一些挖掘,并找到了一种以授权处理程序方式进行这项工作的方法。

授权过程的入口点是 AuthorizeFilter 。筛选器上下文具有 Result 属性,该属性接受 IActionResult 。通过设置此属性,您可以缩短请求并显示所需的任何操作结果(包括视图)。这是解决方案的关键。

如果遵循执行路径,您将意识到筛选器上下文将传递到授权组件,并且可以在 IAuthorizationHandler.HandleRequirementAsync 方法中使用。您可以通过向下转换(如OP所示)从上下文对象的 Resource 属性中获取它。

还有一件重要的事情:您必须从授权处理程序中返回成功,否则不可避免地将导致重定向。 (如果您签出default implementation of IPolicyEvaluator,这一点将变得很清楚。)

因此,将所有这些放在一起:

open

答案 1 :(得分:0)

我认为AuthorizationHandler绝对是放置此逻辑的更好位置。但是-如果我正确理解-您的问题是,在此处理程序执行时,已经选择了要调用的动作,因此您无法再更改路由。

当然,标准方法是启动重定向,但您要避免这种情况以保留当前URL。

鉴于上述情况,我可以想到一种方法:全局action filter

  

动作过滤器可以在调用单个动作方法之前和之后立即运行代码。它们可用于处理传递给操作的参数以及从操作返回的结果。

OnActionExecuting 方法似乎是放置逻辑的正确位置,因为此时您可以访问action方法的属性,并且有机会缩短处理过程(通过设置(如果用户被阻止,则 ActionExecutingContext 参数的 Result 属性)。

如果您不熟悉过滤器的概念,则可以在this MSDN article中找到所有详细信息。