builder.Services.AddAuthorization(authorizationOptions => { authorizationOptions.AddPolicy("AspManager", authorizationPolicy => { authorizationPolicy.RequireRole("Manager"); authorizationPolicy.RequireClaim("Coding-Skill", "ASP.NET Core MVC"); }); });AspManager策略有两个必要条件:
[Authorize(Policy = "AspManager")] public IActionResult Project() => View("Index", User.Claims);现在,ASP.NET Core Identity 只授权下面用户访问Project方法:
名称 |
描述 |
RequireUserName(name) |
指定特定用户 |
RequireClaim(type, value) |
用户需要有Claim类型和对应的值(值类型Param: params string[] 或者 Param: IEnumerable<string>) |
RequireRole(roles) |
用户必须是指定角色的成员。参数类型为: Param: params string[] roles 或者 Param: IEnumerable<string> roles |
AddRequirements(requirement) |
指定一个客户自定义策略 |
public class AllowUserPolicy : IAuthorizationRequirement { public string[] AllowUsers { get; set; } public AllowUserPolicy(params string[] allowUsers) { AllowUsers=allowUsers; } }AllowUserPolicy类实现了IAuthorizationRequirement 接口并且通过构造函数参数获取到所有允许访问资源的用户,下面我们在CustomPolicy文件夹下创建另外一个类AllowUsersHandler.cs,代码如下:
public class AllowUsersHandler : AuthorizationHandler<AllowUserPolicy> { public override Task HandleAsync(AuthorizationHandlerContext context) { return base.HandleAsync(context); } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AllowUserPolicy requirement) { if (requirement.AllowUsers.Any(user => user.Equals(context.User.Identity?.Name, StringComparison.OrdinalIgnoreCase))) { context.Succeed(requirement); } else { context.Fail(); } return Task.CompletedTask; }AllowUsersHandler授权Handler继承AuthorizationHandler类,当授权系统需要检查访问的Action时,HandleRequirementAsync()方法被调用,这个方法的参数接受AuthorizationHandlerContext 对象和AllowUserPolicy 类,AllowUserPolicy类提供了允许访问资源的用户。AuthorizationHandlerContext类主要成员如下:
名称 |
描述 |
Succeed(requirement) |
如果请求满足要求,则调用此方法。该方法的参数是AllowUserPolicy对象 |
Fail() |
如果请求不满足要求,则调用该方法 |
Resource |
这个属性返回授权访问资源的一个对象 |
// 堆代码 duidaima.com builder.Services.AddTransient<IAuthorizationHandler,AllowUsersHandler>(); builder.Services.AddAuthorization(authorizationOptions => { authorizationOptions.AddPolicy("AspManager", authorizationPolicy => { authorizationPolicy.RequireRole("Manager"); authorizationPolicy.RequireClaim("Coding-Skill", "ASP.NET Core MVC"); }); authorizationOptions.AddPolicy("AllowTom", authorizationPolicy => { authorizationPolicy.AddRequirements(new AllowUserPolicy("tom")); }); });现在,我们将这个策略应用到Controller的方法上,我们在ClaimsController中添加一个TomFiles方法并在该方法上应用这个[Authorize(Policy = "AllowTom")]特性。看如下代码:
[Authorize(Policy = "AllowTom")] public IActionResult TomFiles() => View("Index", User.Claims);这个方法只能被tom的用户给调用。如果别的用户调用这个方法将调转到拒绝页面。使用Tom用户进行测试,输入https://localhost:
7296/Claims/TomFiles
public class AllowPrivatePolicy : IAuthorizationRequirement { } public class AllowPrivateHandler : AuthorizationHandler<AllowPrivatePolicy> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AllowPrivatePolicy requirement) { string [] allowUsers = context.Resource as string[]; if(allowUsers.Any(user=>user.Equals(context.User.Identity?.Name,StringComparison.OrdinalIgnoreCase))) { context.Succeed(requirement); } else { context.Fail(); } return Task.CompletedTask; } }我们在应用程序的Program类中注册AuthorizationHandler,并创建一个新的策略叫PrivateAccess
builder.Services.AddTransient<IAuthorizationHandler, AllowUsersHandler>(); builder.Services.AddTransient<IAuthorizationHandler,AllowPrivateHandler>(); builder.Services.AddAuthorization(authorizationOptions => { authorizationOptions.AddPolicy("AspManager", authorizationPolicy => { authorizationPolicy.RequireRole("Manager"); authorizationPolicy.RequireClaim("Coding-Skill", "ASP.NET Core MVC"); }); authorizationOptions.AddPolicy("AllowTom", authorizationPolicy => { authorizationPolicy.AddRequirements(new AllowUserPolicy("tom")); }); authorizationOptions.AddPolicy("PrivateAccess", authorizationPolicy => { authorizationPolicy.AddRequirements(new AllowPrivatePolicy()); }); });注意我们没有通过policy.AddRequirements(new AllowPrivate Policy())传递任何参数到AllowPrivatePolicy类,相反我们通过Controller传递数据。最后,在ClaimsController构造函数中添加IAuthorizationService服务。添加一个PrivateAccess方法来验证刚才我们添加的PrivateAccess。我们添加一个新的PrivateAccess方法并且使用authService.AuthorizeAsync 来验证我们刚添加的PrivateAccess策略
public async Task<IActionResult> PrivateAccess() { string[] allowedUsers = { "tom", "alice" }; var authorized=await _authorizationService.AuthorizeAsync(User,allowedUsers,"PrivateAccess"); if(authorized.Succeeded) { return View("Index",User.Claims); } else { return new ChallengeResult(); } }
这个方法只能有tom和alice这两个用户调用。注意我们给AllowPrivateHandler了的AuthorizeAsync()方法的第二个参数提供了allowUsers的变量。
如下代码:
var authorized=await _authorizationService.AuthorizeAsync(User,allowedUsers,"PrivateAccess");AllowPrivateHandler类获取allowedUsers 值通过AuthorizationHandlerContext 类的 Resource 属性,代码如下
string[] allowUsers = context.Resource as string[];初始化ChallengeResult 会强制除了tom和alice以外的用户调转到登录页面。使用alice用户登录我们可以看到该方法被调用,进入https://localhost:7296/Claims/PrivateAccess