ASP.NET Core中的授权(3) — 基于自定义策略
2022/2/28 1:22:40
本文主要是介绍ASP.NET Core中的授权(3) — 基于自定义策略,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
引用:https://www.jianshu.com/p/0bdf572cc103
程序认证身份之后就是授权,授权也有很多种
三种:基于角色,基于声明, 基于策略
此项目的demo的git地址:https://github.com/xeekseven/AspNet-core-Example/tree/master/ANC-Authorize-CustomRequirement
场景
如果有这样的一个需求,一个管理系统,里面有多重角色,每个角色有多种权限,而且角色的权限是动态可调整了,一个用户多种角色,角色也是可调整了,这样一个: 权限(n)—(1) 角色 (n)— (1)用户 这样的一个需求,应该怎么实现?其实 ,自定义策略模式即可满足
前言
为何不使用简单策略?简单策略模式无非就是逻辑运算符比基于声明多了些,但是比较鸡肋,不如......直接上自定义策略
基于自定义策略授权
复杂类型的授权,好处在于动态调整,当然就要自己写策略提供器,也就是根据不同的参数来生成不同的策略,然后还需要自己重新实现策略的handler
- 先定义一个权限策略PermissionRequirement,包含一些属性
public class PermissionRequirement : IAuthorizationRequirement { public string PermissionName { get; } public PermissionRequirement (string PermissionName) { this.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; var permissions = RolePermissionCache.GetPermissions(role.Value); if (permissions.Contains(requirement.PermissionName)) { context.Succeed(requirement); } } return Task.CompletedTask; } } //权限动态缓存类 临时替代数据库 public class RolePermissionCache { //实际在数据库获取与配置 public static List<string> GetPermissions(string role){ switch(role){ case "Administrator": return new List<string>(){ "Index","Privacy" }; case "Custom": return new List<string>(){ "Index" }; } return new List<string>(); } }
- 还需要一个动态 new 策略声明的类,用来保证每次不同的参数对应的是不同属性值的一种策略:
internal class PermissionPolicyProvider : IAuthorizationPolicyProvider { const string POLICY_PREFIX = "Permission"; public Task<AuthorizationPolicy> GetDefaultPolicyAsync() { return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); } public Task<AuthorizationPolicy> GetFallbackPolicyAsync() { return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); } public Task<AuthorizationPolicy> GetPolicyAsync(string policyName) { if(policyName.StartsWith(POLICY_PREFIX,System.StringComparison.OrdinalIgnoreCase)){ var policy = new AuthorizationPolicyBuilder(); policy.AddRequirements(new PermissionRequirement(policyName.Substring(POLICY_PREFIX.Length))); return Task.FromResult(policy.Build()); } return Task.FromResult<AuthorizationPolicy>(null); } }
- 最后需要一个特性来在控制器应用自定义的策略的特性:
internal class PermissionAuthorizeAttribute : AuthorizeAttribute { const string POLICY_PREFIX = "Permission"; public PermissionAuthorizeAttribute(string permissionName) => PermissionName = permissionName; public string PermissionName { get { return PermissionName; } set { Policy = $"{POLICY_PREFIX}{value.ToString()}"; } } }
- 现在就在startup启动类中进行配置:
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>(); services.AddSingleton<IAuthorizationHandler, PermissionRequirementHandler>(); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.AccessDeniedPath = new PathString("/Home/NotPermission"); options.LoginPath = new PathString("/Home/Login"); options.ExpireTimeSpan = TimeSpan.FromSeconds(10); }); services.AddControllersWithViews(); services.AddRazorPages(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseCookiePolicy(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapRazorPages(); }); }
- 终于,现在可以根据我们自己的需求来自定义每个控制器的策略了:
[PermissionAuthorize("Privacy")] public IActionResult Privacy() { return View(); }
- 当然还有登录的代码:
[HttpPost] [AllowAnonymous] public async Task<IActionResult> Login(string username,string password) { var returnUrl = HttpContext.Request.Query["ReturnUrl"]; string roleType = ""; if(username == "admin"){ roleType = "Administrator"; } else if(username == "custom"){ roleType = "Custom"; } if((username == "admin" && password == "admin") || (username == "custom" && password == "custom")){ var claims = new List<Claim> { new Claim(ClaimTypes.Name,username), new Claim("Role",roleType), new Claim(ClaimTypes.Role,roleType) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), new AuthenticationProperties()); if (!string.IsNullOrWhiteSpace(returnUrl)) { return Redirect(returnUrl); } return Redirect("/Home/Index"); } if (!string.IsNullOrWhiteSpace(returnUrl)) { return Redirect(returnUrl); } return Redirect("/Home/Login"); }
前一篇 —ASP.NET Core中的授权(2) — 基于声明: https://www.jianshu.com/p/f96c181c34d9
作者:谁有羊毛
链接:https://www.jianshu.com/p/0bdf572cc103
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这篇关于ASP.NET Core中的授权(3) — 基于自定义策略的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-12-06使用Microsoft.Extensions.AI在.NET中生成嵌入向量
- 2024-11-18微软研究:RAG系统的四个层次提升理解与回答能力
- 2024-11-15C#中怎么从PEM格式的证书中提取公钥?-icode9专业技术文章分享
- 2024-11-14云架构设计——如何用diagrams.net绘制专业的AWS架构图?
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#