在 Asp.net 核心中决定是否在 per-request 基础上使用授权
Deciding to use Authorization or not on a per-request basis in Asp.net Core
我正在开发一个 ASP.net 核心 MVC 2.2 应用程序,目前我在我的控制器操作上使用经典的 [Authorize]
和 [AllowAnonymous]
属性来决定某个操作可以匿名访问或需要授权。
但是,我有一个要求,只有当 http 请求中缺少某个 header 时,某些操作才需要授权。通常我会通过简单地使用这样的东西来实现它:
[HttpGet]
[AllowAnonymous]
public IActionResult SomeAction()
{
if (!Request.Headers.ContainsKey("something"))
{
return RedirectToAction("SomeActionWithAuth");
}
...
}
[HttpGet]
[Authorize]
public IActionResult SomeActionWithAuth()
{
...
}
然而,在这种特殊情况下,我有一个严格的要求来避免重定向,所以我不能使用这种方法。
所以我的问题是:
- 有没有办法在请求到达控制器之前拦截请求,并在运行时根据 per-request 决定请求是否需要身份验证?
- 如果那不可能,是否有办法在运行时决定将请求路由到哪个 controller/action? (这样我就可以有一个类似于上面的设置,有两个具有不同身份验证要求的操作,但不会在客户端引起实际的 HTTP 重定向,这是我做不到的)
创建您自己的授权策略来处理此问题。
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<IAuthorizationHandler, HeaderRequirementHandler>();
将策略添加到授权服务
services.AddAuthorization(options =>
{
options.AddPolicy("SomeHeader", policy =>
policy.Requirements.Add(new HeaderRequirement("SomeHeader")));
});
现在你可以这样使用了:[Authorize(Policy = "SomeHeader")]
如果你需要它更动态一点,如果你不想注册每一个 header 可能被验证但宁愿在 run-time 解释。你可以写你自己的 policy provider
我正在开发一个 ASP.net 核心 MVC 2.2 应用程序,目前我在我的控制器操作上使用经典的 [Authorize]
和 [AllowAnonymous]
属性来决定某个操作可以匿名访问或需要授权。
但是,我有一个要求,只有当 http 请求中缺少某个 header 时,某些操作才需要授权。通常我会通过简单地使用这样的东西来实现它:
[HttpGet]
[AllowAnonymous]
public IActionResult SomeAction()
{
if (!Request.Headers.ContainsKey("something"))
{
return RedirectToAction("SomeActionWithAuth");
}
...
}
[HttpGet]
[Authorize]
public IActionResult SomeActionWithAuth()
{
...
}
然而,在这种特殊情况下,我有一个严格的要求来避免重定向,所以我不能使用这种方法。
所以我的问题是:
- 有没有办法在请求到达控制器之前拦截请求,并在运行时根据 per-request 决定请求是否需要身份验证?
- 如果那不可能,是否有办法在运行时决定将请求路由到哪个 controller/action? (这样我就可以有一个类似于上面的设置,有两个具有不同身份验证要求的操作,但不会在客户端引起实际的 HTTP 重定向,这是我做不到的)
创建您自己的授权策略来处理此问题。
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<IAuthorizationHandler, HeaderRequirementHandler>();
将策略添加到授权服务
services.AddAuthorization(options =>
{
options.AddPolicy("SomeHeader", policy =>
policy.Requirements.Add(new HeaderRequirement("SomeHeader")));
});
现在你可以这样使用了:[Authorize(Policy = "SomeHeader")]
如果你需要它更动态一点,如果你不想注册每一个 header 可能被验证但宁愿在 run-time 解释。你可以写你自己的 policy provider