一、简单授权
ASP.NET Core 中的授权通过 AuthorizeAttribute 和其各种参数来控制。 在其页面中,通过 [Authorize]
属性应用于控制器、操作或 Razor 页面,限制对已通过身份验证的用户的访问。
示例如下:
[Authorize] public class AccountController : Controller { public ActionResult Login() { } public ActionResult Logout() { } }
如果要对操作(而不是控制器)应用授权,请将属性应用于 AuthorizeAttribute
操作本身
示例如下:
public class AccountController : Controller { public ActionResult Login() { } [Authorize] public ActionResult Logout() { } }
你还可以使用属性,以 AllowAnonymous
允许未通过身份验证的用户访问各个操作。 例如:
[Authorize] public class AccountController : Controller { [AllowAnonymous] public ActionResult Login() { } public ActionResult Logout() { } }
二、基于角色的授权
基于角色的授权检查是声明性 — 的,开发人员将其嵌入到代码中、控制器或控制器内的操作,指定当前用户必须是其成员的角色才能访问请求的资源。
例如,以下代码将访问权限限制为属于角色成员的用户的任何操作:
[Authorize(Roles = "Administrator")] public class AdministrationController : Controller { }
多角色可以定义如下:
[Authorize(Roles = "HRManager,Finance")] public class SalaryController : Controller { }
如果应用多个属性,则访问用户必须是所有指定角色的成员;下面的示例要求用户必须是 PowerUser
和角色的成员 ControlPanelUser
。
[Authorize(Roles = "PowerUser")] [Authorize(Roles = "ControlPanelUser")] public class ControlPanelController : Controller { }
三、基于策略的授权
基于策略的授权,其实就是要求用户必须满足指定的策略要求,这个策略一般都是用户的一些基本信息,如名字、角色或者其他,我们首先要在在配置函数中,添加一个策略如下:
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddRazorPages(); services.AddAuthorization(options => { options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber")); }); }
如以上代码,要求用户的claim信息中包含EmployeeNumber属性
var claims = new List<Claim>() { new Claim(ClaimTypes.Name,username), new Claim("UserId",currentUser.UID.ToString()), new Claim(ClaimTypes.Role, roleName), new Claim("EmployeeNumber",“1"), };
那么在控制器中,只需要以下代码,并能实现对权限的控制
[Authorize(Policy = "EmployeeOnly")] public IActionResult VacationBalance() { return View(); }
基于策略的授权,
policy函数具有以下一些常用的函数:
AddAuthenticationSchemes(String[])
将指定的身份验证添加 schemes 到 AuthenticationSchemes 此实例的。
AddRequirements(IAuthorizationRequirement[])
将指定的添加 requirements 到 Requirements 此实例的。
Build()
AuthorizationPolicy根据此实例中的要求生成一个新的。
Combine(AuthorizationPolicy)
将指定的合并 policy 到当前实例中。
RequireAssertion(Func<AuthorizationHandlerContext,Boolean>)
将添加 AssertionRequirement 到当前实例中。
RequireAssertion(Func<AuthorizationHandlerContext,Task<Boolean>>)
将添加 AssertionRequirement 到当前实例中。
RequireAuthenticatedUser()
该实例强制对当前用户进行身份验证。
RequireClaim(String)
要求当前用户具有指定的声明。
RequireClaim(String, IEnumerable<String>)
这要求当前用户具有指定的声明,并且声明值必须是允许的值之一。
RequireClaim(String, String[])
这要求当前用户具有指定的声明,并且声明值必须是允许的值之一。
RequireRole(IEnumerable<String>)
该实例强制当前用户必须至少有一个指定的角色。
RequireRole(String[])
该实例强制当前用户必须至少有一个指定的角色。
RequireUserName(String)
强制当前用户与指定的名称匹配。
除以上功能之外,用于可以自定义策略,实现对页面的授权,其定义策略的基本方法如下:
1、实现IAuthorizationRequirement接口,定义一个策略规范
using Microsoft.AspNetCore.Authorization; public class MinimumAgeRequirement : IAuthorizationRequirement { public int MinimumAge { get; } public MinimumAgeRequirement(int minimumAge) { MinimumAge = minimumAge; } }
2、实现策略检查器,其负责对策略进行检查,以下代码请求用户年纪,并且进行策略比较,实现授权
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumAgeRequirement requirement) { if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth && c.Issuer == "http://contoso.com")) { //TODO: Use the following if targeting a version of //.NET Framework older than 4.6: // return Task.FromResult(0); return Task.CompletedTask; } var dateOfBirth = Convert.ToDateTime( context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth && c.Issuer == "http://contoso.com").Value); int calculatedAge = DateTime.Today.Year - dateOfBirth.Year; if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge)) { calculatedAge--; } if (calculatedAge >= requirement.MinimumAge) { context.Succeed(requirement); } //TODO: Use the following if targeting a version of //.NET Framework older than 4.6: // return Task.FromResult(0); return Task.CompletedTask; } }
3、在ConfigureServices中添加策略检查代码,如下所示:
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddRazorPages(); services.AddAuthorization(options => { options.AddPolicy("AtLeast21", policy => policy.Requirements.Add(new MinimumAgeRequirement(21))); });
//添加一个可以注入的对象 services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>(); }
4、如果要实现多个授权策略,可以实现继承如下接口
ublic class PermissionHandler : IAuthorizationHandler { public Task HandleAsync(AuthorizationHandlerContext context) { var pendingRequirements = context.PendingRequirements.ToList(); foreach (var requirement in pendingRequirements) { if (requirement is ReadPermission) { if (IsOwner(context.User, context.Resource) || IsSponsor(context.User, context.Resource)) { context.Succeed(requirement); } } else if (requirement is EditPermission || requirement is DeletePermission) { if (IsOwner(context.User, context.Resource)) { context.Succeed(requirement); } } } //TODO: Use the following if targeting a version of //.NET Framework older than 4.6: // return Task.FromResult(0); return Task.CompletedTask; } private bool IsOwner(ClaimsPrincipal user, object resource) { // Code omitted for brevity return true; } private bool IsSponsor(ClaimsPrincipal user, object resource) { // Code omitted for brevity return true; }
四、策略授权提供程序IAuthorizationPolicyProvider
通常,在使用 基于策略的授权时,通过调用 AuthorizationOptions.AddPolicy
作为授权服务配置的一部分来注册策略。 在某些情况下,可能无法 (或理想的) 以这种方式注册所有的授权策略。 在这些情况下,可以使用自定义 IAuthorizationPolicyProvider
来控制如何提供授权策略
internal class MinimumAgePolicyProvider : IAuthorizationPolicyProvider { const string POLICY_PREFIX = "MinimumAge"; // Policies are looked up by string name, so expect 'parameters' (like age) // to be embedded in the policy names. This is abstracted away from developers // by the more strongly-typed attributes derived from AuthorizeAttribute // (like [MinimumAgeAuthorize()] in this sample) public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase) && int.TryParse(policyName.Substring(POLICY_PREFIX.Length), out var age)) { var policy = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme); policy.AddRequirements(new MinimumAgeRequirement(age)); return Task.FromResult(policy.Build()); } return Task.FromResult<AuthorizationPolicy>(null); } }