回顧:認證受權方案之JwtBearer認證html
在上一篇中,咱們經過JwtBearer的方式認證,瞭解在認證時,都是基於Claim的,所以咱們能夠經過用戶令牌獲取到用戶的Claims,在受權過程當中對這些Claims進行驗證,從而來判斷是否具備獲取或執行目標資源操做的權限。本章就來介紹一下 ASP.NET Core 的受權系統的簡單使用。數據庫
受權與身份認證是相互獨立,可是,受權卻須要一種身份驗證機制,所以,身份驗證能夠爲當前用戶建立一個或多個標識,是肯定用戶真實身份的過程。而受權是根據標識肯定用戶可執行的操做的過程,其本質就是具備某種特性的用戶會有權限訪問某個資源或者執行某個操做。例如:一個擁有管理員身份的用戶有建立人員、刪除人員、編輯人員和刪除人員的操做權限,而一個非管理身份的用戶僅有讀取本身信息的權限。api
這時候,你可能會問,究竟怎樣特性的用戶能夠被受權訪問某個資源或執行某個操做。由此咱們引出了受權策略的方式,能夠根據用戶擁有的角色,也能夠根據用戶的職位,部門甚至是性別,年齡等等特性進行受權。asp.net
經過創建受權策略方式,檢驗認證的用戶所攜帶的身份聲明(ClaimsPrincipal對象)與受權策略是否一致,從而肯定用戶能否執行操做。dom
將角色賦予某個控制器或控制器內的操做,指定當前用戶必須是其角色才能訪問請求資源。ide
可使用Authorize
屬性的Roles特性指定所請求資源的角色。學習
例如:ui
[Authorize(Roles ="admin")] public class WeatherForecastController : ControllerBase { }
[Authorize(Roles ="admin,user")] public class WeatherForecastController : ControllerBase { }
其中只要知足admmin
或者user
其一就能夠進行訪問。.net
[Authorize(Roles = "admin")] [Authorize(Roles = "user")] public class WeatherForecastController : ControllerBase { }
能夠建立策略的方式進行訪問控制,在配置受權服務中添加註冊受權服務策略。設計
在Startup.cs文件中,經過ConfigureServices()
配置服務,建立一個容許具備admin
角色的用戶才能進行訪問的策略
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //添加受權角色策略 services.AddAuthorization(options => { options.AddPolicy("BaseRole", options => options.RequireRole("admin")); }); //或者指定多個容許的角色 //services.AddAuthorization(options => // { // options.AddPolicy("MoreBaseRole", options => options.RequireRole("admin","user")); // }); }
在控制器方法使用特性Policy
的屬性進行策略應用
[Authorize(Policy = "BaseRole")] public class WeatherForecastController : ControllerBase { }
對當前用戶必須擁有的聲明,並將聲明賦予某個控制器或控制器內的操做,所以,指定聲明必須持有對應的值才能訪問請求資源。
聲明要求基於策略,因此必須進行構建一個表示聲明要求的策略,才能進行受權。
最簡單的類型聲明是將判斷聲明是否存在,而不檢查值。
能夠建立策略的方式進行訪問控制,在配置受權服務中添加註冊受權服務策略。
在Startup.cs文件中,經過ConfigureServices()
配置服務,建立一個容許具備聲明的用戶才能進行訪問的策略
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //添加基於聲明的受權 services.AddAuthorization(options => { options.AddPolicy("BaseClaims", options => options.RequireClaim("name")); }); }
BaseClaims
聲明策略會檢查name
當前標識是否存在聲明。
在控制器方法使用特性Policy
的屬性進行策略應用
[Authorize(Policy = "BaseClaims")] public class WeatherForecastController : ControllerBase { }
可是,大多時候,咱們須要聲明包含值,只有指定容許值的列表,才能受權成功。因此,能夠添加指定值。
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //添加基於聲明的受權,指定容許值列表。 services.AddAuthorization(options => { options.AddPolicy("BaseClaims", options => options.RequireClaim("name","i3yuan")); }); }
上面介紹的基於角色和基於聲明的受權,都使用了要求、要求處理程序和預配置的策略。這些在構建上提供了便捷,可是最終都是生成受權策略。ASP.NET Core,設計了另外一種靈活的受權方式,一種更豐富的可重複使用的受權結構,基於策略的受權,同時這也是受權的核心。
這節會先講一下受權策略的應用,在下一節中,會對受權策略的核心進行一步步的詳解。
在上面咱們簡單的介紹了基於策略的角色受權,可是這種方式無非基於角色或者聲明多一些。
所以,這裏咱們基於自定義策略受權的方式,實現受權。
自定義受權,就要咱們本身寫策略提供器,本身根據不一樣的參數來生成不一樣的策略,從新實現策略的方式。策略要求由如下兩種元素組成:僅保留數據的要求類,以及對用戶驗證數據的受權處理程序。建立自定義要求,還能夠進一步表達特定策略。
PermissionRequirement
定義一個權限策略,這個策略幷包含一些屬性。
public class PermissionRequirement: IAuthorizationRequirement { public string _permissionName { get; } public PermissionRequirement(string PermissionName) { _permissionName = PermissionName; } }
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { var role = context.User.FindFirst(c => c.Type == ClaimTypes.Role); if (role != null) { var roleValue = role.Value; if (roleValue==requirement._permissionName) { context.Succeed(requirement); } } return Task.CompletedTask;
受權處理程序讀取與角色用戶關聯的聲明,並檢查自定義的角色,若是角色匹則成功,不然沒法返回成功。
這裏的自定義聲明是寫固定了,可是也能夠經過數據庫或外部服務的方式進行運行查詢獲取用戶相關角色信息相對應的判斷條件,從而在處理程序中進行判斷處理。
受權處理程序調用方法 Succeed
,同時傳遞當前要求,以通知此要求已成功獲得驗證。若是沒有傳遞要求,處理程序無需執行任何操做,能夠直接返回內容。不過,若是處理程序要肯定是否不符合要求(不管其餘處理程序是否已成功驗證同一要求),將會對受權上下文對象調用方法 Fail
。
(請注意,因爲這是自定義要求,所以沒有擴展方法,而必須繼續處理策略對象的整個 Requirements
集合):
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //基於自定義策略受權 services.AddAuthorization(options => { options.AddPolicy("customizePermisson", policy => policy .Requirements .Add(new PermissionRequirement("admin"))); }); //此外,還須要在 IAuthorizationHandler 類型的範圍內向 DI 系統註冊新的處理程序: services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>(); // 如前所述,要求可包含多個處理程序。若是爲受權層的同一要求向 DI 系統註冊多個處理程序,有一個成功就足夠了。 }
指定當前用戶必須是應用對控制器或控制器內的操做,如
[Authorize(Policy = "customizePermisson")] public class WeatherForecastController : ControllerBase { }
在上一篇認證受權方案之JwtBearer認證中,咱們已經實現了獲取token的方式,這一次,咱們實現一個以基於角色場景爲例的認證受權。
在原來生成token的方式中,添加多一個聲明角色的Claim,以下:
new Claim(JwtClaimTypes.Role,"admin")
[HttpGet] public IActionResult GetToken() { try { //定義發行人issuer string iss = "JWTBearer.Auth"; //定義受衆人audience string aud = "api.auth"; //定義許多種的聲明Claim,信息存儲部分,Claims的實體通常包含用戶和一些元數據 IEnumerable<Claim> claims = new Claim[] { new Claim(JwtClaimTypes.Id,"1"), new Claim(JwtClaimTypes.Name,"i3yuan"), new Claim(JwtClaimTypes.Role,"admin"), }; //notBefore 生效時間 // long nbf =new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds(); var nbf = DateTime.UtcNow; //expires //過時時間 // long Exp = new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds(); var Exp = DateTime.UtcNow.AddSeconds(1000); //signingCredentials 簽名憑證 string sign = "q2xiARx$4x3TKqBJ"; //SecurityKey 的長度必須 大於等於 16個字符 var secret = Encoding.UTF8.GetBytes(sign); var key = new SymmetricSecurityKey(secret); var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //String issuer = default(String), String audience = default(String), IEnumerable<Claim> claims = null, Nullable<DateTime> notBefore = default(Nullable<DateTime>), Nullable<DateTime> expires = default(Nullable<DateTime>), SigningCredentials signingCredentials = null var jwt = new JwtSecurityToken(issuer: iss, audience: aud, claims:claims,notBefore:nbf,expires:Exp, signingCredentials: signcreds); var JwtHander = new JwtSecurityTokenHandler(); var token = JwtHander.WriteToken(jwt); return Ok(new { access_token = token, token_type = "Bearer", }); } catch (Exception ex) { throw; } }
對控制器或控制器內的操做,指定當前用戶必須是其角色才能訪問請求資源,如WeatherForecastController.cs
[ApiController] [Route("[controller]")] [Authorize(Roles ="admin")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IEnumerable<WeatherForecast> Get() { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }) .ToArray(); } }
分別獲取role爲admin和role爲user的狀況下頒發的token,只有在角色爲admin的狀況下才能受權經過。
由上可知,只有在角色爲admin的狀況下,才能訪問目標資源進行操做。
HTTP
上下文或外部源注入的其餘任何信息的自定義邏輯。這些要求各自與一個或多個處理程序相關聯,這些處理程序負責要求的實際計算。參考文獻文檔