这一节我们主要介绍在ASP.NET Core Identity中使用策略进行授权,Policy是用户必须具备一组集合为授权访问应用程序上的资源。Identity Policy的授权可以包含对用户的Role和Claim, 这有助于我们在应用程序中构建更丰富的授权结构
例如:我们创建一个名称为MIT的Identity Policy,该Policy包含3个必要条件:“高中成绩为A”,“18岁以下”,“美国国籍”。现在我们将这个策略应用到MIT门户网站的申请区域,只有这些学生才能申请研究生课程:.
-
高中毕业成绩为A
-
18岁以下
-
美国国籍
我们在程序中创建Identity策略:
builder.Services.AddAuthorization(authorizationOptions =>{authorizationOptions.AddPolicy("AspManager", authorizationPolicy =>{authorizationPolicy.RequireRole("Manager");authorizationPolicy.RequireClaim("Coding-Skill", "ASP.NET Core MVC");});});
-
用户角色必须是Manager -
用户Claim类型是 Coding-Skill,Claim值是ASP.NET Core MVC
2、基于ASP.NET Core Identity 策略授权
我们可以把刚才创建的策略使用到任何的Controller和Action方法上,在应用程序中使用基于策略授权的特性,进入ClaimsController创建一个新的Project方法,将[Authorize(Policy = "AspManager")]特性应用到该方法上,代码如下:
[Authorize(Policy = "AspManager")]public IActionResult Project() => View("Index", User.Claims);
-
该用户属于Manager角色。
-
该用户有Claim类型Coding-Skill和Claim值为ASP.NET Core MVC
|
名称 |
描述 |
|
RequireUserName(name) |
指定特定用户 |
|
RequireClaim(type, value) |
用户需要有Claim类型和对应的值(值类型Param: params string[] 或者 Param: IEnumerable<string>) |
|
RequireRole(roles) |
用户必须是指定角色的成员。参数类型为: Param: params string[] roles 或者 Param: IEnumerable<string> roles |
|
AddRequirements(requirement) |
指定一个客户自定义策略 |

现在我们尝试访问一下ClaimsController的Project方法,
https://localhost:7296/Claims/Project. 我们会看到访问拒绝:

因此我们需要给用户pintu添加一个类型是Coding-Skill和值是ASP.NET Core MVC的Claim。我们给pintu创建一个新的Claim ,URL为:https://localhost:7296/Claims/Create (看如下图片)

添加完之后,需要退出并且重新登录一下,我们进入如下URL
https//localhost:7296/Claims 。我们能看见最新添加的Claim


4、自定义Requirement策略授权
我们创建一个自定义策略,只允许Tom用户访问控制器的方法。如下所示:
-
创建一个类实现IAuthorizationRequirement 接口,它内部提供了一种机制判断是否授权成功或失败 -
创建一个实现 AuthorizationHandler类的子类,评估授权需求
public class AllowUserPolicy : IAuthorizationRequirement{public string[] AllowUsers { get; set; }public AllowUserPolicy(params string[] allowUsers){AllowUsers=allowUsers;}}
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 |
这个属性返回授权访问资源的一个对象 |
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:


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;}}
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();}}
var authorized=await _authorizationService.AuthorizeAsync(User,allowedUsers,"PrivateAccess");AllowPrivateHandler类获取allowedUsers 值通过AuthorizationHandlerContext 类的 Resource 属性,代码如下
string[] allowUsers = context.Resource as string[];
现在我们使用mary账户登录,进入相同的页面,我们发现调转到了登录页面
源代码地址:
https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/AspNetCore.Identity/Identity