1.前言
回顧:認證授權方案之JwtBearer認證
在上一篇中,我們通過JwtBearer的方式認證,了解在認證時,都是基於Claim的,因此我們可以通過用戶令牌獲取到用戶的Claims,在授權過程中對這些Claims進行驗證,從而來判斷是否具有獲取或執行目標資源操作的權限。本章就來介紹一下 ASP.NET Core 的授權系統的簡單使用。
2.說明
授權與身份認證是相互獨立,但是,授權卻需要一種身份驗證機制,因此,身份驗證可以為當前用戶創建一個或多個標識,是確定用戶真實身份的過程。而授權是根據標識確定用戶可執行的操作的過程,其本質就是具有某種特性的用戶會有權限訪問某個資源或者執行某個操作。例如:一個擁有管理員身份的用戶有創建人員、刪除人員、編輯人員和刪除人員的操作權限,而一個非管理身份的用戶僅有讀取自己信息的權限。
這時候,你可能會問,究竟怎樣特性的用戶可以被授權訪問某個資源或執行某個操作。由此我們引出了授權策略的方式,可以根據用戶擁有的角色,也可以根據用戶的職位,部門甚至是性別,年齡等等特性進行授權。
通過建立授權策略方式,檢驗認證的用戶所攜帶的身份聲明(ClaimsPrincipal對象)與授權策略是否一致,從而確定用戶可否執行操作。
3.授權
3.1. 基於角色
3.1.1 添加角色
將角色賦予某個控制器或控制器內的操作,指定當前用戶必須是其角色才能訪問請求資源。
可以使用Authorize屬性的Roles特性指定所請求資源的角色。
例如:
- 分配了“admin”角色用戶進行訪問操作
[Authorize(Roles ="admin")]
public class WeatherForecastController : ControllerBase
{
}
- 以逗號分隔角色名來允行多個角色訪問操作
[Authorize(Roles ="admin,user")]
public class WeatherForecastController : ControllerBase
{
}
其中只要滿足admmin或者user其一就可以進行訪問。
- 同時滿足指定的多個角色進行的訪問操作
[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.總結
- 從上一篇的認證到這一篇的授權階段,簡單的介紹了Asp.net Core的認證授權系統,對授權有了初步的認識以及使用,對授權進行劃分為兩種,一種是基於角色的授權,但隨着角色的增加會對處理授權產生限制,不適合表達複雜的授權邏輯。另一種是基於策略的身份驗證,策略包含一系列基於聲明的要求,以及基於可從
HTTP上下文或外部源注入的其他任何信息的自定義邏輯。這些要求各自與一個或多個處理程序相關聯,這些處理程序負責要求的實際計算。 - 可以發現,asp.net core提供的授權策略是一個非常強大豐富且靈活的認證授權方案,能夠滿足大部分的授權場景。
- 如果有不對的或不理解的地方,希望大家可以多多指正,提出問題,一起討論,不斷學習,共同進步。
- 因此,在後續的篇章中,會繼續探索授權系統,對授權策略的核心進行一步步的詳解。
- 本示例源碼地址
參考文獻文檔
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司"嚨底家"!
※幫你省時又省力,新北清潔一流服務好口碑
※別再煩惱如何寫文案,掌握八大原則!
特斯拉(Tesla)高調宣布鋰電池儲能系統,其中針對企業用戶的「Powerpack」,100 度電售價 25,000 美元,已將平均儲能成本拉低到相當驚人的每度電 250 美元,一般認為若平均儲能成本降到每度電 100 美元,將引爆能源儲存革命,特斯拉挾 GigaFactory 的威力,正全速逼近這個目標,不過,卻有一個小型新創事業,認為現在就可以做到。 這家新創事業 FreeWire 初期募資金額不過 42.5 萬美元,加上美國海軍資助 50 萬美元,如何能超越家大業大的特斯拉?其實原理也不難,就是採用二手電池。 FreeWire 、日產(Nissan)與 NEC 合資的汽車能源供應公司(Automotive Energy Supply Corporation,AESC)合作,AESC 是僅次於 Panasonic,全球第二大車用鋰電池供應商,市佔率達 21%,2014 年銷售最佳的電動車是 Nissan Leaf,其電池正是由 AESC 供應,Nissan 每個月都會測試電池,每六個月就汰換效能已經衰退的鋰電池,數量以千計,對 Nissan 來說庫存這些二線電池是個麻煩,但這些電池的效能或許已經不不敷電動車所需,拿來做為能源儲存用途卻還很有用。 於是,FreeWire 以新電池六分之一的價格取得這些二手電池,第一步,是取之於電動車用之於電動車,將這些二手電池組裝成總容量 48 度電的行動充電車,專供電動車在本來沒有設置充電座的停車場、機場、企業廠區等處充電,行動充電車可以推到停車場任何一個停車格,幫電動車充電,如此一來,停車場可以省下設置大量充電座的成本,卻能提供身為少數的電動車主充電服務,而這些二手電池在每天充放電循環 2 次的情況下,還可以有 5 年的壽命。 