在《asp.net core認(rèn)證與授權(quán)》中講解了固定和自定義角色授權(quán)系統(tǒng)權(quán)限,其實(shí)我們還可以通過其他方式來授權(quán),比如可以通過角色組,用戶名,生日等,但這些主要取決于ClaimTypes,其實(shí)我們也可以自定義鍵值來授權(quán),這些統(tǒng)一叫策略授權(quán),其中更強(qiáng)大的是,我們可以自定義授權(quán)Handler來達(dá)到靈活授權(quán),下面一一展開。
員工經(jīng)過長期磨合與沉淀,具備了協(xié)作精神,得以通過團(tuán)隊(duì)的力量開發(fā)出優(yōu)質(zhì)的產(chǎn)品。創(chuàng)新互聯(lián)堅(jiān)持“專注、創(chuàng)新、易用”的產(chǎn)品理念,因?yàn)椤皩W⑺詫I(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡單”。公司專注于為企業(yè)提供成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、電商網(wǎng)站開發(fā),成都小程序開發(fā),軟件按需開發(fā)網(wǎng)站等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。注意:下面的代碼只是部分代碼,完整代碼參照:https://github.com/axzxs2001/Asp.NetCoreExperiment/tree/master/Asp.NetCoreExperiment/%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/PolicyPrivilegeManagement
首先看基于角色組,或用戶名,或基于ClaimType或自定義鍵值等授權(quán)策略,這些都是通過Services.AddAuthorization添加,并且是AuthorizationOptions來AddPolicy,這里策略的名稱統(tǒng)一用RequireClaim來命名,不同的請求的策略名稱各不相同,如用戶名時(shí)就用policy.RequireUserName(),同時(shí),在登錄時(shí),驗(yàn)證成功后,要添加相應(yīng)的Claim到ClaimsIdentity中:
Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAuthorization(options => { //基于角色的策略 options.AddPolicy("RequireClaim", policy => policy.RequireRole("admin", "system")); //基于用戶名 //options.AddPolicy("RequireClaim", policy => policy.RequireUserName("桂素偉")); //基于Claim //options.AddPolicy("RequireClaim", policy => policy.RequireClaim(ClaimTypes.Country,"中國")); //自定義值 // options.AddPolicy("RequireClaim", policy => policy.RequireClaim("date","2017-09-02")); }).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>{ options.LoginPath = new PathString("/login"); options.AccessDeniedPath = new PathString("/denied"); }); }
HomeController.cs
using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using PolicyPrivilegeManagement.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; namespace PolicyPrivilegeManagement.Controllers { [Authorize(Policy = "RequireClaim")] public class HomeController : Controller { PermissionHandler _permissionHandler; public HomeController(IAuthorizationHandler permissionHandler) { _permissionHandler = permissionHandler as PermissionHandler; } public IActionResult Index() { return View(); } public IActionResult PermissionAdd() { return View(); } public IActionResult Contact() { ViewData["Message"] = "Your contact page."; return View(); } public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } [AllowAnonymous] [HttpGet("login")] public IActionResult Login(string returnUrl = null) { TempData["returnUrl"] = returnUrl; return View(); } [AllowAnonymous] [HttpPost("login")] public async Task<IActionResult> Login(string userName, string password, string returnUrl = null) { var list = new List<dynamic> { new { UserName = "gsw", Password = "111111", Role = "admin",Name="桂素偉",Country="中國",Date="2017-09-02",BirthDay="1979-06-22"}, new { UserName = "aaa", Password = "222222", Role = "system",Name="測試A" ,Country="美國",Date="2017-09-03",BirthDay="1999-06-22"} }; var user = list.SingleOrDefault(s => s.UserName == userName && s.Password == password); if (user != null) { //用戶標(biāo)識(shí) var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Sid, userName)); identity.AddClaim(new Claim(ClaimTypes.Name, user.Name)); identity.AddClaim(new Claim(ClaimTypes.Role, user.Role)); identity.AddClaim(new Claim(ClaimTypes.Country, user.Country)); identity.AddClaim(new Claim("date", user.Date)); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity)); if (returnUrl == null) { returnUrl = TempData["returnUrl"]?.ToString(); } if (returnUrl != null) { return Redirect(returnUrl); } else { return RedirectToAction(nameof(HomeController.Index), "Home"); } } else { const string badUserNameOrPasswordMessage = "用戶名或密碼錯(cuò)誤!"; return BadRequest(badUserNameOrPasswordMessage); } } [HttpGet("logout")] public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return RedirectToAction("Index", "Home"); } [AllowAnonymous] [HttpGet("denied")] public IActionResult Denied() { return View(); } } }
上面的授權(quán)策略都相對簡單,單一,使用場景也很有限,就和固定角色授權(quán)如出一轍,其實(shí)可以用更好的來例用授權(quán),那就是自定義授權(quán)Handler,我們在《asp.net core認(rèn)證與授權(quán)》一文中,是通過中間件來達(dá)到自定義解色的,現(xiàn)在我們換個(gè)思路,通過自定義授權(quán)Handler來實(shí)現(xiàn)。
首先定義一個(gè)UserPermission,即用戶權(quán)限實(shí)體類
/// <summary> /// 用戶權(quán)限 /// </summary> public class UserPermission { /// <summary> /// 用戶名 /// </summary> public string UserName { get; set; } /// <summary> /// 請求Url /// </summary> public string Url { get; set; } }
接下來定義一個(gè)PermissionRequirement,為請求條件實(shí)體類
/// <summary> /// 必要參數(shù)類 /// </summary> public class PermissionRequirement : IAuthorizationRequirement { /// <summary> /// 用戶權(quán)限集合 /// </summary> public List<UserPermission> UserPermissions { get;private set; } /// <summary> /// 無權(quán)限action /// </summary> public string DeniedAction { get; set; } /// <summary> /// 構(gòu)造 /// </summary> /// <param name="deniedAction">無權(quán)限action</param> /// <param name="userPermissions">用戶權(quán)限集合</param> public PermissionRequirement(string deniedAction, List<UserPermission> userPermissions) { DeniedAction = deniedAction; UserPermissions = userPermissions; } }
再定義自定義授權(quán)Hanlder,我們命名為PermissionHandler,此類必需繼承AuthorizationHandler<T>,只用實(shí)現(xiàn)public virtualTask HandleAsync(AuthorizationHandlerContext context),些方法是用戶請求時(shí)驗(yàn)證是否授權(quán)的主方法,所以實(shí)現(xiàn)與自定義角色中間件的Invoke很相似。
using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; namespace PolicyPrivilegeManagement.Models { /// <summary> /// 權(quán)限授權(quán)Handler /// </summary> public class PermissionHandler : AuthorizationHandler<PermissionRequirement> { /// <summary> /// 用戶權(quán)限 /// </summary> public List<UserPermission> UserPermissions { get; set; } protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { //賦值用戶權(quán)限 UserPermissions = requirement.UserPermissions; //從AuthorizationHandlerContext轉(zhuǎn)成HttpContext,以便取出表求信息 var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext; //請求Url var questUrl = httpContext.Request.Path.Value.ToLower(); //是否經(jīng)過驗(yàn)證 var isAuthenticated = httpContext.User.Identity.IsAuthenticated; if (isAuthenticated) { if (UserPermissions.GroupBy(g => g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0) { //用戶名 var userName = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Sid).Value; if (UserPermissions.Where(w => w.UserName == userName && w.Url.ToLower() == questUrl).Count() > 0) { context.Succeed(requirement); } else { //無權(quán)限跳轉(zhuǎn)到拒絕頁面 httpContext.Response.Redirect(requirement.DeniedAction); } } else { context.Succeed(requirement); } } return Task.CompletedTask; } } }
此次的Startup.cs的ConfigureServices發(fā)生了變化,如下
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAuthorization(options => { //自定義Requirement,userPermission可從數(shù)據(jù)庫中獲得 var userPermission = new List<UserPermission> { new UserPermission { Url="/", UserName="gsw"}, new UserPermission { Url="/home/permissionadd", UserName="gsw"}, new UserPermission { Url="/", UserName="aaa"}, new UserPermission { Url="/home/contact", UserName="aaa"} }; options.AddPolicy("Permission", policy => policy.Requirements.Add(new PermissionRequirement("/denied", userPermission))); }).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>{ options.LoginPath = new PathString("/login"); options.AccessDeniedPath = new PathString("/denied"); }); //注入授權(quán)Handler services.AddSingleton<IAuthorizationHandler, PermissionHandler>(); }
HomeController中代碼如下:
using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using PolicyPrivilegeManagement.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; namespace PolicyPrivilegeManagement.Controllers { [Authorize(Policy = "Permission")] public class HomeController : Controller { PermissionHandler _permissionHandler; public HomeController(IAuthorizationHandler permissionHandler) { _permissionHandler = permissionHandler as PermissionHandler; } public IActionResult Index() { return View(); } public IActionResult PermissionAdd() { return View(); } [HttpPost("addpermission")] public IActionResult AddPermission(string url,string userName) { //添加權(quán)限 _permissionHandler.UserPermissions.Add(new UserPermission { Url = url, UserName = userName }); return Content("添加成功"); } public IActionResult Contact() { ViewData["Message"] = "Your contact page."; return View(); } public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } [AllowAnonymous] [HttpGet("login")] public IActionResult Login(string returnUrl = null) { TempData["returnUrl"] = returnUrl; return View(); } [AllowAnonymous] [HttpPost("login")] public async Task<IActionResult> Login(string userName, string password, string returnUrl = null) { var list = new List<dynamic> { new { UserName = "gsw", Password = "111111", Role = "admin",Name="桂素偉",Country="中國",Date="2017-09-02",BirthDay="1979-06-22"}, new { UserName = "aaa", Password = "222222", Role = "system",Name="測試A" ,Country="美國",Date="2017-09-03",BirthDay="1999-06-22"} }; var user = list.SingleOrDefault(s => s.UserName == userName && s.Password == password); if (user != null) { //用戶標(biāo)識(shí) var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Sid, userName)); identity.AddClaim(new Claim(ClaimTypes.Name, user.Name)); identity.AddClaim(new Claim(ClaimTypes.Role, user.Role)); identity.AddClaim(new Claim(ClaimTypes.Country, user.Country)); identity.AddClaim(new Claim("date", user.Date)); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity)); if (returnUrl == null) { returnUrl = TempData["returnUrl"]?.ToString(); } if (returnUrl != null) { return Redirect(returnUrl); } else { return RedirectToAction(nameof(HomeController.Index), "Home"); } } else { const string badUserNameOrPasswordMessage = "用戶名或密碼錯(cuò)誤!"; return BadRequest(badUserNameOrPasswordMessage); } } [HttpGet("logout")] public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return RedirectToAction("Index", "Home"); } [AllowAnonymous] [HttpGet("denied")] public IActionResult Denied() { return View(); } } }
本例設(shè)計(jì)是當(dāng)用戶gsw密碼111111登錄時(shí),是不能訪問/home/contact的,剛登錄時(shí)訪該action是不成功的,這里我們在/home/addpermission中添加一個(gè)Action名稱:/home/contact,用戶名:gsw的信息,此時(shí)再訪問/home/contact,會(huì)發(fā)現(xiàn)是可以訪問的,這是因?yàn)槲覀儫岣铝薖ermissionHandler中的用戶權(quán)限集合,用戶的權(quán)限得到了擴(kuò)展和變化。
其實(shí)用中間件能達(dá)到靈活權(quán)限的設(shè)置,用自定義授權(quán)Handler也可以,接下來比較一下兩種做法的優(yōu)劣:
中間件 | 自定義授權(quán)Handler | |
用戶權(quán)限集合 | 靜態(tài)對象 | 實(shí)體化對象 |
熱更新時(shí) | 用中間件名稱.用戶權(quán)限集合更新 | 因?yàn)樵赟tartup.cs中,PermissionHandler是依賴注放的,可以在熱更新的構(gòu)造中獲取并操作 |
性能方面 | 每個(gè)action請求都會(huì)觸發(fā)Invock方法,標(biāo)記[AllowAnonymous]特性的Action也會(huì)觸發(fā) | 只有標(biāo)記[Authorize]特性的Action會(huì)觸發(fā)該方法,標(biāo)記[AllowAnonymous]特性的Action不會(huì)觸發(fā),性能更優(yōu)化 |
最后,把授權(quán)策略做了個(gè)NuGet的包,大家可在asp.net core 2.0的項(xiàng)目中查詢 AuthorizePolicy引用使用這個(gè)包,包對應(yīng)的github地址:https://github.com/axzxs2001/AuthorizePolicy,歡迎大家提出建議,來共同完善這個(gè)授權(quán)策略。
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。
本文題目:asp.netcore策略授權(quán)-創(chuàng)新互聯(lián)
分享路徑:http://bm7419.com/article8/ipoip.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、手機(jī)網(wǎng)站建設(shè)、域名注冊、用戶體驗(yàn)、網(wǎng)站制作、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容