asp.Netcoreポリシーライセンス
60997 ワード
「asp.net core認証と授権」では、固定とカスタムロール授権システムの権限について説明しています.実際には、ロールグループ、ユーザー名、誕生日など、他の方法で授権することもできますが、これらは主にClaimTypeに依存しています.実際には、カスタムキー値で授権することもできます.これらはポリシー授権と呼ばれています.その中で、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()は、ログイン時に認証に成功した後、適切なClaimsをClaimsIdentityに追加します.
Startup.cs
HomeController.cs
上記のライセンスポリシーは比較的簡単で、単一で、使用シーンも限られており、固定ロールのライセンスと同じように、実際にはより良い例でライセンスを使用することができます.それはカスタムライセンスHandlerです.私たちは「asp.net core認証とライセンス」という文で、ミドルウェアを通じてカスタム解色を達成しています.今、考え方を変えて、カスタムライセンスHandlerを通じて実現します.
まず、UserPermission(ユーザー権限エンティティクラス)を定義します.
HomeControllerのコードは次のとおりです.
本例の設計は、ユーザgswパスワード111111が登録されている場合、/home/contactにアクセスできないため、登録されたばかりのときにこのactionにアクセスすることは成功しない.ここでは、/home/addpermissionにAction名:/home/contact、ユーザ名:gswの情報を追加する.このとき、/home/contactにアクセスすると、アクセス可能であることがわかる.これは、PermissionHandlerにおけるユーザ権限の集合を熱的に更新したためである.ユーザーの権限が拡張され、変更されました.
実はミドルウェアを使って柔軟な権限の設定を達成することができて、カスタム授権Handlerを使ってもいいです.次に2つの方法の優劣を比較します.
ミドルウェア
カスタムライセンスHandler
ユーザー権限セット
静的オブジェクト
オブジェクトをソリッド化
ホットアップデート時
ミドルウェア名でユーザー権限セットの更新
スタートアップだからcsではPermissionHandlerは注放に依存しており,熱的に更新された構造で取得して操作できる.
パフォーマンス
各アクションリクエストはInvockメソッドをトリガーし、[AllowAnonymous]プロパティをマークしたActionもトリガーします.
このメソッドは[Authorize]プロパティのアクションのみがトリガーされ、[AllowAnonymous]プロパティのアクションはトリガーされず、パフォーマンスが最適化されます.
最後に、ライセンスポリシーをNuGetのパッケージにしました.asp.Netcore 2.0のプロジェクトでAuthorizePolicyがこのパッケージを参照すると、パッケージに対応するgithubアドレスが表示されます.https://github.com/axzxs2001/AuthorizePolicyこの授権戦略を共同で改善するための提案を歓迎します.
注:次のコードは一部のコードにすぎません.完全なコード参照: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()は、ログイン時に認証に成功した後、適切なClaimsを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 // ClaimType
11 //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.Controllers
14 {
15 [Authorize(Policy = "RequireClaim")]
16 public class HomeController : Controller
17 {
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 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 else
75 {
76 return RedirectToAction(nameof(HomeController.Index), "Home");
77 }
78 }
79 else
80 {
81 const string badUserNameOrPasswordMessage = " !";
82 return BadRequest(badUserNameOrPasswordMessage);
83 }
84 }
85 [HttpGet("logout")]
86 public async Task 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 ///
2 /// 3 /// 4 public class UserPermission 5 { 6 ///
7 /// 8 /// 9 public string UserName 10 { get; set; } 11 ///
12 /// Url 13 /// 14 public string Url 15 { get; set; } 16 }
接下来定义一个PermissionRequirement,为请求条件实体类
1 ///
2 /// 3 /// 4 public class PermissionRequirement : IAuthorizationRequirement 5 { 6 ///
7 /// 8 /// 9 public List
UserPermissions { get;private set; } 10 /// 11 /// action 12 /// 13 public string DeniedAction { get; set; } 14 ///
15 /// 16 /// 17 /// action 18 /// 19 public PermissionRequirement(string deniedAction, List
userPermissions) 20 { 21 DeniedAction = deniedAction; 22 UserPermissions = userPermissions; 23 } 24 }
再定义自定义授权Hanlder,我们命名为PermissionHandler,此类必需继承AuthorizationHandler
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 ///
10 /// Handler 11 /// 12 public class PermissionHandler : AuthorizationHandler
13 { 14 /// 15 /// 16 /// 17 public List
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 // Url 26 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 else 40 { 41 // 42 httpContext.Response.Redirect(requirement.DeniedAction );
43 }
44 }
45 else
46 {
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 {
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 // Handler
23 services.AddSingleton();
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 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 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を使ってもいいです.次に2つの方法の優劣を比較します.
ミドルウェア
カスタムライセンスHandler
ユーザー権限セット
静的オブジェクト
オブジェクトをソリッド化
ホットアップデート時
ミドルウェア名でユーザー権限セットの更新
スタートアップだからcsではPermissionHandlerは注放に依存しており,熱的に更新された構造で取得して操作できる.
パフォーマンス
各アクションリクエストはInvockメソッドをトリガーし、[AllowAnonymous]プロパティをマークしたActionもトリガーします.
このメソッドは[Authorize]プロパティのアクションのみがトリガーされ、[AllowAnonymous]プロパティのアクションはトリガーされず、パフォーマンスが最適化されます.
最後に、ライセンスポリシーをNuGetのパッケージにしました.asp.Netcore 2.0のプロジェクトでAuthorizePolicyがこのパッケージを参照すると、パッケージに対応するgithubアドレスが表示されます.https://github.com/axzxs2001/AuthorizePolicyこの授権戦略を共同で改善するための提案を歓迎します.