Asp 核心 MVC 2.1 授权基于每个用户的策略?
Asp Core MVC 2.1 Authorization based on policies per user?
在我的网络应用程序中,我想以这种方式根据用户应用策略。例如我有 3 个政策;
- 允许在星期一进入。
- 允许在特定时间进入。
- 禁止进入
- ...
用户John 激活了策略1,而用户Richard 只激活了策略2。例如,如果用户John 在我的应用程序中注册正常,但在某个控制器中将不允许该步骤,因为它是星期一。这些条件可以在执行时更改。如何在动作控制器中动态添加策略?
我一直在寻找,但我在 asp.net 核心中看到的是我必须将策略注册到启动项,这不符合我的逻辑。
我认为解决这个问题有两个关键:
- 使用multiple handlers for a single requirement允许单个端点由不同的规则授权
- 使用 dependency injection in requirement handlers 允许处理程序中的动态 rules/data
多个处理程序
首先,创建一个简单的需求:
public class CustomPolicyRequirement : IAuthorizationRequirement { }
然后,为其创建所需的处理程序。我根据您描述的策略制作了一些非常简单的示例处理程序:
public class MondaysRequirementHandler : AuthorizationHandler<CustomPolicyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomPolicyRequirement requirement)
{
// Allow John in on Mondays
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday && context.User.Identity.Name == "John")
context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class EveningsOnlyRequirementHandler : AuthorizationHandler<CustomPolicyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomPolicyRequirement requirement)
{
var now = DateTime.Now;
// Allow Richard in, as long as it's between 18:00 and 22:00
if (now.Hour >= 18 && now.Hour < 22 && context.User.Identity.Name == "Richard")
context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class ProhibitedUserRequirementHandler : AuthorizationHandler<CustomPolicyRequirement>
{
readonly IProhibitedUsersService prohibitedUsersService;
public ProhibitedUserRequirementHandler(IProhibitedUsersService prohibitedUsersService)
=> this.prohibitedUsersService = prohibitedUsersService;
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomPolicyRequirement requirement)
{
// Don't let prohbited users in, even if other handlers are satisfied
if (prohibitedUsersService.IsUserProhibited(context.User.Identity))
context.Fail();
return Task.CompletedTask;
}
}
由于所有处理程序都与 CustomPolicyRequirement
相关联,因此只要至少有一个处理程序成功并且没有一个失败,就可以满足要求。既不成功也不失败的处理程序不影响结果。
动态数据
第三个示例处理程序依赖于依赖注入服务:
public interface IProhibitedUsersService
{
bool IsUserProhibited(IIdentity user);
}
可以实施该服务以从 SQL 数据库(或任何其他来源)获取数据,这将允许在应用程序处于 运行 时调整规则。
在我的网络应用程序中,我想以这种方式根据用户应用策略。例如我有 3 个政策;
- 允许在星期一进入。
- 允许在特定时间进入。
- 禁止进入
- ...
用户John 激活了策略1,而用户Richard 只激活了策略2。例如,如果用户John 在我的应用程序中注册正常,但在某个控制器中将不允许该步骤,因为它是星期一。这些条件可以在执行时更改。如何在动作控制器中动态添加策略?
我一直在寻找,但我在 asp.net 核心中看到的是我必须将策略注册到启动项,这不符合我的逻辑。
我认为解决这个问题有两个关键:
- 使用multiple handlers for a single requirement允许单个端点由不同的规则授权
- 使用 dependency injection in requirement handlers 允许处理程序中的动态 rules/data
多个处理程序
首先,创建一个简单的需求:
public class CustomPolicyRequirement : IAuthorizationRequirement { }
然后,为其创建所需的处理程序。我根据您描述的策略制作了一些非常简单的示例处理程序:
public class MondaysRequirementHandler : AuthorizationHandler<CustomPolicyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomPolicyRequirement requirement)
{
// Allow John in on Mondays
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday && context.User.Identity.Name == "John")
context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class EveningsOnlyRequirementHandler : AuthorizationHandler<CustomPolicyRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomPolicyRequirement requirement)
{
var now = DateTime.Now;
// Allow Richard in, as long as it's between 18:00 and 22:00
if (now.Hour >= 18 && now.Hour < 22 && context.User.Identity.Name == "Richard")
context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class ProhibitedUserRequirementHandler : AuthorizationHandler<CustomPolicyRequirement>
{
readonly IProhibitedUsersService prohibitedUsersService;
public ProhibitedUserRequirementHandler(IProhibitedUsersService prohibitedUsersService)
=> this.prohibitedUsersService = prohibitedUsersService;
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomPolicyRequirement requirement)
{
// Don't let prohbited users in, even if other handlers are satisfied
if (prohibitedUsersService.IsUserProhibited(context.User.Identity))
context.Fail();
return Task.CompletedTask;
}
}
由于所有处理程序都与 CustomPolicyRequirement
相关联,因此只要至少有一个处理程序成功并且没有一个失败,就可以满足要求。既不成功也不失败的处理程序不影响结果。
动态数据
第三个示例处理程序依赖于依赖注入服务:
public interface IProhibitedUsersService
{
bool IsUserProhibited(IIdentity user);
}
可以实施该服务以从 SQL 数据库(或任何其他来源)获取数据,这将允许在应用程序处于 运行 时调整规则。