分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

asp.net core策略授权

发布时间:2023-09-06 01:09责任编辑:顾先生关键词:暂无标签

在《asp.net core认证与授权》中讲解了固定和自定义角色授权系统权限,其实我们还可以通过其他方式来授权,比如可以通过角色组,用户名,生日等,但这些主要取决于ClaimTypes,其实我们也可以自定义键值来授权,这些统一叫策略授权,其中更强大的是,我们可以自定义授权Handler来达到灵活授权,下面一一展开。

注意:下面的代码只是部分代码,完整代码参照:https://github.com/axzxs2001/Asp.NetCoreExperiment/tree/master/Asp.NetCoreExperiment/%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/PolicyPrivilegeManagement

首先看基于角色组,或用户名,或基于ClaimType或自定义键值等授权策略,这些都是通过Services.AddAuthorization添加,并且是AuthorizationOptions来AddPolicy,这里策略的名称统一用RequireClaim来命名,不同的请求的策略名称各不相同,如用户名时就用policy.RequireUserName(),同时,在登录时,验证成功后,要添加相应的Claim到ClaimsIdentity中:

Startup.cs

 1 ????????public void ConfigureServices(IServiceCollection services) 2 ????????{ 3 ????????????services.AddMvc(); 4 ????????????services.AddAuthorization(options => 5 ????????????{ 6 //基于角色组的策略 7 ????????????????options.AddPolicy("RequireClaim", policy => policy.RequireRole("admin", "system")); 8 ????????????????//基于用户名 9 ????????????????//options.AddPolicy("RequireClaim", policy => policy.RequireUserName("桂素伟"));10 ????????????????//基于ClaimType11 ????????????????//options.AddPolicy("RequireClaim", policy => policy.RequireClaim(ClaimTypes.Country,"中国"));12 ????????????????//自定义值13 ????????????????// options.AddPolicy("RequireClaim", policy => policy.RequireClaim("date","2017-09-02")); ???????????????14 ????????????}).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>{15 ????????????????options.LoginPath = new PathString("/login");16 ????????????????options.AccessDeniedPath = new PathString("/denied");17 ????????????}); 18 ????????}

HomeController.cs

 1 using System; 2 using System.Collections.Generic; 3 using System.Diagnostics; 4 using System.Linq; 5 using System.Threading.Tasks; 6 using Microsoft.AspNetCore.Mvc; 7 using PolicyPrivilegeManagement.Models; 8 using Microsoft.AspNetCore.Authorization; 9 using Microsoft.AspNetCore.Authentication;10 using Microsoft.AspNetCore.Authentication.Cookies;11 using System.Security.Claims;12 13 namespace PolicyPrivilegeManagement.Controllers14 {15 ????[Authorize(Policy = "RequireClaim")]16 ????public class HomeController : Controller17 ????{ ??????18 ????????public IActionResult Index()19 ????????{20 ????????????return View();21 ????????}22 23 ????????public IActionResult About()24 ????????{25 ????????????ViewData["Message"] = "Your application description page.";26 ????????????return View();27 ????????}28 ????????29 ????????public IActionResult Contact()30 ????????{31 ????????????ViewData["Message"] = "Your contact page.";32 ????????????return View();33 ????????}34 35 ????????public IActionResult Error()36 ????????{37 ????????????return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });38 ????????}39 ????????[AllowAnonymous]40 ????????[HttpGet("login")]41 ????????public IActionResult Login(string returnUrl = null)42 ????????{43 ????????????TempData["returnUrl"] = returnUrl;44 ????????????return View();45 ????????}46 ????????[AllowAnonymous]47 ????????[HttpPost("login")]48 ????????public async Task<IActionResult> Login(string userName, string password, string returnUrl = null)49 ????????{50 ????????????var list = new List<dynamic> {51 ????????????????new { UserName = "gsw", Password = "111111", Role = "admin",Name="桂素伟",Country="中国",Date="2017-09-02",BirthDay="1979-06-22"},52 ????????????????new { UserName = "aaa", Password = "222222", Role = "system",Name="测试A" ,Country="美国",Date="2017-09-03",BirthDay="1999-06-22"}53 ????????????};54 ????????????var user = list.SingleOrDefault(s => s.UserName == userName && s.Password == password);55 ????????????if (user != null)56 ????????????{57 ????????????????//用户标识58 ????????????????var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);59 ????????????????identity.AddClaim(new Claim(ClaimTypes.Sid, userName));60 ????????????????identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));61 ????????????????identity.AddClaim(new Claim(ClaimTypes.Role, user.Role));62 ????????????????identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));63 ????????????????identity.AddClaim(new Claim("date", user.Date));64 65 ????????????????await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));66 ????????????????if (returnUrl == null)67 ????????????????{68 ????????????????????returnUrl = TempData["returnUrl"]?.ToString();69 ????????????????}70 ????????????????if (returnUrl != null)71 ????????????????{72 ????????????????????return Redirect(returnUrl);73 ????????????????}74 ????????????????else75 ????????????????{76 ????????????????????return RedirectToAction(nameof(HomeController.Index), "Home");77 ????????????????}78 ????????????}79 ????????????else80 ????????????{81 ????????????????const string badUserNameOrPasswordMessage = "用户名或密码错误!";82 ????????????????return BadRequest(badUserNameOrPasswordMessage);83 ????????????}84 ????????}85 ????????[HttpGet("logout")]86 ????????public async Task<IActionResult> Logout()87 ????????{88 ????????????await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);89 ????????????return RedirectToAction("Index", "Home");90 ????????}91 ????????[AllowAnonymous]92 ????????[HttpGet("denied")]93 ????????public IActionResult Denied()94 ????????{95 ????????????return View();96 ????????}97 ????}98 }

上面的授权策略都相对简单,单一,使用场景也很有限,就和固定角色授权如出一辙,其实可以用更好的来例用授权,那就是自定义授权Handler,我们在《asp.net core认证与授权》一文中,是通过中间件来达到自定义解色的,现在我们换个思路,通过自定义授权Handler来实现。

首先定义一个UserPermission,即用户权限实体类

 1 /// <summary> 2 ????/// 用户权限 3 ????/// </summary> 4 ????public class UserPermission 5 ????{ 6 ????????/// <summary> 7 ????????/// 用户名 8 ????????/// </summary> 9 ????????public string UserName10 ????????{ get; set; }11 ????????/// <summary>12 ????????/// 请求Url13 ????????/// </summary>14 ????????public string Url15 ????????{ get; set; }16 ????}

接下来定义一个PermissionRequirement,为请求条件实体类

 1 /// <summary> 2 ????/// 必要参数类 3 ????/// </summary> 4 ????public class PermissionRequirement : IAuthorizationRequirement 5 ????{ 6 ????????/// <summary> 7 ????????/// 用户权限集合 8 ????????/// </summary> 9 ????????public ?List<UserPermission> UserPermissions { get;private set; }10 ????????/// <summary>11 ????????/// 无权限action12 ????????/// </summary>13 ????????public string DeniedAction { get; set; }14 ????????/// <summary>15 ????????/// 构造16 ????????/// </summary>17 ????????/// <param name="deniedAction">无权限action</param>18 ????????/// <param name="userPermissions">用户权限集合</param>19 ????????public PermissionRequirement(string deniedAction, List<UserPermission> userPermissions)20 ????????{21 ????????????DeniedAction = deniedAction;22 ????????????UserPermissions = userPermissions;23 ????????}24 ????}

再定义自定义授权Hanlder,我们命名为PermissionHandler,此类必需继承AuthorizationHandler<T>,只用实现public virtual Task HandleAsync(AuthorizationHandlerContext context),些方法是用户请求时验证是否授权的主方法,所以实现与自定义角色中间件的Invoke很相似。

 1 using Microsoft.AspNetCore.Authorization; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Security.Claims; 5 using System.Threading.Tasks; 6 ?7 namespace PolicyPrivilegeManagement.Models 8 { 9 ????/// <summary>10 ????/// 权限授权Handler11 ????/// </summary>12 ????public class PermissionHandler : AuthorizationHandler<PermissionRequirement>13 ????{14 ????????/// <summary>15 ????????/// 用户权限16 ????????/// </summary>17 ????????public List<UserPermission> UserPermissions { get; set; }18 19 ????????protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)20 ????????{21 ????????????//赋值用户权限22 ????????????UserPermissions = requirement.UserPermissions;23 ????????????//从AuthorizationHandlerContext转成HttpContext,以便取出表求信息24 ????????????var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;25 ????????????//请求Url26 ????????????var questUrl = httpContext.Request.Path.Value.ToLower();27 ????????????//是否经过验证28 ????????????var isAuthenticated = httpContext.User.Identity.IsAuthenticated;29 ????????????if (isAuthenticated)30 ????????????{31 ????????????????if (UserPermissions.GroupBy(g => g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0)32 ????????????????{33 ????????????????????//用户名34 ????????????????????var userName = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Sid).Value;35 ????????????????????if (UserPermissions.Where(w => w.UserName == userName && w.Url.ToLower() == questUrl).Count() > 0)36 ????????????????????{37 ????????????????????????context.Succeed(requirement);38 ????????????????????}39 ????????????????????else40 ????????????????????{41 ????????????????????????//无权限跳转到拒绝页面42 ????????????????????????httpContext.Response.Redirect("/denied");43 ????????????????????}44 ????????????????}45 ????????????????else46 ????????????????{47 ????????????????????context.Succeed(requirement);48 ????????????????}49 ????????????}50 ????????????return Task.CompletedTask;51 ????????}52 ????}53 }

此次的Startup.cs的ConfigureServices发生了变化,如下

 1 ?????public void ConfigureServices(IServiceCollection services) 2 ????????{ 3 ????????????services.AddMvc(); 4 ????????????services.AddAuthorization(options => 5 ????????????{ ??6 ?????????????????//自定义Requirement,userPermission可从数据库中获得 7 ????????????????var userPermission= new List<UserPermission> { 8 ??????????????????????????????new UserPermission { ?Url="/", UserName="gsw"}, 9 ??????????????????????????????new UserPermission { ?Url="/home/permissionadd", UserName="gsw"},10 ??????????????????????????????new UserPermission { ?Url="/", UserName="aaa"},11 ??????????????????????????????new UserPermission { ?Url="/home/contact", UserName="aaa"}12 ??????????????????????????};13 14 ????????????????options.AddPolicy("Permission",15 ??????????????????????????policy => policy.Requirements.Add(new PermissionRequirement("/denied", userPermission)));16 17 ????????????}).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>{18 ????????????????options.LoginPath = new PathString("/login");19 ????????????????options.AccessDeniedPath = new PathString("/denied");20 21 ????????????});22 ????????????//注入授权Handler23 ????????????services.AddSingleton<IAuthorizationHandler, PermissionHandler>();24 ????????}

HomeController中代码如下:

 ?1 using System.Collections.Generic; ?2 using System.Diagnostics; ?3 using System.Linq; ?4 using System.Threading.Tasks; ?5 using Microsoft.AspNetCore.Mvc; ?6 using PolicyPrivilegeManagement.Models; ?7 using Microsoft.AspNetCore.Authorization; ?8 using Microsoft.AspNetCore.Authentication; ?9 using Microsoft.AspNetCore.Authentication.Cookies; 10 using System.Security.Claims; 11 ?12 namespace PolicyPrivilegeManagement.Controllers 13 { 14 ????[Authorize(Policy = "Permission")] ???15 ????public class HomeController : Controller 16 ????{ 17 ????????PermissionHandler _permissionHandler; 18 ????????public HomeController(IAuthorizationHandler permissionHandler) 19 ????????{ 20 ????????????_permissionHandler = permissionHandler as PermissionHandler; 21 ????????} 22 ????????public IActionResult Index() 23 ????????{ 24 ????????????return View(); 25 ????????} 26 ?27 ????????public IActionResult PermissionAdd() 28 ????????{ ???????????29 ????????????return View(); 30 ????????} 31 ?32 ????????[HttpPost("addpermission")] 33 ????????public IActionResult AddPermission(string url,string userName) 34 ????????{ ???????35 ????????????//添加权限 36 ????????????_permissionHandler.UserPermissions.Add(new UserPermission { Url = url, UserName = userName }); 37 ????????????return Content("添加成功"); 38 ????????} 39 ?????????40 ????????public IActionResult Contact() 41 ????????{ 42 ????????????ViewData["Message"] = "Your contact page."; 43 ?44 ????????????return View(); 45 ????????} 46 ?47 ????????public IActionResult Error() 48 ????????{ 49 ????????????return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); 50 ????????} 51 ????????[AllowAnonymous] 52 ????????[HttpGet("login")] 53 ????????public IActionResult Login(string returnUrl = null) 54 ????????{ 55 ????????????TempData["returnUrl"] = returnUrl; 56 ????????????return View(); 57 ????????} 58 ????????[AllowAnonymous] 59 ????????[HttpPost("login")] 60 ????????public async Task<IActionResult> Login(string userName, string password, string returnUrl = null) 61 ????????{ 62 ????????????var list = new List<dynamic> { 63 ????????????????new { UserName = "gsw", Password = "111111", Role = "admin",Name="桂素伟",Country="中国",Date="2017-09-02",BirthDay="1979-06-22"}, 64 ????????????????new { UserName = "aaa", Password = "222222", Role = "system",Name="测试A" ,Country="美国",Date="2017-09-03",BirthDay="1999-06-22"} 65 ????????????}; 66 ????????????var user = list.SingleOrDefault(s => s.UserName == userName && s.Password == password); 67 ????????????if (user != null) 68 ????????????{ 69 ????????????????//用户标识 70 ????????????????var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); 71 ????????????????identity.AddClaim(new Claim(ClaimTypes.Sid, userName)); 72 ????????????????identity.AddClaim(new Claim(ClaimTypes.Name, user.Name)); 73 ????????????????identity.AddClaim(new Claim(ClaimTypes.Role, user.Role)); 74 ????????????????identity.AddClaim(new Claim(ClaimTypes.Country, user.Country)); 75 ????????????????identity.AddClaim(new Claim("date", user.Date)); 76 ?77 ????????????????await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity)); 78 ????????????????if (returnUrl == null) 79 ????????????????{ 80 ????????????????????returnUrl = TempData["returnUrl"]?.ToString(); 81 ????????????????} 82 ????????????????if (returnUrl != null) 83 ????????????????{ 84 ????????????????????return Redirect(returnUrl); 85 ????????????????} 86 ????????????????else 87 ????????????????{ 88 ????????????????????return RedirectToAction(nameof(HomeController.Index), "Home"); 89 ????????????????} 90 ????????????} 91 ????????????else 92 ????????????{ 93 ????????????????const string badUserNameOrPasswordMessage = "用户名或密码错误!"; 94 ????????????????return BadRequest(badUserNameOrPasswordMessage); 95 ????????????} 96 ????????} 97 ????????[HttpGet("logout")] 98 ????????public async Task<IActionResult> Logout() 99 ????????{100 ????????????await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);101 ????????????return RedirectToAction("Index", "Home");102 ????????}103 ????????[AllowAnonymous]104 ????????[HttpGet("denied")]105 ????????public IActionResult Denied()106 ????????{107 ????????????return View();108 ????????}109 ????}110 }

本例设计是当用户gsw密码111111登录时,是不能访问/home/contact的,刚登录时访该action是不成功的,这里我们在/home/addpermission中添加一个Action名称:/home/contact,用户名:gsw的信息,此时再访问/home/contact,会发现是可以访问的,这是因为我们热更新了PermissionHandler中的用户权限集合,用户的权限得到了扩展和变化。

其实用中间件能达到灵活权限的设置,用自定义授权Handler也可以,接下来比较一下两种做法的优劣:

中间件

自定义授权Handler

用户权限集合

静态对象

实体化对象

热更新时

用中间件名称.用户权限集合更新

因为在Startup.cs中,PermissionHandler是依赖注放的,可以在热更新的构造中获取并操作

性能方面

每个action请求都会触发Invock方法,标记[AllowAnonymous]特性的Action也会触发

只有标记[Authorize]特性的Action会触发该方法,标记[AllowAnonymous]特性的Action不会触发,性能更优化

asp.net core策略授权

原文地址:http://www.cnblogs.com/axzxs2001/p/7482777.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved