【问题标题】:Deciding to use Authorization or not on a per-request basis in Asp.net Core在 Asp.net Core 中根据请求决定是否使用授权
【发布时间】:2020-02-19 15:20:54
【问题描述】:

我正在开发一个 ASP.net 核心 MVC 2.2 应用程序,目前我在控制器操作上使用经典的 [Authorize][AllowAnonymous] 属性来决定是否可以匿名访问某个操作或需要授权.

但是,我有一个要求,即仅当 http 请求中缺少某个标头时,某些操作才需要授权。通常我会通过简单地实现这一点:

[HttpGet]
[AllowAnonymous]
public IActionResult SomeAction()
{
    if (!Request.Headers.ContainsKey("something"))
    {
        return RedirectToAction("SomeActionWithAuth");
    }
    ...
}

[HttpGet]
[Authorize]
public IActionResult SomeActionWithAuth()
{
    ...
}

但是,在这种特殊情况下,我对避免重定向有严格的要求,所以我不能使用这种方法。

所以我的问题是:

  • 有没有办法在请求到达控制器之前拦截请求,并在运行时根据每个请求决定请求是否需要身份验证?
  • 如果这不可能,是否有办法在运行时决定将请求路由到哪个控制器/动作? (这样我就可以进行与上述类似的设置,两个操作具有不同的身份验证要求,但不会在客户端引起实际的 HTTP 重定向,这是我无法做到的)

【问题讨论】:

  • 您只需编写自己的授权过滤器来替换 Authorize / AllowAnonymous 过滤器。编写过滤器是rather straightforward

标签: c# asp.net-core asp.net-core-mvc asp.net-core-2.0


【解决方案1】:

创建您自己的授权策略来处理此问题。

public class HeaderRequirement : IAuthorizationRequirement
{
    public HeaderRequirement(string header)
    {
        Header = header;
    }

    public string Header { get; }
}

public class HeaderRequirementHandler : AuthorizationHandler<HeaderRequirement>
{
    protected override Task HeaderRequirementHandler (
        AuthorizationHandlerContext context,
        HeaderRequirement requirement)
    {
        var hasHeader = context.Request.Headers.ContainsKey(requirement.Header);
        if (hasHeader) // if we have the header
        {
            context.Succeed(requirement); // authorization successful
        }

        return Task.CompletedTask;
    }
}

将处理程序注册为服务

services.AddScoped&lt;IAuthorizationHandler, HeaderRequirementHandler&gt;();

将策略添加到授权服务

services.AddAuthorization(options =>
    {
        options.AddPolicy("SomeHeader", policy =>
            policy.Requirements.Add(new HeaderRequirement("SomeHeader")));
    });

现在你可以像这样使用它:[Authorize(Policy = "SomeHeader")]

如果您需要它更动态一点,如果您不想注册每个可能经过身份验证的标头,而是在运行时进行解释。你可以写你自己的policy provider

【讨论】:

  • 感谢您的回答。我的问题是:如果我不调用“context.Succeed()”,这种方法会表现得像“标准”授权过滤器吗?因为如果我找不到所需的标头,我需要它“回退”默认 [Authorize] 属性的标准行为,在我的情况下,它执行 NTLM/Windows 身份验证。
  • @Master_T 我不能肯定地说,因为这在很大程度上取决于您如何配置您的授权。
  • 我刚刚测试了它......它有效! (有点)。如果我在没有调用 context.Succeed() 的情况下返回,则会执行默认的授权行为(在我的情况下:NTLM auth)(浏览器会收到标准的 NTLM auth 质询)。身份验证通过后,HeaderRequirementHandler 将被第二次调用。这本身会导致无限循环,但是自从第二次对用户进行身份验证以来,如果我没有找到我正在寻找的标头,我会直接检查 context.User 对象以查看用户是否经过身份验证并执行我的权限直接在那里检查逻辑。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 2020-02-05
  • 1970-01-01
  • 2020-09-17
  • 1970-01-01
  • 2017-07-04
相关资源
最近更新 更多