認證受權方案之受權初識

1.前言

回顧認證受權方案之JwtBearer認證html

受權

在上一篇中,咱們經過JwtBearer的方式認證,瞭解在認證時,都是基於Claim的,所以咱們能夠經過用戶令牌獲取到用戶的Claims,在受權過程當中對這些Claims進行驗證,從而來判斷是否具備獲取或執行目標資源操做的權限。本章就來介紹一下 ASP.NET Core 的受權系統的簡單使用。數據庫

2.說明

受權與身份認證是相互獨立,可是,受權卻須要一種身份驗證機制,所以,身份驗證能夠爲當前用戶建立一個或多個標識,是肯定用戶真實身份的過程。而受權是根據標識肯定用戶可執行的操做的過程,其本質就是具備某種特性的用戶會有權限訪問某個資源或者執行某個操做。例如:一個擁有管理員身份的用戶有建立人員、刪除人員、編輯人員和刪除人員的操做權限,而一個非管理身份的用戶僅有讀取本身信息的權限。api

這時候,你可能會問,究竟怎樣特性的用戶能夠被受權訪問某個資源或執行某個操做。由此咱們引出了受權策略的方式,能夠根據用戶擁有的角色,也能夠根據用戶的職位,部門甚至是性別,年齡等等特性進行受權。asp.net

經過創建受權策略方式,檢驗認證的用戶所攜帶的身份聲明(ClaimsPrincipal對象)與受權策略是否一致,從而肯定用戶能否執行操做。dom

受權

3.受權

3.1. 基於角色

3.1.1 添加角色

將角色賦予某個控制器或控制器內的操做,指定當前用戶必須是其角色才能訪問請求資源。ide

可使用Authorize屬性的Roles特性指定所請求資源的角色。學習

例如:ui

  • 分配了「admin」角色用戶進行訪問操做
[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
{ 
}

3.1.2 添加策略的角色

能夠建立策略的方式進行訪問控制,在配置受權服務中添加註冊受權服務策略。設計

在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
    {
    
    }

3.2. 基於聲明

3.2.1添加聲明

對當前用戶必須擁有的聲明,並將聲明賦予某個控制器或控制器內的操做,所以,指定聲明必須持有對應的值才能訪問請求資源。

聲明要求基於策略,因此必須進行構建一個表示聲明要求的策略,才能進行受權。

最簡單的類型聲明是將判斷聲明是否存在,而不檢查值。

能夠建立策略的方式進行訪問控制,在配置受權服務中添加註冊受權服務策略。

在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"));
        });
    }

3.3 基於策略

上面介紹的基於角色和基於聲明的受權,都使用了要求、要求處理程序和預配置的策略。這些在構建上提供了便捷,可是最終都是生成受權策略。ASP.NET Core,設計了另外一種靈活的受權方式,一種更豐富的可重複使用的受權結構,基於策略的受權,同時這也是受權的核心。

這節會先講一下受權策略的應用,在下一節中,會對受權策略的核心進行一步步的詳解。

在上面咱們簡單的介紹了基於策略的角色受權,可是這種方式無非基於角色或者聲明多一些。

所以,這裏咱們基於自定義策略受權的方式,實現受權。

自定義受權,就要咱們本身寫策略提供器,本身根據不一樣的參數來生成不一樣的策略,從新實現策略的方式。策略要求由如下兩種元素組成:僅保留數據的要求類,以及對用戶驗證數據的受權處理程序。建立自定義要求,還能夠進一步表達特定策略。

3.3.1. 定義權限策略PermissionRequirement

定義一個權限策略,這個策略幷包含一些屬性。

public class PermissionRequirement: IAuthorizationRequirement
{
    public string _permissionName { get; }

    public PermissionRequirement(string PermissionName)
    {
        _permissionName = PermissionName;
    }
}

3.3.2. 再定義一個策略處理類

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

3.3.3. 下面展現瞭如何將自定義要求添加到策略

(請注意,因爲這是自定義要求,所以沒有擴展方法,而必須繼續處理策略對象的整個 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 系統註冊多個處理程序,有一個成功就足夠了。

    }

3.3.4. 應用自定義的策略的特性

指定當前用戶必須是應用對控制器或控制器內的操做,如

[Authorize(Policy = "customizePermisson")]
    public class WeatherForecastController : ControllerBase
    { 
    }

4.場景

在上一篇認證受權方案之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();
    }
}

5.運行

5.1. 獲取token

分別獲取role爲admin和role爲user的狀況下頒發的token,只有在角色爲admin的狀況下才能受權經過。

5.2. 受權資源接口訪問

在role爲admin的狀況下

受權

受權

在role爲user的狀況下

受權

受權

由上可知,只有在角色爲admin的狀況下,才能訪問目標資源進行操做。

6.總結

  1. 從上一篇的認證到這一篇的受權階段,簡單的介紹了Asp.net Core的認證受權系統,對受權有了初步的認識以及使用,對受權進行劃分爲兩種,一種是基於角色的受權,但隨着角色的增長會對處理受權產生限制,不適合表達複雜的受權邏輯。另外一種是基於策略的身份驗證,策略包含一系列基於聲明的要求,以及基於可從 HTTP 上下文或外部源注入的其餘任何信息的自定義邏輯。這些要求各自與一個或多個處理程序相關聯,這些處理程序負責要求的實際計算。
  2. 能夠發現,asp.net core提供的受權策略是一個很是強大豐富且靈活的認證受權方案,可以知足大部分的受權場景。
  3. 若是有不對的或不理解的地方,但願你們能夠多多指正,提出問題,一塊兒討論,不斷學習,共同進步。
  4. 所以,在後續的篇章中,會繼續探索受權系統,對受權策略的核心進行一步步的詳解。
  5. 本示例源碼地址

參考文獻文檔

相關文章
相關標籤/搜索