{"id":1075,"date":"2025-05-21T20:28:54","date_gmt":"2025-05-21T12:28:54","guid":{"rendered":"https:\/\/www.hyy.net\/?p=1075"},"modified":"2025-05-21T20:28:54","modified_gmt":"2025-05-21T12:28:54","slug":"asp-net-core-razor-pages-in-action-10-%e9%80%9a%e8%bf%87%e6%8e%88%e6%9d%83%e6%8e%a7%e5%88%b6%e8%ae%bf%e9%97%ae","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=1075","title":{"rendered":"ASP.NET Core Razor Pages in Action 10 \u901a\u8fc7\u6388\u6743\u63a7\u5236\u8bbf\u95ee"},"content":{"rendered":"<p>ASP.NET Core Razor Pages in Action 10 \u901a\u8fc7\u6388\u6743\u63a7\u5236\u8bbf\u95ee<\/p>\n<h2>\u672c\u7ae0\u6db5\u76d6<\/h2>\n<p>\u2022  \u5728 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u4e2d\u542f\u7528\u6388\u6743\u670d\u52a1<br \/>\n\u2022  \u4f7f\u7528\u89d2\u8272\u548c\u58f0\u660e\u6388\u6743\u7ec8\u7aef\u8282\u70b9<br \/>\n\u2022  \u6839\u636e\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u521b\u5efa\u6388\u6743\u7b56\u7565<br \/>\n\u2022  \u6388\u6743\u8bbf\u95ee\u8d44\u6e90<\/p>\n<p>\u5728\u4e0a\u4e00\u7ae0\u4e2d\uff0c\u60a8\u5b66\u4e60\u4e86\u5982\u4f55\u901a\u8fc7\u8981\u6c42\u7528\u6237\u5bf9\u81ea\u5df1\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u6765\u8bc6\u522b\u7528\u6237\u3002\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u540e\uff0c\u7528\u6237\u4e0d\u518d\u662f\u533f\u540d\u7684;\u4ed6\u4eec\u6709\u4e00\u4e2a\u8eab\u4efd\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u9650\u5236\u5bf9\u5e94\u7528\u7a0b\u5e8f\u5404\u4e2a\u90e8\u5206\u7684\u8bbf\u95ee\u3002\u6b64\u8fc7\u7a0b\u79f0\u4e3a\u6388\u6743\uff0c\u5bf9\u4e8e\u4fdd\u62a4\u5e94\u7528\u7a0b\u5e8f\u7684\u67d0\u4e9b\u90e8\u5206\u514d\u53d7\u4e0d\u5e94\u8bbf\u95ee\u7684\u7528\u6237\u7684\u653b\u51fb\u81f3\u5173\u91cd\u8981\u3002<\/p>\n<p>\u5373\u4f7f\u662f\u6700\u7b80\u5355\u7684\u52a8\u6001 Web \u5e94\u7528\u7a0b\u5e8f\u4e5f\u53ef\u80fd\u5305\u62ec\u4e00\u4e2a\u6240\u6709\u8005\u7ef4\u62a4\u5185\u5bb9\u7684\u533a\u57df\uff0c\u5373\u7ba1\u7406\u533a\u57df\u3002\u8fd9\u5c06\u9700\u8981\u9632\u6b62\u672a\u7ecf\u6388\u6743\u7684\u8bbf\u95ee\uff0c\u9664\u975e\u60a8\u5e0c\u671b\u968f\u673a\u7528\u6237\u5f00\u59cb\u53d1\u5e03\u4ed6\u4eec\u81ea\u5df1\u7684\u5185\u5bb9\uff0c\u6216\u8005\u66f4\u7cdf\u7684\u662f\uff1a\u6c61\u635f\u6216\u5220\u9664\u60a8\u73b0\u6709\u7684\u5185\u5bb9\u3002\u66f4\u590d\u6742\u7684\u5e94\u7528\u7a0b\u5e8f\u53ef\u80fd\u9700\u8981\u590d\u6742\u7684\u8bbf\u95ee\u7b56\u7565\uff0c\u5176\u4e2d\u4e0d\u540c\u7684\u7528\u6237\u5bf9\u5e94\u7528\u7a0b\u5e8f\u7684\u67d0\u4e9b\u90e8\u5206\u5177\u6709\u4e0d\u540c\u7ea7\u522b\u7684\u6743\u9650\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u5141\u8bb8\u9009\u5b9a\u6570\u91cf\u7684\u7528\u6237\u6dfb\u52a0\u5230\u60a8\u7684\u7f51\u7ad9\u63d0\u4f9b\u7684\u5ea6\u5047\u5730\u70b9\u8303\u56f4\uff0c\u4f46\u8fdb\u4e00\u6b65\u9650\u5236\u8c01\u53ef\u4ee5\u7ba1\u7406\u4ef7\u683c\u3002\u5ba2\u6237\u5c06\u80fd\u591f\u9884\u8ba2\u5047\u671f\u5e76\u67e5\u770b\u4ed6\u4eec\u81ea\u5df1\u7684\u8ba2\u5355\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f46\u53ea\u6709\u7ba1\u7406\u5458\u624d\u80fd\u67e5\u770b\u6240\u6709\u8ba2\u5355\u7684\u8be6\u7ec6\u4fe1\u606f\u3002\u8d85\u7ea7\u7528\u6237\u53ef\u80fd\u662f\u552f\u4e00\u53ef\u4ee5\u66f4\u6539\u8ba2\u5355\u90e8\u5206\u5185\u5bb9\u7684\u7528\u6237\u3002<\/p>\n<p>\u5728\u6700\u7b80\u5355\u7684\u7ea7\u522b\u4e0a\uff0c\u60a8\u53ef\u4ee5\u4fdd\u62a4\u5e94\u7528\u7a0b\u5e8f\u7684\u67d0\u4e9b\u90e8\u5206\uff0c\u4ee5\u4fbf\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u8bbf\u95ee\u5b83\u4eec\u3002\u60a8\u5c06\u9996\u5148\u5b66\u4e60\u5982\u4f55\u5bf9\u5355\u4e2a\u9875\u9762\u6216\u7ec8\u7aef\u8282\u70b9\u6267\u884c\u6b64\u4f5c\u3002\u60a8\u8fd8\u5c06\u4e86\u89e3\u5982\u4f55\u4fdd\u62a4\u7279\u5b9a\u6587\u4ef6\u5939\u6216\u6574\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6240\u6709\u9875\u9762\u3002\u7136\u540e\uff0c\u60a8\u5c06\u63a2\u7d22 ASP.NET Core Identity \u63d0\u4f9b\u7684\u4e00\u4e9b\u529f\u80fd\uff0c\u7528\u4e8e\u66f4\u7cbe\u7ec6\u5730\u7ba1\u7406\u6388\u6743\u3002\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u6839\u636e\u7528\u6237\u7684\u89d2\u8272\u5c06\u7528\u6237\u5206\u7ec4\u5728\u4e00\u8d77\uff0c\u5e76\u5728\u6b64\u57fa\u7840\u4e0a\u7ba1\u7406\u5bf9\u7ec8\u7aef\u8282\u70b9\u7684\u8bbf\u95ee\u3002\u7136\u540e\uff0c\u60a8\u5c06\u66f4\u8be6\u7ec6\u5730\u63a2\u8ba8\u4e0a\u4e00\u7ae0\u4e2d\u4ecb\u7ecd\u7684\u58f0\u660e\u6982\u5ff5\uff0c\u5e76\u786e\u5b9a\u5982\u4f55\u57fa\u4e8e\u58f0\u660e\u5236\u5b9a\u6388\u6743\u7b56\u7565\u5e76\u5e94\u7528\u5b83\u4eec\u6765\u7ba1\u7406\u5bf9\u7ec8\u7aef\u8282\u70b9\u7684\u8bbf\u95ee\u3002\u963b\u6b62\u8bbf\u95ee\u7ec8\u7aef\u8282\u70b9\u79f0\u4e3a\u57fa\u4e8e\u8bf7\u6c42\u7684\u6388\u6743\u3002\u5728\u5b66\u4e60\u5982\u4f55\u521b\u5efa\u7b56\u7565\u65f6\uff0c\u60a8\u5c06\u4e86\u89e3\u5b83\u4eec\u5982\u4f55\u57fa\u4e8e\u8981\u6c42\u53ca\u5176\u5904\u7406\u7a0b\u5e8f\u3002\u60a8\u5c06\u7f16\u5199\u81ea\u5df1\u7684\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\uff0c\u5e76\u4f7f\u7528\u5b83\u4eec\u6765\u5236\u5b9a\u4e00\u4e9b\u7b56\u7565\u3002<\/p>\n<p>\u6700\u540e\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5728\u9875\u9762\u4e2d\u5b9e\u73b0 fine-grained \u6388\u6743\u3002\u4f8b\u5982\uff0c\u8bb8\u591a\u7528\u6237\u53ef\u80fd\u6709\u6743\u8bbf\u95ee\u5217\u51fa\u8981\u51fa\u79df\u7684\u623f\u4ea7\u7684\u9875\u9762\uff0c\u4f46\u53ea\u6709\u9009\u5b9a\u7684\u7528\u6237\u624d\u6709\u6743\u7f16\u8f91\u8fd9\u4e9b\u623f\u4ea7\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u4e0d\u5e0c\u671b\u5411\u6ca1\u6709\u8db3\u591f\u6743\u9650\u7684\u7528\u6237\u663e\u793a Edit \u5bfc\u822a\u3002\u5728\u6b64\u7c7b\u9875\u9762\u4e2d\u5e94\u7528\u6388\u6743\u7b56\u7565\u79f0\u4e3a\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u3002<\/p>\n<p>\u6211\u4e00\u76f4\u8ba4\u4e3a\u6388\u6743\u4e0e\u4f9d\u8d56\u9879\u6ce8\u5165\u6709\u4e00\u4e9b\u5171\u540c\u70b9\u3002\u8fd9\u4e24\u4e2a\u4e3b\u9898\u5b9e\u9645\u4e0a\u90fd\u662f\u76f8\u5bf9\u5bb9\u6613\u7406\u89e3\u7684\u8bdd\u9898\uff0c\u4f46\u90fd\u7b3c\u7f69\u5728\u62bd\u8c61\u6982\u5ff5\u7684\u8ff7\u96fe\u4e2d\u3002\u6b63\u5982\u6211\u5e0c\u671b\u5728\u6709\u5173\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165\u7684\u7ae0\u8282\u4e2d\u6d88\u9664\u8ff7\u96fe\u4e00\u6837\uff0c\u6211\u5c06\u9996\u5148\u89e3\u91ca\u60a8\u5c06\u4f7f\u7528\u7684\u6709\u5173\u6388\u6743\u7684\u4e00\u4e9b\u6982\u5ff5\u3002<\/p>\n<h2>10.1 Razor Pages \u4e2d\u7684\u57fa\u672c\u6388\u6743<\/h2>\n<p>Razor Pages \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6388\u6743\u7531\u8bb8\u591a\u670d\u52a1\u63d0\u4f9b\uff0c\u5305\u62ec IAuthorizationService\u3002\u8fd9\u4e9b\u5fc5\u987b\u5728\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\u65f6\u6dfb\u52a0\u5230\u670d\u52a1\u5bb9\u5668\u4e2d\u3002\u4e00\u79cd\u4fbf\u6377\u7684\u65b9\u6cd5 AddAuthorization \u8d1f\u8d23\u6dfb\u52a0\u6240\u6709\u5fc5\u9700\u7684\u670d\u52a1\uff1a<\/p>\n<pre><code>builder.Services.AddAuthorization();<\/code><\/pre>\n<p>\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u5728 Web \u5e94\u7528\u7a0b\u5e8f\u6a21\u677f\u4e2d\u901a\u8fc7\u5305\u542b app \u6765\u542f\u7528\u3002UseAuthorization\uff08\uff09 \u5728 Program \u7c7b\u4e2d\u3002<\/p>\n<p>\u6388\u6743\u53d6\u51b3\u4e8e\u77e5\u9053\u7528\u6237\u662f\u8c01\u4ee5\u53ca\u4ed6\u4eec\u8bd5\u56fe\u505a\u4ec0\u4e48\uff0c\u4ee5\u53ca\u5728\u57fa\u4e8e\u8bf7\u6c42\u7684\u6388\u6743\u7684\u60c5\u51b5\u4e0b\uff0c\u4ed6\u4eec\u8bd5\u56fe\u8bbf\u95ee\u54ea\u4e2a\u9875\u9762\u3002\u5982\u7b2c 4 \u7ae0\u6240\u8ff0\uff0c\u7531 UseRouting \u6dfb\u52a0\u5230\u7ba1\u9053\u4e2d\u7684 EndpointRouting \u4e2d\u95f4\u4ef6\u8d1f\u8d23\u786e\u5b9a\u7528\u6237\u5c1d\u8bd5\u8bbf\u95ee\u7684\u9875\u9762\u3002\u5728\u4e0a\u4e00\u7ae0\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\uff08\u4f7f\u7528 UseAuthentication \u6dfb\u52a0\uff09\u8d1f\u8d23\u786e\u5b9a\u7528\u6237\u662f\u8c01\u3002\u6700\u540e\uff0cMapRazorPages \u662f\u6267\u884c\u6240\u9009\u9875\u9762\u7684\u4f4d\u7f6e\u3002\u6b64\u4e2d\u95f4\u4ef6\u6d41\u7a0b\u5982\u56fe 10.1 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1001.png\" ><\/p>\n<p>\u56fe 10.1 \u4e2d\u95f4\u4ef6\u6388\u6743\u987a\u5e8f\u53d6\u51b3\u4e8e\u77e5\u9053\u7528\u6237\u662f\u8c01\u4ee5\u53ca\u4ed6\u4eec\u5c1d\u8bd5\u53bb\u54ea\u91cc\u3002\u5982\u679c\u7528\u6237\u672a\u6388\u6743\uff0c\u5219\u7ba1\u9053\u77ed\u8def\u3002\u5426\u5219\uff0c\u8bf7\u6c42\u5c06\u6d41\u5411\u7ec8\u7aef\u8282\u70b9\u4e2d\u95f4\u4ef6\uff0c\u5e76\u6267\u884c\u9875\u9762\u3002<\/p>\n<p>\u9274\u4e8e\u60a8\u4e0d\u60f3\u6267\u884c\u5f53\u524d\u7528\u6237\u65e0\u6743\u8bbf\u95ee\u7684\u9875\u9762\uff0c\u56e0\u6b64\u7ba1\u9053\u4e2d\u653e\u7f6e UseAuthorization \u7684\u552f\u4e00\u903b\u8f91\u4f4d\u7f6e\u662f\u5728 UseRouting \u548c UseAuthentication \u4e4b\u540e\u4ee5\u53ca MapRazorPages \u4e4b\u524d\u3002\u56e0\u6b64\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u5fc5\u987b\u653e\u5728\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4e4b\u540e\u548c\u8c03\u7528 MapRazorPages \u4e4b\u524d\uff08\u6e05\u5355 10.1\uff09\u3002<\/p>\n<p>\u6e05\u5355 10.1 app \u7684\u4f4d\u7f6e\u3002UseAuthorization \u81f3\u5173\u91cd\u8981<\/p>\n<pre><code>app.UseRouting();           \u2776\napp.UseAuthentication();    \u2776\napp.UseAuthorization();    \napp.MapRazorPages();        \u2777<\/code><\/pre>\n<p>\u2776 \u8def\u7531\u548c\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u5fc5\u987b\u653e\u5728\u6388\u6743\u4e2d\u95f4\u4ef6\u4e4b\u524d\u3002<br \/>\n\u2777 \u7aef\u70b9\u4e2d\u95f4\u4ef6\u5fc5\u987b\u653e\u5728\u6388\u6743\u4e2d\u95f4\u4ef6\u4e4b\u540e\u3002<\/p>\n<h3>10.1.1 \u5e94\u7528\u7b80\u5355\u6388\u6743<\/h3>\n<p>\u60a8\u5c06\u4f7f\u7528 AuthorizeAttribute \u5c06\u6388\u6743\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\u3002\u8be5\u5c5e\u6027\u5177\u6709\u4e00\u4e9b\u5c5e\u6027\uff0c\u5176\u4e2d\u5305\u62ec Roles \u548c Policy\uff0c\u5728\u5b8c\u6210\u672c\u7ae0\u65f6\uff0c\u60a8\u5c06\u66f4\u8be6\u7ec6\u5730\u4e86\u89e3\u8fd9\u4e9b\u5c5e\u6027\u3002\u5728\u6700\u57fa\u672c\u7684\u60c5\u51b5\u4e0b\uff0c\u5f53\u60a8\u5c06\u5c5e\u6027\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\u65f6\uff0c\u5b83\u4f1a\u963b\u6b62\u533f\u540d\u7528\u6237\u8bbf\u95ee\u8be5\u7ec8\u7aef\u8282\u70b9\u3002\u7528\u6237\u5fc5\u987b\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u624d\u80fd\u83b7\u5f97\u7ee7\u7eed\u7684\u6388\u6743\u3002<\/p>\n<p>\u6709\u591a\u79cd\u65b9\u6cd5\u53ef\u4ee5\u5c06\u5c5e\u6027\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\u3002\u5c06\u5176\u6dfb\u52a0\u5230 PageModel \u7c7b\u7684\u6700\u7b80\u5355\u65b9\u6cd5\u3002<\/p>\n<p>\u6ce8\u610f\u719f\u6089 MVC \u6846\u67b6\u7684\u8bfb\u8005\u53ef\u80fd\u4e60\u60ef\u4e8e\u5c06 Authorize \u5c5e\u6027\u5206\u914d\u7ed9\u63a7\u5236\u5668\u4e2d\u7684\u4f5c\u65b9\u6cd5\u3002\u867d\u7136 PageModel \u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u7c7b\u4f3c\u4e8e\u63a7\u5236\u5668\u4f5c\u65b9\u6cd5\uff0c\u4f46 Razor Pages \u4e0d\u652f\u6301\u5c06 Authorize \u5c5e\u6027\u5206\u914d\u7ed9\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u3002\u5982\u679c\u60a8\u8003\u8651\u4e00\u4e0b\uff0c\u8fd9\u662f\u6709\u9053\u7406\u7684\uff0c\u56e0\u4e3a\u60a8\u6b63\u5728\u6388\u6743\u7ec8\u7aef\u8282\u70b9\uff0c\u800c\u4e0d\u7ba1\u7528\u4e8e\u8bbf\u95ee\u5b83\u7684 HTTP \u65b9\u6cd5\u5982\u4f55\u3002Razor \u9875\u9762\u8868\u793a\u5355\u4e2a\u7ec8\u7ed3\u70b9\uff0c\u800c MVC \u63a7\u5236\u5668\u901a\u5e38\u8d1f\u8d23\u5904\u7406\u591a\u4e2a\u7ec8\u7ed3\u70b9\u3002<\/p>\n<p>\u76ee\u524d\uff0c\u5982\u679c\u901a\u8fc7 GET \u8bf7\u6c42\u8bbf\u95ee\u8be5\u9875\u9762\uff0c\u5219 Index \u9875\u9762\u4f1a\u5411\u533f\u540d\u7528\u6237\u8fd4\u56de ChallengeResult\u3002\u60a8\u5c06\u66f4\u6539\u6b64\u8bbe\u7f6e\uff0c\u4ee5\u4fbf\u533f\u540d\u7528\u6237\u65e0\u6cd5\u901a\u8fc7\u4f7f\u7528 Authorize \u5c5e\u6027\u4fdd\u62a4\u9875\u9762\u6765\u8bbf\u95ee\u8be5\u9875\u9762\u3002\u5bf9 Pages\\Index.cshtml.cs \u4e2d\u4ee3\u7801\u7684\u66f4\u6539\u5c06\u663e\u793a\u5728\u4e0b\u4e00\u4e2a\u6e05\u5355\u4e2d\u3002<\/p>\n<p>\u6e05\u5355 10.2 \u5c06 Authorize \u5c5e\u6027\u5e94\u7528\u4e8e home PageModel<\/p>\n<pre><code>using CityBreaks.Models;\nusing CityBreaks.Services;\nusing Microsoft.AspNetCore.Authorization;                \u2776\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace CityBreaks.Pages\n{\n    [Authorize]                                          \u2777\n    public class IndexModel : PageModel\n    {\n        private readonly ICityService _cityService;\n\n        public IndexModel(ICityService cityService) =&gt;\n            _cityService = cityService;\n\n        public List&lt;City&gt; Cities { get; set; }\n        public async Task OnGetAsync() =&gt; \n            Cities = await _cityService.GetAllAsync();   \u2778\n    }\n}<\/code><\/pre>\n<p>\u2776 \u6dfb\u52a0 using \u4ee5\u5f15\u5165\u6388\u6743 API\u3002<br \/>\n\u2777 \u5c06 Authorize \u5c5e\u6027\u6dfb\u52a0\u5230 PageModel \u7c7b\u4e2d\u3002<br \/>\n\u2778 \u5220\u9664\u68c0\u67e5\u4ee5\u67e5\u770b\u7528\u6237\u662f\u5426\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u60a8\u5c06\u88ab\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\uff0c\u5c31\u50cf\u4ee5\u524d\u4e00\u6837\u3002\u6388\u6743\u670d\u52a1\u80fd\u591f\u8bbf\u95ee\u6240\u8bf7\u6c42\u9875\u9762\u7684\u7ec8\u7aef\u8282\u70b9\u5143\u6570\u636e\uff0c\u5e76\u786e\u5b9a\u5b83\u9700\u8981\u6388\u6743\u7528\u6237\u3002\u5b83\u8fd8\u80fd\u591f\u786e\u5b9a\u5f53\u524d\u7528\u6237\u672a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u56e0\u6b64\u670d\u52a1\u672c\u8eab\u8fd4\u56de ChallengeResult\uff08401 \u72b6\u6001\u4ee3\u7801\uff09\uff0c\u4ece\u800c\u5bfc\u81f4\u7528\u6237\u88ab\u5b9a\u5411\u767b\u5f55\u3002ChallengeResult \u662f\u4e09\u79cd\u53ef\u80fd\u7684\u7ed3\u679c\u4e4b\u4e00\u3002\u5982\u679c\u7528\u6237\u5df2\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4f46\u4e0d\u7b26\u5408\u6307\u5b9a\u7684\u6388\u6743\u7b56\u7565\u8981\u6c42\uff0c\u5219\u6388\u6743\u670d\u52a1\u5c06\u8fd4\u56de ForbidResult\uff08403 \u72b6\u6001\u4ee3\u7801\uff09\u3002\u5982\u679c\u7528\u6237\u83b7\u5f97\u6388\u6743\uff0c\u4e2d\u95f4\u4ef6\u4f1a\u5c06\u8bf7\u6c42\u4f20\u9012\u7ed9\u7ba1\u9053\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4e2d\u95f4\u4ef6\uff08\u56fe 10.2\uff09\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1002.png\" ><\/p>\n<p>\u56fe 10.2 \u6388\u6743\u4e2d\u95f4\u4ef6\u4e2d\u7684\u51b3\u7b56\u6709\u4e09\u79cd\u53ef\u80fd\u7684\u7ed3\u679c\u4e4b\u4e00\uff1a401 Challenge\u3001403 Forbidden \u6216\u5c06\u8bf7\u6c42\u4f20\u9012\u7ed9\u7ba1\u9053\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4e2d\u95f4\u4ef6\u3002<\/p>\n<p>\u5728 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c401 \u54cd\u5e94\u5305\u62ec\u5411\u6d4f\u89c8\u5668\u53d1\u9001\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u7684\u6307\u4ee4\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u8be5\u9875\u9762\u914d\u7f6e\u4e3a\u4f4d\u4e8e \/identity\/ account\/login\u3002\u5982\u679c\u60a8\u4e0d\u4f7f\u7528 Identity\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 LoginPath cookie \u9009\u9879\u5bf9\u5176\u8fdb\u884c\u81ea\u5b9a\u4e49\uff0c\u5982\u4e0a\u4e00\u7ae0\u6240\u793a\uff1a<\/p>\n<pre><code>builder.Services.AddAuthentication(CookieAuthenticationDefaults\n\u27a5 .AuthenticationScheme)\n    .AddCookie(options =&gt;\n{\n    options.LoginPath = &quot;\/Login&quot;;\n});<\/code><\/pre>\n<p>\u5f53\u60a8\u4f7f\u7528 Identity \u65f6\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u5e94\u7528\u7a0b\u5e8f Cookie \u914d\u7f6e\u81ea\u5b9a\u4e49\u767b\u5f55\u8def\u5f84\u3002\u6b64\u81ea\u5b9a\u4e49\u5e94\u5728\u5c06 Identity \u670d\u52a1\u6dfb\u52a0\u5230\u5bb9\u5668\u540e\u8fdb\u884c\uff1a<\/p>\n<pre><code>builder.Services.ConfigureApplicationCookie(options =&gt;\n{\n    options.LoginPath = &quot;\/Login&quot;;\n});<\/code><\/pre>\n<p>403 \u54cd\u5e94\u5305\u62ec\u91cd\u5b9a\u5411\u5230\u7531 AccessDeniedPath \u9009\u9879\u6307\u5b9a\u7684\u9875\u9762\u3002\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f Identity UI\uff0c\u5219\u91cd\u5b9a\u5411\u4f4d\u7f6e\u4e3a \/identity\/account\/accessdenied\u3002\u7531\u4e8e KebabPageRouteParameterTransformer \u7684\u6548\u679c\uff0c\u60a8\u9700\u8981\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u8def\u5f84\uff0c\u5b83\u5728 access \u548c denied \u4e4b\u95f4\u63d2\u5165\u4e00\u4e2a\u8fde\u5b57\u7b26\u3002\u5c06\u4ee3\u7801\u653e\u5728 AddDefaultIdentity \u540e\u9762\u7684 Program.cs \u4e2d\u7684\u4e0b\u4e00\u4e2a\u5217\u8868\u4e2d\u3002<\/p>\n<p>\u6e05\u5355 10.3 \u81ea\u5b9a\u4e49 AccessDenied \u8def\u5f84<\/p>\n<pre><code>builder.Services.ConfigureApplicationCookie(options =&gt;\n{\n    options.AccessDeniedPath = &quot;\/identity\/account\/access-denied&quot;;\n});<\/code><\/pre>\n<p>\u901a\u8fc7\u4f7f\u7528\u5c5e\u6027\u88c5\u9970 PageModel \u6765\u6388\u6743\u7aef\u70b9\u7684\u58f0\u660e\u6027\u65b9\u6cd5\u65e2\u5feb\u901f\u53c8\u7b80\u5355\uff0c\u4f46\u5982\u679c\u60a8\u6709\u8bb8\u591a\u9875\u9762\u8981\u9632\u6b62\u533f\u540d\u7528\u6237\uff0c\u5219\u68c0\u67e5\u662f\u5426\u5df2\u5c06\u5c5e\u6027\u5e94\u7528\u4e8e\u76f8\u5173 PageModel\u7684\u552f\u4e00\u65b9\u6cd5\u662f\u5355\u72ec\u67e5\u770b\u6bcf\u4e2a\u6587\u4ef6\u3002\u5982\u679c\u8981\u4fdd\u62a4\u6574\u4e2a\u6587\u4ef6\u5939\u7684\u5185\u5bb9\uff0c\u5219\u5fc5\u987b\u8bb0\u4f4f\u5c06\u5c5e\u6027\u6dfb\u52a0\u5230\u6587\u4ef6\u5939\u4e2d\u7684\u6bcf\u4e2a\u9875\u9762\uff0c\u5305\u62ec\u5728\u5c06\u6765\u67d0\u4e2a\u9636\u6bb5\u6dfb\u52a0\u7684\u65b0\u9875\u9762\u3002\u7f13\u89e3\u6b64\u95ee\u9898\u7684\u4e00\u79cd\u65b9\u6cd5\u662f\u58f0\u660e\u4e00\u4e2a\u6d3e\u751f\u81ea PageModel \u7684\u7c7b\uff0c\u5e76\u5c06 Authorize \u5c5e\u6027\u5e94\u7528\u4e8e\u8be5\u7c7b\uff0c\u7136\u540e\u83b7\u53d6\u6587\u4ef6\u5939\u4e2d\u8981\u4ece\u8be5\u7c7b\u7ee7\u627f\u7684\u6240\u6709\u9875\u9762\u3002\u4e0b\u9762\u8bf4\u660e\u4e86\u5982\u4f55\u4f7f\u7528\u540d\u4e3a AdminPageModel \u7684\u7c7b\u6765\u5b9e\u73b0\u6b64\u76ee\u7684\u3002<\/p>\n<p>\u6e05\u5355 10.4 \u4f7f\u7528 BasePage \u9650\u5236\u5bf9\u884d\u751f\u4ea7\u54c1\u7684\u8bbf\u95ee<\/p>\n<pre><code>using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace CityBreaks.Pages\n{\n    [Authorize]\n    public class AdminPageModel : PageModel\n    {\n    }\n}<\/code><\/pre>\n<p>\u5f53\u60a8\u521b\u5efa\u9700\u8981\u4fdd\u62a4\u7684\u9875\u9762\u65f6\uff0c\u53ea\u9700\u66f4\u6539\u5b83\u7ee7\u627f\u7684\u7c7b\u578b\uff0c\u4f7f\u5176\u6d3e\u751f\u81ea AdminPageModel \u5e76\u81ea\u52a8\u53d7\u5230 Authorize \u5c5e\u6027\u7684\u4fdd\u62a4\uff1a<\/p>\n<pre><code>public class CreateModel : AdminPageModel<\/code><\/pre>\n<p>\u8fd9\u79cd\u57fa\u9875\u65b9\u6cd5\u975e\u5e38\u5e38\u89c1\uff0c\u5c24\u5176\u662f\u5728\u65e7\u7248\u672c\u7684 .NET \u4e2d\uff0c\u4f46\u5b83\u4ecd\u7136\u5b58\u5728\u4e00\u4e2a\u95ee\u9898\uff0c\u5373\u60a8\u9700\u8981\u8bb0\u4f4f\u66f4\u6539\u751f\u6210\u7684\u4ee3\u7801\uff0c\u4ee5\u786e\u4fdd Razor \u9875\u9762\u6d3e\u751f\u81ea\u81ea\u5b9a\u4e49\u7c7b\u578b\u800c\u4e0d\u662f PageModel\u3002\u60a8\u59cb\u7ec8\u53ef\u4ee5\u7f16\u5199\u6709\u52a9\u4e8e\u5b9e\u65bd\u6b64\u76ee\u7684\u7684\u5355\u5143\u6d4b\u8bd5\uff08\u65e0\u8bba\u5982\u4f55\uff0c\u5b83\u4eec\u90fd\u662f\u4e00\u4e2a\u597d\u4e3b\u610f\uff09\u3002<\/p>\n<p>\u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u60a8\u5e0c\u671b\u96c6\u4e2d\u5c06\u6388\u6743\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\u7684\u4ee3\u7801\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u4e00\u76ee\u4e86\u7136\u5730\u4e86\u89e3\u5e94\u7528\u7a0b\u5e8f\u7684\u54ea\u4e9b\u90e8\u5206\u53d7\u5230\u4fdd\u62a4\u4ee5\u53ca\u53d7\u5230\u4fdd\u62a4\u7684\u7a0b\u5ea6\u3002\u5728\u7b2c 4 \u7ae0\u4e2d\uff0c\u60a8\u4f7f\u7528\u4e86 PageConventionCollection \u7c7b\u578b\u7684\u4e00\u4e9b\u6269\u5c55\u65b9\u6cd5\uff0c\u5c06\u65b0\u7684\u8def\u7531\u548c\u9875\u9762\u8def\u7531\u6a21\u578b\u7ea6\u5b9a\u6dfb\u52a0\u5230\u8def\u7531\u7cfb\u7edf\u4e2d\u3002\u5b58\u5728\u5176\u4ed6\u6269\u5c55\u65b9\u6cd5\uff0c\u4f7f\u60a8\u80fd\u591f\u901a\u8fc7\u7ea6\u5b9a\u5c06\u6388\u6743\u5e94\u7528\u4e8e\u5355\u4e2a\u9875\u9762\u548c\u6574\u4e2a\u6587\u4ef6\u5939\u3002\u4f7f\u7528\u8fd9\u4e9b\u89c4\u5219\uff0c\u60a8\u53ef\u4ee5\u5728\u4e00\u4e2a\u4f4d\u7f6e\u5efa\u7acb\u6388\u6743\u89c4\u5219\uff1aProgram \u7c7b\u3002\u4e3b\u8981\u65b9\u6cd5\u5305\u62ec<\/p>\n<p>\u2022  AuthorizePage - \u5411\u5355\u4e2a\u9875\u9762\u6dfb\u52a0\u6388\u6743<br \/>\n\u2022  AuthorizeFolder - \u5411\u6307\u5b9a\u6587\u4ef6\u5939\u4e2d\u7684\u6240\u6709\u9875\u9762\u6dfb\u52a0\u6388\u6743<br \/>\n\u2022  AuthorizeAreaFolder - \u5411\u6307\u5b9a\u533a\u57df\u5185\u6307\u5b9a\u6587\u4ef6\u5939\u4e2d\u7684\u6240\u6709\u9875\u9762\u6dfb\u52a0\u6388\u6743<\/p>\n<p>\u8fd9\u4e9b\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u4e2a\u90fd\u91c7\u7528\u9875\u9762\u3001\u6587\u4ef6\u5939\u548c\/\u6216\u533a\u57df\u7684\u540d\u79f0\uff0c\u5e76\u4e14\u8fd8\u5305\u62ec\u91c7\u7528\u7b56\u7565\u540d\u79f0\u7684\u91cd\u8f7d\u3002\u6211\u4eec\u7a0d\u540e\u4f1a\u8be6\u7ec6\u63a2\u8ba8\u653f\u7b56\u3002\u76ee\u524d\uff0c\u60a8\u53ef\u4ee5\u5c06\u7b56\u7565\u89c6\u4e3a\u4ee3\u8868\u6388\u6743\u8981\u6c42\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002\u60a8\u53ef\u4ee5\u5728 Program.cs \u4e2d\u4f7f\u7528 AuthorizePage \u65b9\u6cd5\u66ff\u6362\u4e4b\u524d\u5e94\u7528\u4e8e\u4e3b\u9875\u7684 Authorize \u5c5e\u6027\u3002<\/p>\n<p>\u6e05\u5355 10.5 \u4f7f\u7528 AuthorizePage \u65b9\u6cd5\u5c06\u6388\u6743\u5e94\u7528\u4e8e\u7279\u5b9a\u9875\u9762<\/p>\n<pre><code>builder.Services.AddRazorPages(options =&gt; {\n    options.Conventions.AuthorizePage(&quot;\/Index&quot;);                           \u2776\n    options.Conventions.Add(new CultureTemplatePageRouteModelConvention());\n    options.Conventions.Add(new PageRouteTransformerConvention(new KebabPageRouteParameterTransformer()));\n});<\/code><\/pre>\n<p>\u2776 \u5728\u6ca1\u6709\u7b56\u7565\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528 AuthorizePage \u4e0e\u5c06\u666e\u901a Authorize \u5c5e\u6027\u5e94\u7528\u4e8e\u7aef\u70b9 PageModel \u7684\u6548\u679c\u76f8\u540c\u3002<\/p>\n<p>\u60a8\u53ea\u5e0c\u671b\u6388\u6743\u7528\u6237\u80fd\u591f\u8bbf\u95ee Pages \u76ee\u5f55\u4e2d\u5404\u79cd *Manager \u6587\u4ef6\u5939\u4e2d\u7684 CRUD \u7ba1\u7406\u9875\u9762\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 AuthorizeFolder \u65b9\u6cd5\u7acb\u5373\u7981\u6b62\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u8bbf\u95ee\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>\u793a\u4f8b 10.6 \u4f7f\u7528 AuthorizeFolder \u65b9\u6cd5\u6388\u6743\u6587\u4ef6\u5939<\/p>\n<pre><code>builder.Services.AddRazorPages(options =&gt; {\n    options.Conventions.AuthorizeFolder(&quot;\/CityManager&quot;);\n    options.Conventions.AuthorizeFolder(&quot;\/CountryManager&quot;);\n    options.Conventions.AuthorizeFolder(&quot;\/PropertyManager&quot;);\n});<\/code><\/pre>\n<h3>\u300010.1.2 \u5141\u8bb8\u533f\u540d\u8bbf\u95ee<\/h3>\n<p>\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u80fd\u5e0c\u671b\u7981\u6b62\u533f\u540d\u8bbf\u95ee\u5e94\u7528\u7a0b\u5e8f\u7684\u5927\u591a\u6570\u5185\u5bb9\uff0c\u4f46\u5bf9\u5947\u6570\u9875\u9762\u542f\u7528\u533f\u540d\u8bbf\u95ee\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u6b63\u5728\u5f00\u53d1\u4e00\u4e2a\u5185\u90e8\u4e1a\u52a1\u7ebf\u5e94\u7528\u7a0b\u5e8f\uff0c\u8be5\u5e94\u7528\u7a0b\u5e8f\u9700\u8981\u9501\u5b9a\u4ee5\u9632\u6b62\u533f\u540d\u7528\u6237\u83b7\u5f97\u8bbf\u95ee\u6743\u9650\u3002\u4e3a\u6b64\uff0c\u60a8\u53ef\u4ee5\u6307\u5b9a\u4e00\u4e2a FallbackPolicy\uff0c\u8be5 FallbackPolicy \u9700\u8981\u5728\u914d\u7f6e\u6388\u6743\u670d\u52a1\u65f6\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff1a<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt; {\n    options.FallbackPolicy = new AuthorizationPolicyBuilder().\n        RequireAuthenticatedUser().Build();\n});<\/code><\/pre>\n<p>FallbackPolicy \u5728\u672a\u6307\u5b9a\u5176\u4ed6\u6388\u6743\u7b56\u7565\uff08\u4f8b\u5982\u901a\u8fc7\u5c5e\u6027\u6216\u7ea6\u5b9a\uff09\u7684\u60c5\u51b5\u4e0b\u6210\u4e3a\u5e94\u7528\u7a0b\u5e8f\u7684\u9ed8\u8ba4\u6388\u6743\u7b56\u7565\u3002<\/p>\n<p>\u60a8\u4ecd\u7136\u9700\u8981\u7528\u6237\u80fd\u591f\u8bbf\u95ee\u767b\u5f55\u9875\u9762\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002\u5bf9\u4e8e\u8fd9\u4e9b\u5b9e\u4f8b\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 AllowAnonymousAttribute\u3002\u5c31\u50cf AuthorizeAttribute \u4e00\u6837\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u5e94\u7528\u4e8e\u76ee\u6807\u7ec8\u7aef\u8282\u70b9\u7684 PageModel \u7c7b\uff1a<\/p>\n<pre><code>[AllowAnonymous]\npublic class LoginModel : PageModel<\/code><\/pre>\n<p>\u6216\u8005\uff0c\u53ef\u4ee5\u5c06 AuthorizeFolder \u65b9\u6cd5\u7684\u5e94\u7528\u7a0b\u5e8f\u4e0e AllowAnonymousToPage \u65b9\u6cd5\u7ed3\u5408\u4f7f\u7528\uff0c\u8be5\u65b9\u6cd5\u5c06\u8986\u76d6\u6307\u5b9a\u9875\u9762\u7684\u6388\u6743\uff0c\u4ece\u800c\u5141\u8bb8\u7528\u6237\u8bbf\u95ee\u8be5\u9875\u9762\uff0c\u800c\u65e0\u9700\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>\u6e05\u5355 10.7 \u5141\u8bb8\u533f\u540d\u8bbf\u95ee\u5355\u4e2a\u7aef\u70b9<\/p>\n<pre><code>builder.Services.AddRazorPages(options =&gt; {\n    options.Conventions.AuthorizeFolder(&quot;\/&quot;);              \u2776\n    options.Conventions.AllowAnonymousToPage(&quot;\/Login&quot;);    \u2777\n});<\/code><\/pre>\n<p>\u2776 \u9ed8\u8ba4\u963b\u6b62\u533f\u540d\u8bbf\u95ee\u5e94\u7528\u7a0b\u5e8f\u3002<br \/>\n\u2777 \u5141\u8bb8\u533f\u540d\u8bbf\u95ee\u53d7\u4fdd\u62a4\u6587\u4ef6\u5939\u4e2d\u7684\u767b\u5f55\u9875\u9762\u3002<\/p>\n<p>\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u5df2\u7ecf\u7814\u7a76\u4e86\u5b8c\u5168\u53d6\u51b3\u4e8e\u7528\u6237\u662f\u5426\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u6388\u6743\u3002\u5728\u73b0\u5b9e\u4e16\u754c\u4e2d\uff0c\u9664\u4e86\u6700\u7b80\u5355\u7684\u5e94\u7528\u7a0b\u5e8f\u4e4b\u5916\uff0c\u5176\u4ed6\u4efb\u4f55\u5185\u5bb9\u90fd\u9700\u8981\u66f4\u7cbe\u7ec6\u7684\u8bbf\u95ee\u63a7\u5236\u3002\u5728\u672c\u7ae0\u7684\u5176\u4f59\u90e8\u5206\uff0c\u6211\u4eec\u5c06\u63a2\u7d22\u8868\u8fbe\u8fd9\u4e9b\u9700\u6c42\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u7528\u6237\u7684\u7b56\u7565\u3002<\/p>\n<h2>10.2 \u4f7f\u7528\u89d2\u8272<\/h2>\n<p>\u89d2\u8272\u63d0\u4f9b\u4e86\u4e00\u79cd\u7b80\u5355\u7684\u673a\u5236\uff0c\u7528\u4e8e\u5c06\u5177\u6709\u76f8\u540c\u8bbf\u95ee\u7ea7\u522b\u7684\u7528\u6237\u5206\u7ec4\u5728\u4e00\u8d77\u3002\u5b83\u4eec\u5728\u590d\u6742\u6027\u4e0d\u592a\u53ef\u80fd\u589e\u52a0\u4e14\u6613\u4e8e\u533a\u5206\u4e0d\u540c\u7528\u6237\u7ec4\u7684\u8bbf\u95ee\u9700\u6c42\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6700\u6709\u7528\u3002Identity \u5305\u62ec\u5bf9\u89d2\u8272\u7684\u652f\u6301\uff0c\u4f46\u5fc5\u987b\u901a\u8fc7\u4f7f\u7528 <code>AddRoles&lt;TRole&gt;<\/code> \u65b9\u6cd5\u5c06\u4e0e\u89d2\u8272\u76f8\u5173\u7684\u670d\u52a1\u6dfb\u52a0\u5230\u5bb9\u5668\u4e2d\u6765\u542f\u7528\u5b83\u3002IdentityRole \u662f\u8868\u793a\u89d2\u8272\u7684\u9ed8\u8ba4\u5b9e\u73b0\uff1a<\/p>\n<pre><code>builder.Services.AddDefaultIdentity&lt;CityBreaksUser&gt;(options =&gt; {\n    options.Password.RequireDigit = false;\n    options.Password.RequireLowercase = false;\n    options.Password.RequireNonAlphanumeric = false;\n    options.Password.RequireUppercase = false;\n})\n    .AddRoles&lt;IdentityRole&gt;()                        \u2776\n    .AddEntityFrameworkStores&lt;CityBreaksContext&gt;();<\/code><\/pre>\n<p>\u2776 \u4f7f\u7528 AddRoles \u65b9\u6cd5\u5c06\u4e0e\u89d2\u8272\u76f8\u5173\u7684\u670d\u52a1\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>\u6ca1\u6709\u7528\u4e8e\u7ba1\u7406\u89d2\u8272\u7684 UI\uff0c\u56e0\u6b64\u60a8\u5fc5\u987b\u6784\u5efa\u81ea\u5df1\u7684 UI\u3002\u7528\u4e8e\u5904\u7406\u89d2\u8272\u7684\u4e3b\u8981 API \u662f <code>RoleManager&lt;TRole&gt;<\/code> \u670d\u52a1\uff0c\u5b83\u662f\u901a\u8fc7 AddRoles \u65b9\u6cd5\u6dfb\u52a0\u5230\u670d\u52a1\u5bb9\u5668\u7684\u670d\u52a1\u4e4b\u4e00\u3002RoleManager \u5305\u62ec\u4ee5\u4e0b CRUD \u65b9\u6cd5\uff1a<\/p>\n<p>\u2022  CreateAsync<br \/>\n\u2022  UpdateAsync<br \/>\n\u2022  \u5220\u9664\u5f02\u6b65<\/p>\n<p>RoleManager \u8fd8\u5305\u62ec\u4e00\u4e2a\u5c5e\u6027 Roles\uff0c\u8be5\u5c5e\u6027\u8fd4\u56de RoleStore \u4e2d\u7684\u6240\u6709\u89d2\u8272\u3002RoleStore \u8868\u793a\u89d2\u8272\u7684\u5b58\u50a8\u673a\u5236\u3002\u5728\u4f60\u7684\u4f8b\u5b50\u4e2d\uff0c\u90a3\u5c31\u662f SQLite \u6570\u636e\u5e93\u3002\u901a\u5e38\uff0c\u60a8\u4e0d\u4f1a\u76f4\u63a5\u4f7f\u7528 RoleStore;\u60a8\u5c06\u4e3a\u6b64\u4f7f\u7528 RoleManager\u3002\u5728\u63a5\u4e0b\u6765\u7684\u51e0\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684\u7ba1\u7406\u533a\u57df\uff0c\u7528\u4e8e\u4f7f\u7528 RoleManager \u521b\u5efa\u548c\u67e5\u770b\u89d2\u8272\u5e76\u5c06\u5176\u5206\u914d\u7ed9\u7528\u6237\u3002<\/p>\n<h3>10.2.1 \u67e5\u770b\u89d2\u8272<\/h3>\n<p>\u9996\u5148\uff0c\u5c06\u540d\u4e3a RolesManager \u7684\u6587\u4ef6\u5939\u6dfb\u52a0\u5230 Pages \u6587\u4ef6\u5939\u3002\u5728\u8be5\u9875\u9762\u4e2d\uff0c\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a Index.cshtml \u7684\u65b0 Razor \u9875\u9762\u3002\u5c06 RoleManager \u670d\u52a1\u6ce8\u5165 PageModel \u7c7b\u6784\u9020\u51fd\u6570\uff0c\u5e76\u4f7f\u7528\u5176 Roles \u5c5e\u6027\u586b\u5145\u516c\u5171 List<IdentityRole> \u5c5e\u6027\u3002<\/p>\n<p>\u6e05\u5355 10.8 RolesManager IndexModel \u7c7b<\/p>\n<pre><code>using Microsoft.AspNetCore.Identity;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace CityBreaks.Pages.RolesManager\n{\n    public class IndexModel : PageModel\n    {\n        private readonly RoleManager&lt;IdentityRole&gt; _roleManager;    \u2776\n        public IndexModel(RoleManager&lt;IdentityRole&gt; roleManager)    \u2776\n        {                                                           \u2776\n            _roleManager  = roleManager;                            \u2776\n        }                                                           \u2776\n        public List&lt;IdentityRole&gt; Roles { get; set; }               \u2777\n        public void OnGet()\n        {\n            Roles = _roleManager.Roles.ToList();                    \u2777\n        }\n    }\n}<\/code><\/pre>\n<p>\u2776 \u901a\u8fc7\u6784\u9020\u51fd\u6570\u5c06 <code>RoleManager&lt;TRole&gt;<\/code> \u670d\u52a1\u6ce8\u5165\u5230 IndexModel \u4e2d\uff0c\u5e76\u5c06\u5176\u5206\u914d\u7ed9\u79c1\u6709\u5b57\u6bb5\u4f9b\u4ee5\u540e\u4f7f\u7528\u3002<br \/>\n\u2777 \u58f0\u660e\u4e00\u4e2a\u516c\u5171 <code>List&lt;IdentityRole&gt;<\/code> \u5c5e\u6027\uff0c\u5e76\u4f7f\u7528 RoleManager \u670d\u52a1\u5c06\u5176\u586b\u5145\u5230\u6240\u6709\u73b0\u6709\u89d2\u8272\u4e2d\u3002<\/p>\n<p>\u5728 Razor \u9875\u9762\u672c\u8eab\u4e2d\uff0c\u68c0\u67e5\u662f\u5426\u6709\u4efb\u4f55\u89d2\u8272\uff0c\u5982\u679c\u6709\uff0c\u8bf7\u5728\u8868\u4e2d\u663e\u793a\u8fd9\u4e9b\u89d2\u8272\u3002\u6b64\u4ee3\u7801\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>\u6e05\u5355 10.9 \u5217\u51fa\u89d2\u8272\u5e76\u5728\u8868\u4e2d\u663e\u793a\u5b83\u4eec<\/p>\n<pre><code>@page\n@model CityBreaks.Pages.RolesManager.IndexModel\n@{\n    ViewData[&quot;Title&quot;] = &quot;Roles&quot;;\n}\n&lt;a asp-page=&quot;\/RolesManager\/Create&quot;&gt;New&lt;\/a&gt;\n@if (Model.Roles.Any())\n{\n    &lt;table class=&quot;table&quot;&gt;\n        @foreach(var role in Model.Roles)\n        {\n            &lt;tr&gt;\n                &lt;td&gt;@role.Name&lt;\/td&gt;\n            &lt;\/tr&gt;\n        }\n    &lt;\/table&gt;\n}<\/code><\/pre>\n<p>\u8fd9\u91cc\u7684\u4ee3\u7801\u73b0\u5728\u5e94\u8be5\u4e0d\u9700\u8981\u4efb\u4f55\u89e3\u91ca\u3002\u5982\u679c\u60a8\u8fd0\u884c\u8be5\u9875\u9762\uff0c\u5219\u53ea\u4f1a\u770b\u5230\u7528\u4e8e\u521b\u5efa\u65b0\u89d2\u8272\u7684\u94fe\u63a5\u3002\u5b83\u65e0\u5904\u53ef\u53bb\uff0c\u56e0\u4e3a\u8be5\u9875\u9762\u5c1a\u4e0d\u5b58\u5728\u3002\u90a3\u662f\u4f60\u7684\u4e0b\u4e00\u4efd\u5de5\u4f5c\u3002<\/p>\n<h3>10.2.2 \u6dfb\u52a0\u89d2\u8272<\/h3>\n<p>\u5c06\u540d\u4e3a Create \u7684\u65b0 Razor \u9875\u9762\u6dfb\u52a0\u5230 RolesManager \u6587\u4ef6\u5939\u3002\u8fd9\u5c06\u5305\u542b\u7528\u4e8e\u521b\u5efa\u65b0\u89d2\u8272\u7684\u8868\u5355\u3002\u8be5\u89d2\u8272\u552f\u4e00\u9700\u8981\u7684\u6570\u636e\u662f\u540d\u79f0\u3002\u5c06 RoleManager \u670d\u52a1\u6ce8\u5165\u9875\u9762\uff0c\u5e76\u4f7f\u7528\u5176 CreateAsync \u65b9\u6cd5\u6dfb\u52a0\u65b0\u89d2\u8272\u3002\u540c\u6837\uff0c\u4ee3\u7801\u5e94\u7c7b\u4f3c\u4e8e\u60a8\u5df2\u7ecf\u521b\u5efa\u7684 CRUD \u9875\u9762\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86 PageModel \u7c7b\u7684\u4ee3\u7801\u3002<\/p>\n<p>\u6e05\u5355 10.10 RolesManager \u7684 CreateModel<\/p>\n<pre><code>using Microsoft.AspNetCore.Identity;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\n\nnamespace CityBreaks.Pages.RolesManager\n{\n    public class CreateModel : PageModel\n    {\n        private readonly RoleManager&lt;IdentityRole&gt; _roleManager;\n        public CreateModel(RoleManager&lt;IdentityRole&gt; roleManager)\n        {\n            _roleManager = roleManager;\n        }\n\n        [BindProperty]\n        public string Name { get; set; }\n        public async Task&lt;IActionResult&gt; OnPostAsync()\n        {\n            if (ModelState.IsValid)\n            {\n                var role = new IdentityRole { Name = Name };\n                await _roleManager.CreateAsync(role);\n                return RedirectToPage(&quot;\/RolesManager\/Index&quot;);\n            }\n            return Page();\n        }\n    }\n}<\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\uff0c\u5c06\u8868\u5355\u6dfb\u52a0\u5230 Razor \u9875\u9762\u672c\u8eab\u3002<\/p>\n<p>\u6e05\u5355 10.11 \u521b\u5efa\u89d2\u8272\u8868\u5355<\/p>\n<pre><code>@page\n@model CityBreaks.Pages.RolesManager.CreateModel\n@{\n    ViewData[&quot;Title&quot;] = &quot;Create Role&quot;;\n}\n&lt;h4&gt;Create Role&lt;\/h4&gt;\n\n&lt;div class=&quot;row&quot;&gt;\n    &lt;div class=&quot;col-md-8&quot;&gt;\n        &lt;form method=&quot;post&quot;&gt;\n              &lt;div class=&quot;form-group mb-3&quot;&gt;\n                &lt;label asp-for=&quot;Name&quot; class=&quot;control-label&quot;&gt;&lt;\/label&gt;\n                &lt;input asp-for=&quot;Name&quot; class=&quot;form-control&quot; \/&gt;\n                &lt;span asp-validation-for=&quot;Name&quot; class=&quot;text-danger&quot;&gt;&lt;\/span&gt;\n            &lt;\/div&gt;\n            &lt;div class=&quot;form-group&quot;&gt;\n                &lt;input type=&quot;submit&quot; value=&quot;Assign&quot; class=&quot;btn btn-primary&quot; \/&gt;\n            &lt;\/div&gt;\n        &lt;\/form&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n@section scripts{\n&lt;partial name=&quot;_ValidationScriptsPartial&quot; \/&gt;\n}<\/code><\/pre>\n<p>\u73b0\u5728\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u5bfc\u822a\u5230 \/roles-manager \/create\u3002\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a Admin \u7684\u89d2\u8272\uff0c\u5f53\u60a8\u6ee1\u610f\u5b83\u6709\u6548\u65f6\uff0c\u518d\u6dfb\u52a0\u4e24\u4e2a\u540d\u4e3a CityAdmin \u548c PropertyAdmin \u7684\u89d2\u8272\u3002<\/p>\n<h3>10.2.3 \u4e3a\u7528\u6237\u5206\u914d\u89d2\u8272<\/h3>\n<p>\u5728\u4e3a\u7528\u6237\u5206\u914d\u89d2\u8272\u4e4b\u524d\uff0c\u60a8\u9700\u8981\u4e00\u4e9b\u7528\u6237\u3002\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6ce8\u518c\u4e09\u4e2a\u7528\u6237\uff0c\u4f7f\u7528\u4ee5\u4e0b\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u548c\u76f8\u540c\u7684\u5bc6\u7801\uff08\u4e3a\u7b80\u5355\u8d77\u89c1\uff09\u3002\u6211\u5728\u672c\u7ae0\u968f\u9644\u7684\u4ee3\u7801\u4e0b\u8f7d\u4e2d\u4f7f\u7528\u4e86 password\uff1a<\/p>\n<p>anna@test.com<br \/>\ncolin@test.com<br \/>\npaul@test.com<\/p>\n<p>\u63a5\u4e0b\u6765\uff0c\u5c06\u65b0\u7684 Razor \u9875\u9762\u6dfb\u52a0\u5230\u540d\u4e3a Assign \u7684 RolesManager \u6587\u4ef6\u5939\u3002\u5728\u672c\u9875\u4e2d\uff0c\u60a8\u5c06\u83b7\u53d6\u6240\u6709\u7528\u6237\u7684\u5217\u8868\u548c\u6240\u6709\u89d2\u8272\u7684\u5217\u8868\uff0c\u5e76\u5c06\u5b83\u4eec\u663e\u793a\u5728\u7528\u4e8e\u5c06\u6240\u9009\u7528\u6237\u5206\u914d\u7ed9\u6240\u9009\u89d2\u8272\u7684\u9009\u5b9a\u5217\u8868\u4e2d\u3002\u5c06 AssignModel \u4ee3\u7801\u66f4\u6539\u4e3a\u4ee5\u4e0b\u6e05\u5355\u4e2d\u7684\u4ee3\u7801\u3002<\/p>\n<p>\u6e05\u5355 10.12 AssignModel \u4ee3\u7801<\/p>\n<pre><code>using CityBreaks.Models;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.AspNetCore.Mvc.Rendering;\nusing Microsoft.EntityFrameworkCore;\nusing System.ComponentModel.DataAnnotations;\n\nnamespace CityBreaks.Pages.RolesManager\n{\n    public class AssignModel : PageModel\n    {\n        private readonly RoleManager&lt;IdentityRole&gt; _roleManager;           \u2776\n        private readonly UserManager&lt;CityBreaksUser&gt; _userManager;         \u2776\n        public AssignModel(RoleManager&lt;IdentityRole&gt;                       \u2776\n        \u27a5 roleManager, UserManager&lt;CityBreaksUser&gt; userManager)           \u2776\n        {                                                                  \u2776\n            _roleManager = roleManager;                                    \u2776\n            _userManager = userManager;                                    \u2776\n        }                                                                  \u2776\n        public SelectList Roles { get; set; }\n        public SelectList Users { get; set; }\n        [BindProperty, Required, Display(Name =&quot;Role&quot;)]\n        public string SelectedRole { get; set; }\n        [BindProperty, Required, Display(Name =&quot;User&quot;)]\n        public string SelectedUser { get; set; }\n        public async Task OnGet()\n        {\n            await GetOptions();\n        }\n\n        public async Task&lt;IActionResult&gt; OnPostAsync()\n        {\n            if (ModelState.IsValid)\n            {\n                var user = await _userManager.FindByNameAsync(SelectedUser);\u2777\n                await _userManager.AddToRoleAsync(user, SelectedRole);     \u2778\n                return RedirectToPage(&quot;\/RolesManager\/Index&quot;);\n            }\n            await GetOptions();\n            return Page();\n        }\n\n        public async Task GetOptions()                                     \u2779\n        {                                                                  \u2779\n            var roles = await _roleManager.Roles.ToListAsync();            \u2779\n            var users = await _userManager.Users.ToListAsync();            \u2779\n            Roles = new SelectList(roles, nameof(IdentityRole.Name));      \u2779\n            Users = new SelectList(users, nameof(CityBreaksUser.UserName));\u2779\n        }                                                                  \u2779\n    }\n}<\/code><\/pre>\n<p>\u2776 \u5c06 UserManager \u548c RoleManager \u670d\u52a1\u6ce8\u5165 PageModel \u7c7b\u3002<br \/>\n\u2777 \u83b7\u53d6\u5177\u6709\u6240\u9009\u540d\u79f0\u7684\u7528\u6237\u3002<br \/>\n\u2778 \u5c06\u6240\u9009\u7528\u6237\u5206\u914d\u7ed9\u6240\u9009\u89d2\u8272\u3002<br \/>\n\u2779 \u58f0\u660e\u4e00\u4e2a\u79c1\u6709\u65b9\u6cd5\uff0c\u5c06\u7528\u6237\u548c\u89d2\u8272\u5206\u914d\u7ed9 SelectList \u5bf9\u8c61\u3002<\/p>\n<p>Razor \u9875\u9762\u672c\u8eab\u5728\u8868\u5355\u4e2d\u5305\u542b\u4e24\u4e2a select \u5143\u7d20\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<br \/>\n\u793a\u4f8b 10.13 \u5c06\u7528\u6237\u5206\u914d\u7ed9 Role \u8868\u5355<\/p>\n<pre><code>@page\n@model CityBreaks.Pages.RolesManager.AssignModel\n@{\n}\n&lt;h4&gt;Assign User To Role&lt;\/h4&gt;\n\n&lt;div class=&quot;row&quot;&gt;\n    &lt;div class=&quot;col-md-8&quot;&gt;\n        &lt;form method=&quot;post&quot;&gt;\n              &lt;div class=&quot;form-group mb-3&quot;&gt;\n                &lt;label asp-for=&quot;SelectedUser&quot; class=&quot;control-label&quot;&gt;&lt;\/label&gt;\n                &lt;select asp-for=&quot;SelectedUser&quot; asp-items=&quot;Model.Users&quot; \n                 \u27a5 class=&quot;form-control&quot;&gt;\n                    &lt;option&gt;&lt;\/option&gt;\n                &lt;\/select&gt;\n                &lt;span asp-validation-for=&quot;SelectedUser&quot; \n                 \u27a5 class=&quot;text-danger&quot;&gt;&lt;\/span&gt;\n            &lt;\/div&gt;\n            &lt;div class=&quot;form-group mb-3&quot;&gt;\n                &lt;label asp-for=&quot;SelectedRole&quot; class=&quot;control-label&quot;&gt;&lt;\/label&gt;\n                &lt;select asp-for=&quot;SelectedRole&quot; \n                 \u27a5 asp-items=&quot;Model.Roles&quot; class=&quot;form-control&quot;&gt;\n                    &lt;option&gt;&lt;\/option&gt;\n                &lt;\/select&gt;\n                &lt;span asp-validation-for=&quot;SelectedRole&quot; \n                 \u27a5 class=&quot;text-danger&quot;&gt;&lt;\/span&gt;\n            &lt;\/div&gt;\n            &lt;div class=&quot;form-group&quot;&gt;\n                &lt;input type=&quot;submit&quot; value=&quot;Assign&quot; \n                 \u27a5 class=&quot;btn btn-primary&quot; \/&gt;\n            &lt;\/div&gt;\n        &lt;\/form&gt;\n    &lt;\/div&gt;\n&lt;\/div&gt;\n\n@section scripts{\n&lt;partial name=&quot;_ValidationScriptsPartial&quot; \/&gt;\n}<\/code><\/pre>\n<p>\u5b8c\u6210\u6b64\u4f5c\u540e\uff0c\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u5bfc\u822a\u5230 \/roles-manager\/assign\u3002\u5c06 anna@test.com \u5206\u914d\u7ed9 Admin \u89d2\u8272\u3002\u5b8c\u6210\u6b64\u4f5c\u540e\uff0c\u8fd4\u56de\u5230 Assign .cshtml \u6587\u4ef6\uff0c\u5e76\u4e3a Microsoft.AspNetCore.Authorization \u6dfb\u52a0 using \u6307\u4ee4\u3002\u7136\u540e\u5411 AssignModel \u7c7b\u6dfb\u52a0 Authorize \u5c5e\u6027\uff0c\u4f46\u8fd9\u6b21\u5c06 \u201cAdmin\u201d \u5206\u914d\u4e3a Roles \u5c5e\u6027\u4e2d\u7684\u503c\uff1a<\/p>\n<pre><code>[Authorize(Roles = &quot;Admin&quot;)]\npublic class AssignModel : PageModel\n{<\/code><\/pre>\n<p>\u91cd\u65b0\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u4e00\u6b21\uff0c\u4f7f\u7528 colin@test.com \u6216 paul@test.com \u767b\u5f55\u3002\u7136\u540e\u5c1d\u8bd5\u5bfc\u822a\u5230 \/roles-manager \/assign\u3002\u60a8\u5e94\u8be5\u4f1a\u53d1\u73b0\u60a8\u88ab\u91cd\u5b9a\u5411\u5230 Access Denied \u9875\u9762\u3002<\/p>\n<p>\u6ce8\u9500\uff0c\u7136\u540e\u4f7f\u7528 anna@test.com \u767b\u5f55\u3002\u8fd9\u4e00\u6b21\uff0c\u5f53\u60a8\u5bfc\u822a\u5230 roles-manager \/assign \u65f6\uff0c\u60a8\u5e94\u8be5\u4f1a\u8bbf\u95ee\u8be5\u9875\u9762\u3002Anna \u53ef\u4ee5\u8bbf\u95ee\u8be5\u9875\u9762\uff0c\u56e0\u4e3a\u5979\u662f Roles \u5c5e\u6027\u4e2d\u6307\u5b9a\u7684\u89d2\u8272\u7684\u6210\u5458\uff0c\u800c Paul \u5219\u4e0d\u662f\u3002\u5c3d\u7ba1\u60a8\u53ea\u4f20\u5165\u4e86\u4e00\u4e2a\u89d2\u8272\u540d\u79f0\uff0c\u4f46 Roles \u5c5e\u6027\u91c7\u7528\u9017\u53f7\u5206\u9694\u7684\u89d2\u8272\u540d\u79f0\u5217\u8868\uff0c\u8fd9\u5728\u4f7f\u7528\u89d2\u8272\u65f6\u63d0\u4f9b\u4e86\u7075\u6d3b\u6027\u3002\u6b64\u5916\uff0c\u7528\u6237\u53ef\u4ee5\u5c5e\u4e8e\u591a\u4e2a\u89d2\u8272\u3002<\/p>\n<h3>10.2.4 \u4f7f\u7528\u7b56\u7565\u5e94\u7528\u89d2\u8272\u68c0\u67e5<\/h3>\n<p>\u60a8\u6269\u5c55\u4e86 Authorize \u5c5e\u6027\u4ee5\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u5c5e\u4e8e\u6307\u5b9a\u89d2\u8272\u3002\u5982\u679c\u8981\u5bf9\u6574\u4e2a\u6587\u4ef6\u5939\u7684\u5185\u5bb9\u5e94\u7528\u6b64\u68c0\u67e5\uff0c\u53ef\u4ee5\u4f7f\u7528\u91c7\u7528\u7b56\u7565\u7684 AuthorizeFolder \u65b9\u6cd5\u7684\u91cd\u8f7d;\u6211\u4eec\u5f88\u5feb\u4f1a\u66f4\u8be6\u7ec6\u5730\u7814\u7a76\u653f\u7b56\u3002\u4e0d\u8fc7\uff0c\u60a8\u53ef\u4ee5\u5c06\u7b56\u7565\u89c6\u4e3a\u8868\u793a\u9700\u8981\u6ee1\u8db3\u7684\u8981\u6c42\uff0c\u4ee5\u786e\u5b9a\u5f53\u524d\u7528\u6237\u662f\u5426\u6709\u6743\u8bbf\u95ee\u8bf7\u6c42\u7684\u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n<p>\u5bf9\u4e8e\u76f8\u5bf9\u7b80\u5355\u7684\u7b56\u7565\uff0c\u60a8\u53ef\u4ee5\u5728 AddAuthorization \u65b9\u6cd5\u4e2d\u4f7f\u7528 AuthorizeOptions \u6765\u914d\u7f6e\u57fa\u4e8e\u89d2\u8272\u7684\u7b56\u7565\u3002AddPolicy \u65b9\u6cd5\u91c7\u7528\u7b56\u7565\u7684\u540d\u79f0\u548c AuthorizationPolicyBuilder\uff0c\u540e\u8005\u5177\u6709 RequireRole \u65b9\u6cd5\uff0c\u4f7f\u60a8\u80fd\u591f\u58f0\u660e\u9700\u8981\u54ea\u4e9b\u89d2\u8272\u3002<\/p>\n<p>\u6e05\u5355 10.14 \u5728 Program.cs \u4e2d\u914d\u7f6e\u57fa\u4e8e\u89d2\u8272\u7684\u7b56\u7565<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt;\n{\n    options.AddPolicy(&quot;AdminPolicy&quot;, \n    \u27a5 policyBuilder =&gt; policyBuilder.RequireRole(&quot;Admin&quot;));\n});<\/code><\/pre>\n<p>\u914d\u7f6e\u540d\u4e3a AdminPolicy \u7684\u7b56\u7565\u540e\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u5e94\u7528\u4e8e AuthorizeFolder \u65b9\u6cd5\uff0c\u4ee5\u786e\u4fdd\u53ea\u6709 Admin \u89d2\u8272\u7684\u6210\u5458\u624d\u80fd\u8bbf\u95ee\u5185\u5bb9\uff1a<\/p>\n<pre><code>builder.Services.AddRazorPages(options =&gt; {\n    options.Conventions.AuthorizeFolder(&quot;\/RolesManager&quot;, &quot;AdminPolicy&quot;);\n});<\/code><\/pre>\n<p>\u6b63\u5982\u6211\u5728\u672c\u8282\u5f00\u5934\u6240\u6307\u51fa\u7684\uff0c\u89d2\u8272\u5bf9\u4e8e\u76f8\u5bf9\u7b80\u5355\u7684\u6388\u6743\u8981\u6c42\u975e\u5e38\u6709\u7528\uff0c\u5176\u4e2d\u8bbf\u95ee\u7b56\u7565\u53ef\u4ee5\u5e94\u7528\u4e8e\u7528\u6237\u7ec4\u3002\u7528\u6237\u8981\u4e48\u662f\u89d2\u8272\u7684\u6210\u5458\uff0c\u8981\u4e48\u4e0d\u662f\u3002\u89d2\u8272\u7684\u4f18\u70b9\u662f\u6613\u4e8e\u914d\u7f6e\u548c\u7ba1\u7406\u3002<\/p>\n<p>\u5982\u679c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u6388\u6743\u8981\u6c42\u8d8a\u6765\u8d8a\u590d\u6742\uff0c\u60a8\u5c06\u5f00\u59cb\u53d1\u73b0\u8d8a\u6765\u8d8a\u590d\u6742\u7684\u89d2\u8272\u96c6\u5408\u96be\u4ee5\u7ba1\u7406\u3002\u6b64\u65f6\uff0c\u60a8\u9700\u8981\u6839\u636e\u5bf9\u5355\u4e2a\u7528\u6237\u7684\u4e86\u89e3\u6765\u63a7\u5236\u6388\u6743\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e\u9884\u5b9a\u4e49\u7684\u7528\u6237\u7ec4\u6765\u7ba1\u7406\u6388\u6743\u3002\u60a8\u5c06\u7528\u4e8e\u786e\u5b9a\u8fd9\u4e00\u70b9\u7684\u673a\u5236\u79f0\u4e3a claims\u3002<\/p>\n<h2>10.3 \u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743<\/h2>\n<p>\u6211\u4eec\u5728\u4e0a\u4e00\u7ae0\u4e2d\u8c08\u5230\u4e86\u58f0\u660e\uff0c\u4f46\u4f5c\u4e3a\u590d\u4e60\uff0c\u58f0\u660e\u53ea\u662f\u540d\u79f0-\u503c\u5bf9\uff0c\u8868\u793a\u60a8\u4e86\u89e3\u7684\u6709\u5173\u7528\u6237\u7684\u6570\u636e\u9879\u3002\u5b83\u4eec\u9644\u52a0\u5230 ClaimsIdentity\uff0c\u7136\u540e\u9644\u52a0\u5230 ClaimsPrincipal\uff08\u8bf7\u53c2\u89c1\u56fe 10.3\uff09\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1003.png\" ><\/p>\n<p>\u56fe 10.3 ClaimsPrincipal \u652f\u6301\u591a\u4e2a\u6807\u8bc6\uff0c\u6bcf\u4e2a\u6807\u8bc6\u652f\u6301\u591a\u4e2a\u58f0\u660e\u3002<\/p>\n<p>\u5728 .NET \u4e2d\uff0c\u58f0\u660e\u7531 Claim \u7c7b\u8868\u793a\u3002\u5176\u5c5e\u6027\u5305\u62ec Type\u3001Value \u548c Issuer\u3002\u6700\u540e\u4e00\u4e2a \uff08Issuer\uff09 \u662f\u9881\u53d1\u58f0\u660e\u7684\u9881\u53d1\u673a\u6784\u3002\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5c06\u58f0\u660e\u5206\u914d\u7ed9\u7528\u6237\u65f6\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u9881\u53d1\u8005\u4e3a LOCAL_AUTHORITY\u3002\u5982\u679c\u60a8\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5408\u5e76\u4e86\u5916\u90e8\u8eab\u4efd\u9a8c\u8bc1\u63d0\u4f9b\u7a0b\u5e8f\uff08\u5982 Google \u6216 Facebook\uff09\uff0c\u5b83\u4eec\u5c06\u9881\u53d1\u4ed6\u4eec\u6dfb\u52a0\u5230\u4ed6\u4eec\u8eab\u4efd\u9a8c\u8bc1\u7684\u8eab\u4efd\u7684\u4efb\u4f55\u58f0\u660e\u3002\u60a8\u53ef\u4ee5\u6839\u636e\u4e3a\u9881\u53d1\u8005\u63d0\u4f9b\u7684\u6743\u91cd\u6765\u9009\u62e9\u8981\u4f7f\u7528\u7684\u58f0\u660e\u7248\u672c\u3002\u4f8b\u5982\uff0c\u50cf Facebook \u8fd9\u6837\u7684\u5916\u90e8\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u5f88\u53ef\u80fd\u4f1a\u8bc1\u660e\u7535\u5b50\u90ae\u4ef6\u58f0\u660e\uff0c\u4f46\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u53ef\u80fd\u4e0d\u5b58\u5728\u3002<\/p>\n<p>Type \u8868\u793a\u7684\u5185\u5bb9\u6ca1\u6709\u9650\u5236\u3002\u5e7f\u6cdb\u4f7f\u7528\u7684\u58f0\u660e\u7c7b\u578b\u7531\u57df schemas.xmlsoap.org \u4e2d\u7684 URI \u8868\u793a\u3002\u671f\u671b\u5f00\u53d1\u4eba\u5458\u5728\u5176\u4ee3\u7801\u4e2d\u4f7f\u7528\u8fd9\u4e9b URI \u662f\u4e0d\u5408\u7406\u7684\uff0c\u56e0\u6b64\u4e3a\u65b9\u4fbf\u8d77\u89c1\uff0c\u5b83\u4eec\u5728 .NET \u4e2d\u7531 ClaimTypes \u7c7b\u4e2d\u7684\u5e38\u91cf\u96c6\u5408\u8868\u793a\u3002\u8868 10.1 \u663e\u793a\u4e86\u60a8\u6700\u6709\u53ef\u80fd\u4f7f\u7528\u7684\u7d22\u8d54\u7c7b\u578b\u3002<\/p>\n<p>\u8868 10.1 \u5e38\u7528\u7684\u58f0\u660e\u7c7b\u578b<\/p>\n<table border=\"1\" class=\"contenttable\" width=\"100%\">\n<colgroup class=\"calibre29\">\n<col class=\"calibre30\" span=\"1\" width=\"50%\">\n<col class=\"calibre30\" span=\"1\" width=\"50%\">\n<\/colgroup>\n<tbody>\n<tr class=\"calibre31\">\n<th class=\"fm-contenttable1\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-head\"><a id=\"calibre_link-6581\"><\/a>Claim type<\/p>\n<\/th>\n<th class=\"fm-contenttable1\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-head\"><a id=\"calibre_link-6582\"><\/a>Description<\/p>\n<\/th>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6583\"><\/a><span class=\"fm-code-in-text1\">ClaimTypes.Name<\/span><a id=\"calibre_link-747\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6584\"><\/a>Represents the username of the user<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6585\"><\/a><span class=\"fm-code-in-text1\">ClaimTypes.Email<\/span><a id=\"calibre_link-745\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6586\"><\/a>Used for the user\u2019s email address<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6587\"><\/a><span class=\"fm-code-in-text1\">ClaimTypes.GivenName<\/span><a id=\"calibre_link-746\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6588\"><\/a>The user\u2019s first name<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6589\"><\/a><span class=\"fm-code-in-text1\">ClaimTypes.Surname<\/span><a id=\"calibre_link-749\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6590\"><\/a>The user\u2019s last name<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6591\"><\/a><span class=\"fm-code-in-text1\">ClaimTypes.NameIdentifier<\/span><a id=\"calibre_link-748\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6592\"><\/a>The user\u2019s unique identifier<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u5f53\u7528\u6237\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u5e76\u4e3a\u5176\u5206\u914d\u4e86 ClaimsIdentity \u65f6\uff0c\u8eab\u4efd\u9a8c\u8bc1\u7cfb\u7edf\u4f1a\u5411\u5176\u6dfb\u52a0\u5404\u79cd\u58f0\u660e\u3002\u8fd9\u4e9b\u5305\u62ec Name\u3001Email \u548c NameIdentifier\uff08\u56fe 10.4\uff09\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1004.png\" ><\/p>\n<p>\u56fe 10.4 \u5df2\u9a8c\u8bc1\u7528\u6237\u7684\u586b\u5145\u58f0\u660e<\/p>\n<p>\u5982\u679c\u8981\u4f7f\u7528\u58f0\u660e\u4f5c\u4e3a\u7ba1\u7406\u6388\u6743\u7684\u57fa\u7840\uff0c\u5219\u9700\u8981\u67d0\u79cd\u65b9\u6cd5\u6765\u5206\u914d\u4e0e\u8bbf\u95ee\u7ea7\u522b\u76f8\u5173\u7684\u5176\u4ed6\u58f0\u660e\uff0c\u5e76\u6839\u636e\u7528\u6237\u62e5\u6709\u7684\u58f0\u660e\u7684\u5b58\u5728\u6216\u503c\u6765\u6d4b\u8bd5\u7528\u6237\u662f\u5426\u7b26\u5408\u6761\u4ef6\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684\u9875\u9762\uff0c\u7528\u4e8e\u5411\u7528\u6237\u6dfb\u52a0\u65b0\u58f0\u660e\u3002<\/p>\n<h3>10.3.1 \u5411\u7528\u6237\u6dfb\u52a0\u58f0\u660e<\/h3>\n<p>\u9996\u5148\uff0c\u60a8\u5c06\u5411 Pages \u6587\u4ef6\u5939\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ClaimsManager \u7684\u65b0\u6587\u4ef6\u5939\u3002\u5728\u8be5\u9875\u9762\u4e2d\uff0c\u60a8\u5c06\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a Index \u7684\u65b0 Razor \u9875\u9762\u3002\u8fd9\u5c06\u5217\u51fa\u5df2\u5206\u914d\u5176\u4ed6\u58f0\u660e\u7684\u6240\u6709\u7528\u6237\uff0c\u4ee5\u53ca\u5df2\u5206\u914d\u7684\u58f0\u660e\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>ClaimsManager \u7d22\u5f15\u9875\u9762\u7684 PageModel \u4ee3\u7801\u5c06 UserManager \u4f5c\u4e3a\u6ce8\u5165\u7684\u4f9d\u8d56\u9879\uff0c\u5e76\u5c06\u5176\u5206\u914d\u7ed9\u516c\u5171\u5c5e\u6027\uff0c\u4ee5\u4fbf\u9875\u9762\u7684 Razor \u90e8\u5206\u53ef\u4ee5\u901a\u8fc7\u5176 Model \u5c5e\u6027\u8bbf\u95ee\u5b83\u3002\u5b83\u8fd8\u5728 OnGetAsync \u65b9\u6cd5\u4e2d\u7528\u4e8e\u586b\u5145 CityBreaksUser \u5bf9\u8c61\u7684\u96c6\u5408\u3002<\/p>\n<p>\u6e05\u5355 10.15 \u5e94\u7528\u7a0b\u5e8f\u7684 claims manager \u90e8\u5206\u7684 IndexModel \u7c7b<\/p>\n<pre><code>using CityBreaks.Models;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace CityBreaks.Pages.ClaimsManager\n{\n    public class IndexModel : PageModel\n    {\n        public UserManager&lt;CityBreaksUser&gt; UserManager { get; set; }\n        public IndexModel(UserManager&lt;CityBreaksUser&gt; userManager)\n        {\n            UserManager = userManager; \n        }\n        public List&lt;CityBreaksUser&gt; Users { get; set; }\n        public async Task OnGetAsync()\n        {\n            Users = await UserManager.Users.ToListAsync();\n        }\n    }\n}<\/code><\/pre>\n<p>Razor \u9875\u9762\u5faa\u73af\u8bbf\u95ee\u7528\u6237\u96c6\u5408\uff0c\u5e76\u901a\u8fc7 UserManager.GetClaimsAsync \u65b9\u6cd5\u83b7\u53d6\u5176\u58f0\u660e\u3002\u6b64\u65b9\u6cd5\u4e0e\u6570\u636e\u5b58\u50a8\u901a\u4fe1\uff0c\u56e0\u6b64\u5b83\u4ec5\u8fd4\u56de\u5df2\u5b58\u50a8\u5728 AspNetUserClaims \u8868\u5185\u7684\u6570\u636e\u5e93\u4e2d\u7684\u58f0\u660e\u3002\u751f\u6210\u7684\u6570\u636e\u4e0d\u5305\u62ec\u7531\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u7b49\u5206\u914d\u7684\u58f0\u660e\u3002\u5982\u679c\u627e\u5230\u4efb\u4f55\u5b58\u50a8\u7684\u58f0\u660e\uff0c\u5219\u4f1a\u5728\u5c4f\u5e55\u4e0a\u5448\u73b0\u5b83\u4eec\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>\u6e05\u5355 10.16 ClaimsManager \u7d22\u5f15\u9875\u9762<\/p>\n<pre><code>@page\n@model CityBreaks.Pages.ClaimsManager.IndexModel\n@{\n    ViewData[&quot;Title&quot;] = &quot;User Claims&quot;;\n}\n&lt;h4&gt;User Claims&lt;\/h4&gt;\n&lt;a class=&quot;btn btn-success&quot; asp-page=&quot;\/ClaimsManager\/Assign&quot;&gt;New&lt;\/a&gt;\n@foreach (var user in Model.Users)\n{\n    var claims = await Model.UserManager.GetClaimsAsync(user);\n    if (claims.Any())\n    {\n        &lt;h5&gt;@user.UserName&lt;\/h5&gt;\n        &lt;table class=&quot;table-striped col-12&quot;&gt;\n            &lt;tr&gt;\n                &lt;th&gt;Type&lt;\/th&gt;\n                &lt;th&gt;Value&lt;\/th&gt;\n                &lt;th&gt;Issuer&lt;\/th&gt;\n            &lt;\/tr&gt;\n            @foreach (var claim in claims)\n            {\n                &lt;tr&gt;\n                    &lt;td&gt;@claim.Type&lt;\/td&gt;\n                    &lt;td&gt;@claim.Value&lt;\/td&gt;\n                    &lt;td&gt;@claim.Issuer&lt;\/td&gt;\n                &lt;\/tr&gt;\n            }\n        &lt;\/table&gt;\n    }\n}<\/code><\/pre>\n<p>\u503c\u5f97\u6ce8\u610f\u7684\u662f\uff0c\u524d\u9762\u7684\u4ee3\u7801\u5305\u542b\u4e00\u4e9b\u60a8\u5e94\u8be5\u907f\u514d\u7528\u4e8e\u751f\u4ea7\u5e94\u7528\u7a0b\u5e8f\u7684\u5185\u5bb9\u3002\u8fd9\u662f N + 1 \u95ee\u9898\u7684\u4e00\u4e2a\u793a\u4f8b\uff0c\u4e4b\u6240\u4ee5\u8fd9\u6837\u79f0\u547c\uff0c\u662f\u56e0\u4e3a\u4ee3\u7801\u5bf9\u7528\u6237\u8fdb\u884c\u4e00\u6b21\u6570\u636e\u5e93\u8c03\u7528\uff08\u5728 OnGetAsync \u65b9\u6cd5\u4e2d\uff09\uff0c\u7136\u540e\u5bf9\u6570\u636e\u5e93\u8fdb\u884c N \u6b21\u8fdb\u4e00\u6b65\u8c03\u7528\uff0c\u5176\u4e2d N \u8868\u793a\u5728\u7b2c\u4e00\u6b21\u8c03\u7528\u4e2d\u68c0\u7d22\u5230\u7684\u7ed3\u679c\u6570\u3002\u6bcf\u6b21\u6267\u884c GetClaimsAsync \u65f6\uff0c\u90fd\u4f1a\u53d1\u51fa\u4e00\u4e2a\u6570\u636e\u5e93\u67e5\u8be2\u3002\u6839\u636e\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u5982\u679c\u60a8\u6709\u5927\u91cf\u6570\u636e\u548c\/\u6216\u5e76\u53d1\u7528\u6237\uff0c\u8fd9\u53ef\u80fd\u4f1a\u4e25\u91cd\u635f\u5bb3\u6027\u80fd\u3002\u5982\u679c\u60a8\u53d1\u73b0\u81ea\u5df1\u9700\u8981\u8fed\u4ee3\u6240\u6709\u7528\u6237\u7684\u58f0\u660e\uff0c\u60a8\u5e94\u8be5\u8003\u8651\u7f16\u5199\u81ea\u5df1\u7684 SQL \u4ee5\u5728\u4e00\u6b21\u8c03\u7528\u4e2d\u83b7\u53d6\u6240\u6709\u76f8\u5173\u6570\u636e\u3002<\/p>\n<p>\u9996\u6b21\u8fd0\u884c\u6b64\u9875\u9762\u65f6\uff0c\u5c06\u8fdb\u884c\u6240\u6709\u6570\u636e\u5e93\u8c03\u7528\uff0c\u4f46\u6ca1\u6709\u8981\u663e\u793a\u7684\u6570\u636e\uff0c\u56e0\u6b64\u60a8\u53ea\u4f1a\u770b\u5230\u9080\u8bf7\u60a8\u6dfb\u52a0\u65b0\u58f0\u660e\u7684\u6309\u94ae\u3002\u76ee\u524d\u5b83\u65e0\u5904\u53ef\u53bb\uff0c\u56e0\u4e3a\u60a8\u5c1a\u672a\u521b\u5efa\u9875\u9762\u3002<\/p>\n<p>\u5c06\u540d\u4e3a Assign \u7684\u65b0\u9875\u9762\u6dfb\u52a0\u5230 ClaimsManager \u6587\u4ef6\u5939\u4e2d\u3002\u6b64\u9875\u9762\u5c06\u63d0\u4f9b\u9009\u62e9\u5217\u8868\u4e2d\u7684\u7528\u6237\u5217\u8868\u4ee5\u53ca\u58f0\u660e\u7c7b\u578b\u548c\u503c\u7684\u8f93\u5165\u3002\u60a8\u5c06\u4f7f\u7528\u6b64\u9875\u9762\u521b\u5efa\u58f0\u660e\u5e76\u5c06\u5176\u5206\u914d\u7ed9\u7528\u6237\u3002UserManager \u88ab\u6ce8\u5165\u5230 AssignModel \u6784\u9020\u51fd\u6570\u4e2d\uff0c\u5e76\u7528\u4e8e\u586b\u5145\u5305\u542b\u6bcf\u4e2a\u7528\u6237\u7684 Id \u548c\u540d\u79f0\u7684 SelectList\u3002\u6240\u9009\u5185\u5bb9\u5c06\u7ed1\u5b9a\u5230 SelectedUserId \u5c5e\u6027\u3002\u6dfb\u52a0\u4e86\u4e24\u4e2a\u8fdb\u4e00\u6b65\u7684\u7ed1\u5b9a\u5c5e\u6027\uff0c\u8868\u793a\u58f0\u660e\u7c7b\u578b\u548c\u503c\u3002<\/p>\n<p>\u6e05\u5355 10.17 \u7528\u4e8e\u5411\u7528\u6237\u6dfb\u52a0\u58f0\u660e\u7684 AssignModel \u4ee3\u7801<\/p>\n<pre><code>using CityBreaks.Models;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.RazorPages;\nusing Microsoft.AspNetCore.Mvc.Rendering;\nusing Microsoft.EntityFrameworkCore;\nusing System.ComponentModel.DataAnnotations;\nusing System.Security.Claims;\n\nnamespace CityBreaks.Pages.ClaimsManager\n{\n    public class AssignModel : PageModel\n    {\n        private readonly UserManager&lt;CityBreaksUser&gt; _userManager;\n        public AssignModel(UserManager&lt;CityBreaksUser&gt; userManager)\n        {\n            _userManager = userManager;\n        }\n\n        public SelectList Users { get; set; }\n        [BindProperty, Required, Display(Name = &quot;User&quot;)]\n        public string SelectedUserId { get; set; }\n        [BindProperty, Required, Display(Name =&quot;Claim Type&quot;)]\n        public string ClaimType { get; set; }\n        [BindProperty, Display(Name = &quot;Claim Value&quot;)]\n        public string ClaimValue { get; set; }\n        public async Task OnGetAsync()\n        {\n            await GetOptions();\n        }\n\n        public async Task&lt;IActionResult&gt; OnPostAsync()\n        {\n            if (ModelState.IsValid)\n            {\n                var claim = new Claim(ClaimType, ClaimValue ?? String.Empty);\n                var user = await _userManager.FindByIdAsync(SelectedUserId);\n                await _userManager.AddClaimAsync(user, claim);\n                return RedirectToPage(&quot;\/ClaimsManager\/Index&quot;);\n            }\n            await GetOptions();\n            return Page();\n        }\n\n        public async Task GetOptions()\n        {\n            var users = await _userManager.Users.ToListAsync();\n            Users = new SelectList(users, \n            \u27a5 nameof(CityBreaksUser.Id), nameof(CityBreaksUser.UserName));\n        }\n    }\n}<\/code><\/pre>\n<p>\u4f7f\u7528 UserManager \u7684 AddClaimAsync \u65b9\u6cd5\u5c06\u5176\u4ed6\u58f0\u660e\u5206\u914d\u7ed9\u7528\u6237\u3002\u5b83\u91c7\u7528 user \u548c claim \u4f5c\u4e3a\u53c2\u6570\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 bound \u5c5e\u6027\u6765\u6784\u9020\u8fd9\u4e9b\u5c5e\u6027\u3002\u8fd9\u4e00\u6b21\uff0c\u7531\u4e8e\u60a8\u5c06\u7528\u6237\u7684\u552f\u4e00\u6807\u8bc6\u7b26\u7ed1\u5b9a\u5230\u9009\u62e9\u5217\u8868\uff0c\u56e0\u6b64\u60a8\u4f7f\u7528 FindByIdAsync \u65b9\u6cd5\u4ece UserManager \u83b7\u53d6\u7528\u6237\u3002\u8bf7\u8bb0\u4f4f\uff0c\u60a8\u4e4b\u524d\u4f7f\u7528\u8fc7 FindByNameAsync\u3002\u60a8\u6839\u636e\u4f20\u5165\u7684\u7c7b\u578b\u548c\u503c\u6784\u9020\u65b0\u58f0\u660e\u3002\u58f0\u660e\u4e0d\u5fc5\u5206\u914d\u503c\uff0c\u4f46\u8be5\u503c\u4e0d\u80fd\u4e3a null\uff0c\u56e0\u6b64\u5982\u679c\u672a\u63d0\u4f9b\u503c\uff0c\u5219\u4f20\u5165 String.Empty\u3002\u6dfb\u52a0\u58f0\u660e\u540e\uff0c\u60a8\u5c06\u88ab\u5b9a\u5411\u5230 Index \u9875\u9762\uff0c\u60a8\u53ef\u4ee5\u5728\u5176\u4e2d\u770b\u5230\u663e\u793a\u7684\u65b0\u58f0\u660e\u3002<\/p>\n<p>\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u5bfc\u822a\u5230 \/claims-manager \/assign\u3002\u5411 anna@test.com \u6dfb\u52a0\u65b0\u58f0\u660e\u3002type \u5e94\u8be5\u662f Admin\uff0c\u503c\u5e94\u8be5\u7559\u7a7a\uff08\u56fe 10.5\uff09\u3002\u5206\u914d\u58f0\u660e\u540e\uff0c\u4e0b\u4e00\u6b65\u662f\u5c06\u5176\u7528\u4f5c\u6388\u6743\u7b56\u7565\u7684\u4e00\u90e8\u5206\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1005.png\" ><\/p>\n<p>\u56fe 10.5 \u5206\u914d\u7ed9\u7528\u6237\u7684\u58f0\u660e\u5217\u8868<\/p>\n<h3>10.3.2 \u4f7f\u7528\u7b56\u7565\u5f3a\u5236\u5b9e\u65bd\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743<\/h3>\n<p>\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u4f9d\u8d56\u4e8e\u7b56\u7565\uff0c\u6211\u4e4b\u524d\u5df2\u7ecf\u63d0\u5230\u8fc7\u3002\u7b56\u7565\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u8981\u6c42\u7ec4\u6210\u3002\u5f53\u7b56\u7565\u4e2d\u7684\u6240\u6709\u8981\u6c42\u90fd\u5f97\u5230\u6ee1\u8db3\u65f6\uff0c\u5c06\u6388\u4e88\u6388\u6743\u3002\u4e00\u4e2a\u6216\u591a\u4e2a\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u7684\u5de5\u4f5c\u662f\u8bc4\u4f30\u7b56\u7565\u4e2d\u7684\u6bcf\u4e2a\u9700\u6c42\u662f\u5426\u5f97\u5230\u6ee1\u8db3\uff08\u56fe 10.6\uff09\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1006.png\" ><\/p>\n<p>\u56fe 10.6 \u7b56\u7565\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u9700\u6c42\u7ec4\u6210\uff0c\u6bcf\u4e2a\u9700\u6c42\u90fd\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>\u4f7f\u7528\u6b64\u6a21\u5f0f\uff0c\u53ef\u4ee5\u6784\u5efa\u590d\u6742\u7684\u6388\u6743\u7b56\u7565\uff0c\u4ece\u800c\u5bf9\u8c01\u53ef\u4ee5\u8bbf\u95ee\u5e94\u7528\u7a0b\u5e8f\u7684\u54ea\u4e9b\u90e8\u5206\u8fdb\u884c\u7cbe\u7ec6\u63a7\u5236\u3002\u9664\u4e86\u4fdd\u62a4\u7aef\u70b9\u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u5728 Razor \u9875\u9762\u672c\u8eab\u5185\u5e94\u7528\u6388\u6743\u7b56\u7565\uff0c\u56e0\u6b64\uff0c\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u6839\u636e\u5f53\u524d\u7528\u6237\u7684\u58f0\u660e\u5207\u6362 UI \u90e8\u5206\u7684\u53ef\u89c1\u6027\u3002<\/p>\n<p>\u4e4b\u524d\u4f7f\u7528 AuthorizationPolicyBuilder.RequireRole \u65b9\u6cd5\u65f6\uff0c\u5c06\u521b\u5efa\u4e00\u4e2a RolesAuthorizationRequirement \u7c7b\u578b\u7684\u8981\u6c42\uff0c\u8be5\u8981\u6c42\u6307\u5b9a\u9700\u8981\u6307\u5b9a\u7684\u89d2\u8272\u3002AuthorizationPolicyBuilder\u4e0a\u63d0\u4f9b\u4e86\u5176\u4ed6\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4f7f\u60a8\u53ea\u9700\u4f7f\u7528\u5176\u4ed6\u5185\u7f6e\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u5373\u53ef\u8868\u8fbe\u901a\u7528\u7b56\u7565\uff08\u8868 10.2\uff09\u3002<\/p>\n<p>\u8868 10.2 \u6784\u5efa\u7b80\u5355\u7b56\u7565\u7684\u5e38\u7528\u65b9\u6cd5<\/p>\n<table border=\"1\" class=\"contenttable\" width=\"100%\">\n<colgroup class=\"calibre29\">\n<col class=\"calibre30\" span=\"1\" width=\"50%\">\n<col class=\"calibre30\" span=\"1\" width=\"50%\">\n<\/colgroup>\n<tbody>\n<tr class=\"calibre31\">\n<th class=\"fm-contenttable1\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-head\"><a id=\"calibre_link-6620\"><\/a>Method<\/p>\n<\/th>\n<th class=\"fm-contenttable1\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-head\"><a id=\"calibre_link-6621\"><\/a>Description<\/p>\n<\/th>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6622\"><\/a><span class=\"fm-code-in-text1\">RequireClaim(string claimtype<\/span><a id=\"calibre_link-2394\"><\/a><span class=\"fm-code-in-text1\">)<\/span><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6623\"><\/a>The user must have the specified claim.<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6624\"><\/a><span class=\"fm-code-in-text1\">RequireClaim(string claimtype, params string[] allowedValues<\/span><a id=\"calibre_link-356\"><\/a><span class=\"fm-code-in-text1\">)<\/span><\/p>\n<p class=\"fm-table-body\"><a id=\"calibre_link-6625\"><\/a>or<\/p>\n<p class=\"fm-table-body\"><a id=\"calibre_link-6626\"><\/a><span class=\"fm-code-in-text1\">RequireClaim(string claimtype, IEmumerable&lt;string&gt; allowedValues<\/span><a id=\"calibre_link-2393\"><\/a><span class=\"fm-code-in-text1\">)<\/span><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6627\"><\/a>The user must have the specified claim with one of the specified values.<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6628\"><\/a><span class=\"fm-code-in-text1\">RequireUserName<\/span><a id=\"calibre_link-2412\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6629\"><\/a>The user must have the specified name.<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6630\"><\/a><span class=\"fm-code-in-text1\">RequireAuthenticatedUser<\/span><a id=\"calibre_link-2389\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6631\"><\/a>The user must be authenticated.<\/p>\n<\/td>\n<\/tr>\n<tr class=\"calibre31\">\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6632\"><\/a><span class=\"fm-code-in-text1\">RequireAssertion<\/span><a id=\"calibre_link-2387\"><\/a><\/p>\n<\/td>\n<td class=\"fm-contenttable2\" colspan=\"1\" rowspan=\"1\">\n<p class=\"fm-table-body\"><a id=\"calibre_link-6633\"><\/a>Takes a delegate that represents an assertion to be tested to determine authorization status.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>RequireClaim \u65b9\u6cd5\u7684\u53d8\u4f53\u521b\u5efa\u4e00\u4e2a ClaimsAuthorizationRequirement\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f\uff0c\u5982\u679c\u6307\u5b9a\u7684\u58f0\u660e\u5b58\u5728\uff0c\u5219\u8fd4\u56de true\uff0c\u5982\u679c\u6307\u5b9a\u4e86\u503c\uff0c\u5219\u81f3\u5c11\u627e\u5230\u5176\u4e2d\u4e00\u4e2a\u503c\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u66f4\u6539\u73b0\u6709\u7b56\u7565\u7684\u4ee3\u7801\u4ee5\u4f7f\u7528 RequireClaim \u65b9\u6cd5\u800c\u4e0d\u662f RequireRole \u6765\u6d4b\u8bd5\u8fd9\u4e00\u70b9\uff1a<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt;\n{\n    options.AddPolicy(&quot;AdminPolicy&quot;, policyBuilder =&gt; \n    \u27a5 policyBuilder.RequireClaim(&quot;Admin&quot;));\n});<\/code><\/pre>\n<p>\u60a8\u8fd8\u53ef\u4ee5\u901a\u8fc7\u5c06\u7b56\u7565\u540d\u79f0\u4f20\u9012\u7ed9 AuthorizeAttribute \u7684 Policy \u5c5e\u6027\uff0c\u5c06\u6b64\u7b56\u7565\u5355\u72ec\u5e94\u7528\u4e8e\u9875\u9762\uff1a<\/p>\n<pre><code>[Authorize(Policy=&quot;AdminPolicy&quot;)]\npublic IndexModel : PageModel\n{\n    ...\n}<\/code><\/pre>\n<h3>10.3.3 \u5c06\u65ad\u8a00\u7528\u4e8e\u66f4\u590d\u6742\u7684\u8981\u6c42<\/h3>\n<p>\u63d0\u4f9b RequireAssertion \u65b9\u6cd5\u662f\u4e3a\u4e86\u5904\u7406\u6bd4\u5176\u4ed6\u65b9\u6cd5\u6240\u80fd\u5904\u7406\u7684\u66f4\u590d\u6742\u7684\u8981\u6c42\u3002\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u8981\u5b9e\u65bd\u4e00\u9879\u8981\u6c42\uff0c\u89c4\u5b9a\u5982\u679c\u7528\u6237\u5177\u6709\u5177\u6709\u7279\u5b9a\u503c\u7684\u58f0\u660e\uff0c\u5219\u7528\u6237\u53ef\u4ee5\u8bbf\u95ee\u89d2\u8272\u7ba1\u7406\u533a\u57df\uff0c\u4f46\u524d\u63d0\u662f\u4ed6\u4eec\u5df2\u7ecf\u5728\u516c\u53f8\u5de5\u4f5c\u4e86\u516d\u4e2a\u6708\u4ee5\u4e0a\u3002\u4e3a\u4e86\u80fd\u591f\u786e\u5b9a\u8fd9\u4e00\u70b9\uff0c\u60a8\u9700\u8981\u5c06\u7528\u6237\u7684\u52a0\u5165\u65e5\u671f\u8bb0\u5f55\u4e3a\u7d22\u8d54\u3002\u7136\u540e\uff0c\u60a8\u9700\u8981\u5c06\u8be5\u503c\u8f6c\u6362\u4e3a DateTime \u5e76\u5c06\u5176\u4e0e\u5f53\u524d\u65e5\u671f\u8fdb\u884c\u6bd4\u8f83\uff0c\u4ee5\u786e\u5b9a\u7528\u6237\u5728\u4f01\u4e1a\u5de5\u4f5c\u7684\u65f6\u95f4\u3002<\/p>\n<p>\u4e3a\u4e86\u8bc1\u660e\u8fd9\u4e00\u70b9\uff0c\u8bf7\u68c0\u67e5\u56fe 10.7 \u4e2d\u6240\u793a\u7684\u58f0\u660e\u3002\u8bf7\u6ce8\u610f\uff0c\u5728\u64b0\u5199\u672c\u6587\u65f6\uff0cPaul \u7684\u52a0\u5165\u65e5\u671f\u4e0d\u5230 6 \u4e2a\u6708\uff0c\u800c\u5176\u4ed6\u7528\u6237\u7684\u52a0\u5165\u65e5\u671f\u5219\u8d85\u8fc7 6 \u4e2a\u6708\u3002\u5982\u679c\u8981\u590d\u5236\u6b64\u7ec3\u4e60\uff0c\u8bf7\u52a1\u5fc5\u8f93\u5165\u6ee1\u8db3\u76f8\u540c\u6761\u4ef6\u7684\u65e5\u671f\u3002\u53ea\u6709 Anna \u548c Paul \u5177\u6709\u503c\u4e3a View Roles \u7684 Permission \u58f0\u660e\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1007.png\" ><\/p>\n<p>\u56fe 10.7 \u5206\u914d\u7ed9\u7528\u6237\u7684\u52a0\u5165\u65e5\u671f\u548c\u6743\u9650\u58f0\u660e<\/p>\n<p>RequireAssertion \u65b9\u6cd5\u5c06 AuthorizationHandlerContext \u4f5c\u4e3a\u53c2\u6570\uff0c\u5982\u6e05\u5355 10.18 \u6240\u793a\u3002\u6b64\u7c7b\u578b\u901a\u8fc7\u5176 User \u5c5e\u6027\u63d0\u4f9b\u5bf9\u5f53\u524d\u7528\u6237\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4ece\u90a3\u91cc\uff0c\u60a8\u53ef\u4ee5\u68c0\u67e5\u4ed6\u4eec\u7684\u4e3b\u5f20\u3002\u5728\u4e0b\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u786e\u4fdd\u7528\u6237\u5177\u6709\u540d\u4e3a Permission \u7684\u58f0\u660e\uff0c\u5e76\u4e14\u5176\u503c\u4e3a View Roles\u3002\u7136\u540e\uff0c\u60a8\u5c1d\u8bd5\u68c0\u7d22\u540d\u4e3a Joining Date \u7684\u58f0\u660e\u7684\u503c\u5e76\u5c06\u5176\u8f6c\u6362\u4e3a DateTime\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u6839\u636e\u6388\u6743\u8981\u6c42\u6d4b\u8bd5\u5176\u503c\u3002<\/p>\n<p>Listing 10.18 RequireAssertion \u7528\u4e8e\u66f4\u590d\u6742\u7684\u6388\u6743\u9700\u6c42<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt;\n{\n    options.AddPolicy(&quot;ViewRolesPolicy&quot;, policyBuilder =&gt; \n        policyBuilder.RequireAssertion(context =&gt;               \u2776\n        {\n            var joiningDateClaim = context.User.FindFirst(c =&gt;  \u2777\n            \u27a5 c.Type == &quot;Joining Date&quot;)?.Value;                \u2777\n            var joiningDate = Convert.ToDateTime(               \u2777\n            \u27a5 joiningDateClaim);                               \u2777\n            return context.User.HasClaim(&quot;Permission&quot;, \n            \u27a5 &quot;View Roles&quot;) &amp;&amp;                                 \u2778\n                joiningDate &gt; DateTime.MinValue &amp;&amp;              \u2779\n                joiningDate &lt; DateTime.Now.AddMonths(-6);       \u2779\n    }));\n});<\/code><\/pre>\n<p>\u2776 \u4f7f\u7528 RequireAssertion \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06 AuthorizationHandlerContext \u4f5c\u4e3a\u53c2\u6570\uff0c\u4e3a\u5f53\u524d\u7528\u6237\u63d0\u4f9b\u8bbf\u95ee\u6743\u9650\u3002<br \/>\n\u2777 \u4f7f\u7528 FindFirst \u65b9\u6cd5\u8bbf\u95ee\u58f0\u660e\u5e76\u83b7\u53d6\u5176\u503c\uff08\u5982\u679c\u6709\uff09\u5e76\u5c06\u5176\u8f6c\u6362\u4e3a DateTime\u3002<br \/>\n\u2778 \u4f7f\u7528 HasClaim \u65b9\u6cd5\u786e\u5b9a\u5b58\u5728\u5177\u6709\u6307\u5b9a\u503c\u7684\u58f0\u660e\u3002<br \/>\n\u2779 \u5c06\u8054\u63a5\u65e5\u671f\u503c\u4e0e DateTime.MinValue \u4e0e\u5f53\u524d\u65e5\u671f\u8fdb\u884c\u6bd4\u8f83\uff0c\u4ee5\u786e\u4fdd\u58f0\u660e\u4e0d\u4e3a null\uff0c\u5e76\u4e14\u65e5\u671f\u65e9\u4e8e 6 \u4e2a\u6708\u524d\u3002<\/p>\n<p>\u5185\u7f6e\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u5e94\u6db5\u76d6\u6700\u5e38\u89c1\u7684\u6388\u6743\u8981\u6c42\u3002\u5982\u679c\u4f60\u6709\u5f88\u591a\u590d\u6742\u7684\u6388\u6743\u7b56\u7565\u8981\u5e94\u7528\u4e8e\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f60\u7684 Program \u7c7b\u5c06\u5f88\u5feb\u88ab\u591a\u4e2a\u65ad\u8a00\u586b\u6ee1\u3002\u6b64\u65f6\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u7f16\u5199\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\uff0c\u5c06\u4ee3\u7801\u4ece\u6388\u6743\u914d\u7f6e\u4e2d\u79fb\u51fa\u5e76\u79fb\u52a8\u5230\u5355\u72ec\u7684\u7c7b\u4e2d\u3002<\/p>\n<h3>10.3.4 \u81ea\u5b9a\u4e49\u6388\u6743\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f<\/h3>\n<p>\u6388\u6743\u8981\u6c42\u7c7b\u5b9e\u73b0 IAuthorizationRequirement \u63a5\u53e3\u3002\u5b83\u662f\u4e00\u4e2a\u7a7a\u7684\u6807\u8bb0\u63a5\u53e3\uff0c\u6ca1\u6709\u5b9a\u4e49\u4efb\u4f55\u6210\u5458\u3002\u5904\u7406\u7a0b\u5e8f\u7531 IAuthorizationHandler \u63a5\u53e3\u8868\u793a\uff0c\u8be5\u63a5\u53e3\u5b9a\u4e49 HandleAsync \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06 AuthorizationHandlerContext \u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u5e76\u8fd4\u56de Task\u3002\u5904\u7406\u9700\u6c42\u7684\u903b\u8f91\u4f4d\u4e8e\u6b64\u65b9\u6cd5\u4e2d\u3002<\/p>\n<p>\u8981\u6c42\u53ef\u4ee5\u6709\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\uff0c\u4f46\u662f\u5982\u679c\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u4e4b\u95f4\u5b58\u5728\u4e00\u5bf9\u4e00\u7684\u5173\u7cfb\uff0c\u5219\u901a\u5e38\u4f1a\u770b\u5230\u4e24\u8005\u7684\u4ee3\u7801\u653e\u5728\u5b9e\u73b0\u4e24\u4e2a\u63a5\u53e3\u7684\u540c\u4e00\u7c7b\u4e2d\u3002\u4ee5\u4e0b\u793a\u4f8b\u8bf4\u660e\u4e86\u5982\u4f55\u5c06\u60a8\u4e4b\u524d\u521b\u5efa\u7684\u65ad\u8a00\u8fc1\u79fb\u5230\u6b64\u7c7b\u4e2d\uff0c\u8be5\u7c7b\u91c7\u7528\u8868\u793a\u6708\u6570\u7684\u53c2\u6570\u3002\u5c06\u540d\u4e3a AuthorizationRequired \u7684\u65b0\u6587\u4ef6\u5939\u6dfb\u52a0\u5230\u9879\u76ee\u4e2d\uff0c\u7136\u540e\u4f7f\u7528\u4e0b\u9762\u6e05\u5355\u4e2d\u7684\u4ee3\u7801\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ViewRolesRequirement \u7684\u65b0\u7c7b\u3002<\/p>\n<p>Listing 10.19 \u5e26\u6709\u5185\u7f6e handler \u7684\u81ea\u5b9a\u4e49\u9700\u6c42<\/p>\n<pre><code>using Microsoft.AspNetCore.Authorization;\n\nnamespace CityBreaks.AuthorizationRequirements\n{\n    public class ViewRolesRequirement : \n    \u27a5 IAuthorizationRequirement, IAuthorizationHandler                \u2776\n    {\n        public int Months { get; }                                     \u2777\n        public ViewRolesRequirement(int months)                        \u2777\n        {                                                              \u2777\n            Months = months &gt; 0 ? 0 : months;                          \u2777\n        }                                                              \u2777\n\n        public Task HandleAsync(                                       \u2778\n        \u27a5 AuthorizationHandlerContext context)                        \u2778\n        {\n\n            var joiningDateClaim = context.User.                       \u2779\n            \u27a5 FindFirst(c =&gt; c.Type == &quot;Joining Date&quot;)?.Value;        \u2779\n            if(joiningDateClaim == null)                               \u2779\n            {                                                          \u2779\n                return Task.CompletedTask;                             \u2779\n            }                                                          \u2779\n            var joiningDate = Convert.ToDateTime(                      \u277a\n            \u27a5 joiningDateClaim);                                      \u277a\n            if(context.User.HasClaim(&quot;Permission&quot;,                     \u277a\n            \u27a5 &quot;View Roles&quot;) &amp;&amp;                                        \u277a\n                joiningDate &gt; DateTime.MinValue &amp;&amp;                     \u277a\n                joiningDate &lt; DateTime.Now.AddMonths(                  \u277a\n                \u27a5 Months))                                            \u277a\n            {                                                          \u277a\n                context.Succeed(this);                                 \u277a\n            }                                                          \u277a\n            return Task.CompletedTask;                                 \u277b\n        }\n    }\n}<\/code><\/pre>\n<p>\u2776 \u8be5\u7c7b\u540c\u65f6\u5b9e\u73b0 IAuthorizationRequirement \u548c IAuthorizationHandler \u63a5\u53e3\u3002<br \/>\n\u2777 \u6784\u9020\u51fd\u6570\u5c06 int \u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u786e\u4fdd\u5b83\u4e0d\u662f\u6b63\u6570\u3002<br \/>\n\u2778 HandleAsync \u65b9\u6cd5\u662f\u6839\u636e IAuthorization-Handler \u63a5\u53e3\u7684\u8981\u6c42\u5b9e\u73b0\u7684\u3002<br \/>\n\u2779 \u68c0\u67e5\u7528\u6237\u4ee5\u67e5\u770b\u4ed6\u4eec\u662f\u5426\u5177\u6709 joiningDateClaim\u3002\u5426\u5219\uff0c\u5c06\u9000\u51fa\u5904\u7406\u7a0b\u5e8f\u3002<br \/>\n\u277a \u8bc4\u4f30\u52a0\u5165\u65e5\u671f\u4ee5\u67e5\u770b\u5b83\u662f\u5426\u5b58\u5728\uff0c\u4ee5\u53ca\u5176\u503c\u662f\u5426\u65e9\u4e8e\u4f20\u5165\u7684\u5e74\u9f84\u3002<br \/>\n\u277b \u5982\u679c\u4e0d\u6ee1\u8db3\u8981\u6c42\uff0c\u5219\u8fd4\u56de Task.CompletedTask \u4ee5\u6ee1\u8db3 HandleAsync \u65b9\u6cd5\u7b7e\u540d\u3002<\/p>\n<p>\u5982\u679c\u6807\u8bb0\u4e3a\u5df2\u6210\u529f\u8bc4\u4f30\uff0c\u5219\u6ee1\u8db3\u8be5\u8981\u6c42\u3002\u8fd9\u662f\u901a\u8fc7\u8c03\u7528 AuthorizationHandlerContext \u7c7b\u7684 Succeed \u65b9\u6cd5\u5b9e\u73b0\u7684\u3002\u6b64\u7c7b\u8fd8\u63d0\u4f9b Fail \u65b9\u6cd5\uff0c\u60a8\u53ef\u4ee5\u8c03\u7528\u8be5\u65b9\u6cd5\u4ee5\u786e\u4fdd\u6388\u6743\u4e0d\u6210\u529f\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u7684\u5904\u7406\u7a0b\u5e8f\u5141\u8bb8\u9664\u6ee1\u8db3\u6307\u5b9a\u6761\u4ef6\u7684\u7528\u6237\u4ee5\u5916\u7684\u6240\u6709\u7528\u6237\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528\u6b64\u65b9\u6cd5\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 PolicyBuilder \u6ce8\u518c\u7b56\u7565\uff0c\u4e3a months \u53c2\u6570\u4f20\u5165\u5408\u9002\u7684\u503c\u3002<\/p>\n<p>\u6e05\u5355 10.20 \u6ce8\u518c\u81ea\u5b9a\u4e49\u9700\u6c42<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt;\n{\n    options.AddPolicy(&quot;ViewRolesPolicy&quot;, policyBuilder =&gt; \n        policyBuilder.AddRequirements(new ViewRolesRequirement(months: -6)));\n});<\/code><\/pre>\n<h2>\u521b\u5efa\u5355\u72ec\u7684\u5904\u7406\u7a0b\u5e8f\u7c7b<\/h2>\n<p>\u5bf9\u4e8e\u7b80\u5355\u7684\u7528\u4f8b\uff0c\u6784\u5efa\u7ec4\u5408\u7684\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u5f88\u597d\uff0c\u4f46\u66f4\u5e38\u89c1\u7684\u662f\uff0c\u60a8\u53ef\u80fd\u5e0c\u671b\u5c06\u5904\u7406\u7a0b\u5e8f\u521b\u5efa\u4e3a\u5355\u72ec\u7684\u7c7b\u4ee5\u5b9e\u73b0\u91cd\u7528\u3002\u6267\u884c\u6b64\u4f5c\u65f6\uff0c\u9700\u8981\u5bf9\u5e38\u89c4\u65b9\u6cd5\u8fdb\u884c\u4e00\u4e9b\u66f4\u6539\u3002\u73b0\u6709\u8981\u6c42\u672c\u8eab\u88ab\u7f29\u51cf\u4e3a\u4ec5 IAuthorizationRequirement \u7684\u5b9e\u73b0\u3002<\/p>\n<p>Listing 10.21 \u72ec\u7acb\u9700\u6c42\u7c7b<\/p>\n<pre><code>public class ViewRolesRequirement : IAuthorizationRequirement\n{\n    public int Months { get; }\n    public ViewRolesRequirement(int months)\n    {\n        Months = months &gt; 0 ? 0 : months;\n    }\n}<\/code><\/pre>\n<p>\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a AuthorizationHandlers \u7684\u65b0\u6587\u4ef6\u5939\uff0c\u5e76\u5411\u5176\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ViewRolesHandler \u7684\u65b0\u7c7b\u3002\u8fd9\u662f\u5355\u72ec\u7684 handler \u7c7b\u3002\u5b83\u5b9e\u73b0 IAuthorizationHandler\u3002\u7531\u4e8e\u5904\u7406\u7a0b\u5e8f\u7c7b\u672c\u8eab\u7684\u8303\u56f4\u4e0d\u9650\u4e8e\u7279\u5b9a\u8981\u6c42\uff0c\u56e0\u6b64\u60a8\u5fc5\u987b\u8bbf\u95ee AuthorizationHandlerContext \u7684 PendingRequirements \u5c5e\u6027\uff0c\u4ee5\u7b5b\u9009\u51fa\u6b63\u786e\u7684\u8981\u6c42\u7c7b\u578b\u3002PendingRequirements \u5c5e\u6027\u83b7\u53d6\u5c1a\u672a\u6807\u8bb0\u4e3a\u6210\u529f\u7684\u6240\u6709\u8981\u6c42\u3002<\/p>\n<p>\u6e05\u5355 10.22 \u88ab\u5206\u79bb\u5230\u4e00\u4e2a\u7c7b\u4e2d\u7684 ViewRolesHandler<\/p>\n<pre><code>public class ViewRolesHandler : IAuthorizationHandler\n{\n    public Task HandleAsync(AuthorizationHandlerContext context)\n    {\n        foreach (var requirement in                         \u2776\n        \u27a5 context.PendingRequirements.ToList())            \u2776\n        {\n            if (requirement is ViewRolesRequirement req)    \u2777\n            {\n                var joiningDateClaim = \n                \u27a5 context.User.FindFirst(c =&gt; c.Type == \n                \u27a5 &quot;Joining Date&quot;)?.Value;\n                if (joiningDateClaim == null)\n                {\n                    return Task.CompletedTask;\n                }\n                var joiningDate = Convert.ToDateTime(joiningDateClaim);\n\n                if (context.User.HasClaim(&quot;Permission&quot;, &quot;View Roles&quot;) &amp;&amp;\n                        joiningDate &lt; DateTime.Now.AddMonths(req.Months))\n                {\n                    context.Succeed(requirement);\n                }\n            }\n        }\n        return Task.CompletedTask;\n    }\n}<\/code><\/pre>\n<p>\u2776 PendingRequirements \u8fd4\u56de\u6240\u6709\u672a\u6ee1\u8db3\u7684\u8981\u6c42\u3002\u9700\u8981\u5c06\u5b83\u4eec\u5206\u914d\u7ed9\u4e00\u4e2a\u5217\u8868\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u5bf9\u5b83\u4eec\u6267\u884c\u4f5c\u3002<br \/>\n\u2777 \u4f7f\u7528\u6a21\u5f0f\u5339\u914d\u6765\u8bc6\u522b ViewRolesRequirements \u5e76\u5c06\u5b83\u4eec\u5206\u914d\u7ed9\u5c40\u90e8\u53d8\u91cf\u3002<\/p>\n<p>\u6b64\u65b9\u6cd5\u4e0e\u7ec4\u5408\u9700\u6c42\u5904\u7406\u7a0b\u5e8f\u4e4b\u95f4\u7684\u6700\u540e\u4e00\u4e2a\u533a\u522b\u662f\uff0c\u60a8\u9700\u8981\u5c06\u5904\u7406\u7a0b\u5e8f\u6ce8\u518c\u5230 Service Container \u4e2d\uff0c\u4f5c\u4e3a IAuthorizationHandler \u7684\u5b9e\u73b0\uff1a<\/p>\n<pre><code>builder.Services.AddSingleton&lt;IAuthorizationHandler, ViewRolesHandler&gt;();<\/code><\/pre>\n<p>\u5b8c\u6210\u6b64\u4f5c\u540e\uff0c\u6388\u6743\u7b56\u7565\u7684\u5de5\u4f5c\u65b9\u5f0f\u4e0e\u4e4b\u524d\u91c7\u7528\u7ec4\u5408 requirement-handler \u7ec4\u5408\u7684\u65b9\u6cd5\u76f8\u540c\u3002<\/p>\n<h2>\u5bf9\u9700\u6c42\u4f7f\u7528\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f<\/h2>\n<p>\u6b63\u5982\u6211\u4e4b\u524d\u63d0\u5230\u7684\uff0c\u9700\u6c42\u53ef\u4ee5\u6709\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002\u5f53\u6709\u5176\u4ed6\u65b9\u6cd5\u53ef\u4ee5\u6ee1\u8db3\u8981\u6c42\u65f6\uff0c\u901a\u5e38\u662f\u8fd9\u79cd\u60c5\u51b5\u3002\u5047\u8bbe\u7528\u6237\u53ef\u4ee5\u67e5\u770b\u89d2\u8272\uff0c\u524d\u63d0\u662f\u4ed6\u4eec\u5177\u6709\u503c\u4e3a View Roles \u7684 Permission \u58f0\u660e\uff0c\u5e76\u4e14\u5df2\u5728\u516c\u53f8\u5de5\u4f5c\u81f3\u5c11 6 \u4e2a\u6708\uff0c\u6216\u8005\u4ed6\u4eec\u5904\u4e8e Admin \u89d2\u8272\u4e2d\u3002\u73b0\u5728\uff0c\u60a8\u6709\u4e24\u79cd\u66ff\u4ee3\u65b9\u6cd5\u6765\u6388\u6743\u7528\u6237\u3002\u60a8\u53ef\u4ee5\u5411\u73b0\u6709\u5904\u7406\u7a0b\u5e8f\u6dfb\u52a0\u66f4\u591a\u4ee3\u7801\u4ee5\u68c0\u67e5\u7528\u6237\u662f\u5426\u5728\u6307\u5b9a\u7684\u89d2\u8272\u4e2d\uff0c\u4f46\u968f\u7740\u65f6\u95f4\u7684\u63a8\u79fb\uff0c\u968f\u7740\u66f4\u591a\u66ff\u4ee3\u65b9\u6848\u7684\u51fa\u73b0\uff0c\u8be5\u4ee3\u7801\u53ef\u80fd\u4f1a\u53d8\u5f97\u4e00\u56e2\u7cdf\u3002\u76f8\u53cd\uff0c\u60a8\u5c06\u4e3a ViewRolesRequirements \u5b9e\u73b0\u4e00\u4e2a\u989d\u5916\u7684\u5904\u7406\u7a0b\u5e8f\u3002\u4f46\u662f\uff0c\u8fd9\u4e00\u6b21\uff0c\u60a8\u5c06\u91c7\u7528\u53e6\u4e00\u79cd\u65b9\u6cd5\u6765\u5236\u4f5c\u5904\u7406\u7a0b\u5e8f\uff0c\u8be5\u5904\u7406\u7a0b\u5e8f\u4e13\u95e8\u9488\u5bf9\u9700\u6c42\u8fdb\u884c\u7c7b\u578b\u5316\uff0c\u56e0\u6b64\u65e0\u9700\u8fc7\u6ee4\u6240\u6709\u5f85\u5904\u7406\u7684\u9700\u6c42\u3002<\/p>\n<p>\u60a8\u5c06\u4ece\u62bd\u8c61 <code>AuthorizationHandler&lt;TRequirement&gt;<\/code> \u7c7b\u6d3e\u751f\uff0c\u5176\u4e2d TRequirement \u8868\u793a\u5904\u7406\u7a0b\u5e8f\u6240\u9488\u5bf9\u7684\u9700\u6c42\u7c7b\u578b\u3002\u5904\u7406\u7a0b\u5e8f\u903b\u8f91\u653e\u7f6e\u5728\u91cd\u5199\u7684 HandleRequirementAsync \u65b9\u6cd5\u4e2d\uff0c\u8be5\u65b9\u6cd5\u9664\u4e86 AuthorizationHandlerContext \u4e4b\u5916\uff0c\u8fd8\u91c7\u7528\u8981\u6c42\u7c7b\u578b\u4f5c\u4e3a\u53c2\u6570\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u91cd\u6784\u4e3a\u540d\u4e3a HasClaimHandler \u7684 <code>AuthorizationHandler&lt;TRequirement&gt;<\/code> \u7c7b\u7684\u58f0\u660e\u68c0\u67e5\uff0c\u8be5\u7c7b\u4f4d\u4e8e\u540d\u4e3a AuthorizationHandlers \u7684\u6587\u4ef6\u5939\u4e2d\u3002<\/p>\n<p>\u6e05\u5355 10.23 \u5904\u7406\u6388\u6743\u9700\u6c42<\/p>\n<pre><code>using CityBreaks.AuthorizationRequirements;\nusing Microsoft.AspNetCore.Authorization;\n\nnamespace CityBreaks.AuthorizationHandlers\n{\n    public class HasClaimHandler : AuthorizationHandler&lt;ViewRolesRequirement&gt;\n    {\n        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, \n            ViewRolesRequirement req)\n        {\n            var joiningDateClaim = \n            \u27a5 context.User.FindFirst(c =&gt; c.Type == &quot;Joining Date&quot;)?.Value;\n            if (joiningDateClaim == null)\n            {\n                return Task.CompletedTask;\n            }\n            var joiningDate = Convert.ToDateTime(joiningDateClaim);\n\n            if (context.User.HasClaim(&quot;Permission&quot;, &quot;View Roles&quot;) &amp;&amp;\n                  joiningDate &lt; DateTime.Now.AddMonths(req.Months))\n            {\n                context.Succeed(req);\n            }\n            return Task.CompletedTask;\n        }\n    }\n}<\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\uff0c\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a IsInRoleHandler \u7684\u65b0\u7c7b\uff0c\u8be5\u7c7b\u8d1f\u8d23\u5904\u7406\u6388\u6743\u7684\u9644\u52a0\u6761\u4ef6\u3002\u8be5\u4ee3\u7801\u4e0e\u524d\u9762\u7684\u5904\u7406\u7a0b\u5e8f\u975e\u5e38\u76f8\u4f3c\u3002<\/p>\n<p>\u6e05\u5355 10.24 IsInRoleHandler<\/p>\n<pre><code>using CityBreaks.AuthorizationRequirements;\nusing Microsoft.AspNetCore.Authorization;\n\nnamespace CityBreaks.AuthorizationHandlers\n{\n    public class IsInRoleHandler : AuthorizationHandler&lt;ViewRolesRequirement&gt;\n    {\n        protected override Task \n        \u27a5 HandleRequirementAsync(AuthorizationHandlerContext context, \n            ViewRolesRequirement req)\n        {\n            if (context.User.IsInRole(&quot;Admin&quot;))\n            {\n                context.Succeed(req);\n            }\n            return Task.CompletedTask;\n        }\n    }\n}<\/code><\/pre>\n<p>\u8fd9\u4e24\u4e2a\u5904\u7406\u7a0b\u5e8f\u90fd\u9700\u8981\u5411\u670d\u52a1\u5bb9\u5668\u6ce8\u518c\uff1a<\/p>\n<pre><code>builder.Services.AddSingleton&lt;IAuthorizationHandler, IsInRoleHandler&gt;();\nbuilder.Services.AddSingleton&lt;IAuthorizationHandler, HasClaimHandler&gt;();<\/code><\/pre>\n<p>\u8fd9\u4e9b\u6ce8\u518c\u5e94\u66ff\u6362\u73b0\u6709\u7684\u5904\u7406\u7a0b\u5e8f\u6ce8\u518c;\u5426\u5219\uff0c\u5b83\u4e5f\u5c06\u88ab\u8bc4\u4f30\u3002\u5b9e\u73b0 IAuthorizationHandler \u7684\u5904\u7406\u7a0b\u5e8f\u5c06\u9488\u5bf9\u6bcf\u4e2a\u8981\u6c42\u8fdb\u884c\u5904\u7406\uff0c\u800c\u7c7b\u578b\u5316\u4e3a\u7279\u5b9a\u8981\u6c42\u7684\u5904\u7406\u7a0b\u5e8f\u4ec5\u9488\u5bf9\u8be5\u7c7b\u578b\u7684\u8981\u6c42\u6267\u884c\u3002<\/p>\n<p>\u8981\u6d4b\u8bd5\u6b64\u65b0\u5b89\u6392\uff0c\u8bf7\u4ece Anna \u4e2d\u5220\u9664 Permission \u58f0\u660e\uff0c\u4ee5\u4fbf\u5979\u4ec5\u5177\u6709 Admin \u89d2\u8272\u548c Joining date \u58f0\u660e\u3002\u60a8\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528\u6570\u636e\u5e93\u7ba1\u7406\u5de5\u5177\u6267\u884c\u6b64\u4f5c\u3002\u7136\u540e\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u4ee5\u5979\u7684\u8eab\u4efd\u767b\u5f55\u3002\u60a8\u5e94\u8be5\u4f1a\u53d1\u73b0\u5979\u4ecd\u7136\u80fd\u591f\u8bbf\u95ee Roles \u6587\u4ef6\u5939\u5185\u5bb9\u3002<\/p>\n<h3>10.3.5 \u89d2\u8272\u8fd8\u662f\u58f0\u660e\uff1f<\/h3>\n<p>\u6211\u4eec\u63a2\u7d22\u4e86\u4e24\u79cd\u65b9\u6cd5\u6765\u786e\u5b9a\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\uff1a\u57fa\u4e8e\u4ed6\u4eec\u6240\u5904\u7684\u89d2\u8272\u6216\u4ed6\u4eec\u62e5\u6709\u7684\u58f0\u660e\u3002\u4f46\u662f\u60a8\u5e94\u8be5\u9009\u62e9\u54ea\u79cd\u65b9\u6cd5\u5462\uff1f\u81ea Identity \u53d1\u5e03\u4e4b\u524d\uff0c\u89d2\u8272\u5c31\u4e00\u76f4\u662f ASP.NET \u7684\u4e00\u90e8\u5206\uff0c\u5f53\u65f6\u7528\u6237\u7ba1\u7406\u7cfb\u7edf\u56f4\u7ed5\u6210\u5458\u8d44\u683c\u6846\u67b6\u5c55\u5f00\u3002\u5b83\u4eec\u662f\u4e00\u4e2a\u975e\u5e38\u7b80\u5355\u6613\u638c\u63e1\u7684\u6982\u5ff5\uff0c\u4f46\u5b83\u4eec\u65e8\u5728\u4e0e\u7528\u6237\u7ec4\u4e00\u8d77\u4f7f\u7528\uff0c\u5e76\u65e8\u5728\u8868\u793a\u8fd9\u4e9b\u7528\u6237\u7ec4\u53ef\u4ee5\u6267\u884c\u7684\u4f5c\u3002\u5f15\u5165 Identity \u65f6\uff0c\u91cd\u70b9\u8f6c\u79fb\u5230\u57fa\u4e8e\u58f0\u660e\u7684\u58f0\u660e\u3002\u58f0\u660e\u63cf\u8ff0\u7684\u662f\u7528\u6237\u662f\u4ec0\u4e48\uff0c\u800c\u4e0d\u662f\u4ed6\u4eec\u53ef\u4ee5\u505a\u4ec0\u4e48\u3002\u751a\u81f3\u60a8\u4e00\u76f4\u5728\u4f7f\u7528\u7684 IsInRole \u65b9\u6cd5\u4e5f\u4f1a\u68c0\u67e5\u7279\u5b9a\u58f0\u660e\u3002<\/p>\n<p>\u4e00\u822c\u7684\u5efa\u8bae\u662f\u652f\u6301\u7d22\u8d54\u800c\u4e0d\u662f\u89d2\u8272\u3002\u58f0\u660e\u6bd4\u89d2\u8272\u63d0\u4f9b\u66f4\u5927\u7684\u7075\u6d3b\u6027\uff0c\u89d2\u8272\u4e3b\u8981\u51fa\u4e8e\u5411\u540e\u517c\u5bb9\u6027\u7684\u539f\u56e0\u5305\u542b\u5728 Identity \u4e2d\u3002\u8bdd\u867d\u5982\u6b64\uff0c\u81f3\u5c11\u6709\u4e00\u4e2a\u9886\u57df\u89d2\u8272\u4ecd\u7136\u53ef\u4ee5\u63d0\u4f9b\u4ef7\u503c\uff1a\u4f5c\u4e3a\u5411\u7528\u6237\u6279\u91cf\u5206\u914d\u58f0\u660e\u7684\u673a\u5236\u3002<\/p>\n<p>\u6211\u4eec\u5728\u4e0a\u4e00\u7ae0\u4e2d\u67e5\u770b\u4e86 Identity \u8868\u7684\u67b6\u6784\u3002\u6211\u4eec\u5f53\u65f6\u6ca1\u6709\u63a2\u7d22\u7684\u5df2\u521b\u5efa\u8868\u4e4b\u4e00\u662f AspNetRoleClaims \u8868\u3002\u6b64\u8868\u5305\u542b\u5df2\u5206\u914d\u7ed9\u89d2\u8272\uff08\u800c\u4e0d\u662f\u5355\u4e2a\u7528\u6237\uff09\u7684\u58f0\u660e\u53ca\u5176\u503c\u3002\u7f6e\u4e8e\u6307\u5b9a\u89d2\u8272\u4e2d\u7684\u4efb\u4f55\u7528\u6237\u90fd\u4f1a\u81ea\u52a8\u83b7\u53d6\u6240\u6709\u76f8\u5173\u58f0\u660e\u3002<\/p>\n<p>RoleManager \u7c7b\u5177\u6709\u4e00\u4e2a AddClaimsAsync \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06 IdentityRole \u5bf9\u8c61\u548c Claim \u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u5c06\u5b83\u4eec\u6dfb\u52a0\u5230\u6b64\u8868\u4e2d\u3002\u4f7f\u7528\u73b0\u6709\u7684 ClaimsManager\/Assign \u9875\u9762\u4f5c\u4e3a\u57fa\u7840\uff0c\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a AssignToRole \u7684\u9644\u52a0\u9875\u9762\uff0c\u8be5\u9875\u9762\u4f7f\u7528\u6b64\u65b9\u6cd5\u5c06\u58f0\u660e\u6dfb\u52a0\u5230\u89d2\u8272\u3002\u539f\u59cb Assign \u9875\u9762\u4e0e\u6b64\u65b0\u9875\u9762\u4e4b\u95f4\u7684\u4e3b\u8981\u533a\u522b\u5728\u4e8e\uff0c\u65b0\u9875\u9762\u5c06 RoleManager <IdentityRoles> \u4f5c\u4e3a\u4f9d\u8d56\u9879\uff0c\u800c\u4e0d\u662f UserManager<CityBreaksUser>\u3002\u60a8\u5c06\u4f7f\u7528 RoleManager.Roles \u5c5e\u6027\u83b7\u53d6\u9009\u62e9\u5217\u8868\u7684\u89d2\u8272\u5217\u8868\uff0c\u5e76\u4f7f\u7528 FindByIdAsync \u65b9\u6cd5\u4ece\u6240\u9009\u6807\u8bc6\u503c\u51bb\u7ed3\u89d2\u8272\u3002\u4eb2\u7231\u7684\u8bfb\u8005\uff0c\u5269\u4e0b\u7684\u5c31\u770b\u4f60\u4e86\u3002\u5982\u679c\u60a8\u9047\u5230\u56f0\u96be\uff0c\u8bf7\u67e5\u770b\u672c\u7ae0\u7684\u4e0b\u8f7d\u4ee5\u83b7\u53d6\u6709\u6548\u7248\u672c\u3002<\/p>\n<h2>10.4 \u6388\u6743\u8d44\u6e90<\/h2>\n<p>\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u4e13\u6ce8\u4e8e\u6388\u6743\u7aef\u70b9 \uff08\u9875\u9762\uff09\u3002\u7528\u6237\u8981\u4e48\u6709\u6743\u8bbf\u95ee\u7ec8\u7aef\u8282\u70b9\uff0c\u8981\u4e48\u6ca1\u6709\u3002\u6709\u65f6\uff0c\u60a8\u9700\u8981\u6839\u636e\u7ec8\u7aef\u8282\u70b9\u516c\u5f00\u7684\u8d44\u6e90\u6267\u884c\u6388\u6743\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u9047\u5230\u8fd9\u6837\u7684\u60c5\u51b5\uff1a\u4efb\u4f55\u6388\u6743\u7528\u6237\u90fd\u53ef\u4ee5\u6dfb\u52a0\u65b0\u5c5e\u6027\uff08\u8d44\u6e90\uff09\uff0c\u4f46\u53ea\u6709\u521b\u5efa\u8005\u53ef\u4ee5\u7f16\u8f91\u5c5e\u6027\u3002\u8fd9\u610f\u5473\u7740\u60a8\u548c\u6211\u90fd\u53ef\u4ee5\u6dfb\u52a0\u5c5e\u6027\uff0c\u4f46\u60a8\u4e0d\u80fd\u7f16\u8f91\u6211\u7684\u5c5e\u6027\uff0c\u6211\u4e5f\u65e0\u6cd5\u7f16\u8f91\u60a8\u7684\u5c5e\u6027\u3002\u8981\u5e94\u7528\u6b64\u7c7b\u6388\u6743\uff0c\u60a8\u9700\u8981\u77e5\u9053\u8be5\u8d44\u4ea7\u7684\u521b\u5efa\u8005\u3002\u8fd9\u53ea\u80fd\u901a\u8fc7\u6267\u884c\u7aef\u70b9\u5e76\u4ece\u6570\u636e\u5e93\u52a0\u8f7d\u5c5e\u6027\u6765\u5b8c\u6210\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u4f7f\u7528\u5c06\u8d44\u6e90\u4f5c\u4e3a\u53c2\u6570\u7684\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u6765\u5904\u7406\u6b64\u4efb\u52a1\u3002<\/p>\n<p>\u5728\u6267\u884c\u6b64\u4f5c\u4e4b\u524d\uff0c\u60a8\u9700\u8981\u5c06\u521b\u5efa\u8005\u5206\u914d\u7ed9\u5c5e\u6027\u3002\u6253\u5f00 Property \u7c7b\uff0c\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u4e24\u4e2a\u5c5e\u6027\uff1a<\/p>\n<pre><code>public string CreatorId { get; set; }\npublic CityBreaksUser Creator { get; set; }<\/code><\/pre>\n<p>CreatorId \u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\u5c5e\u6027\uff0c\u56e0\u4e3a\u5b83\u5c06\u4fdd\u5b58\u7528\u6237\u7684 identity \u503c\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u8fd9\u662f\u4e00\u4e2a GUID\u3002\u6dfb\u52a0\u540d\u4e3a AddedCreatorToProperty \u7684\u65b0\u8fc1\u79fb\uff1a<\/p>\n<pre><code>[Powershell]   \nadd-migration AddedCreatorToProperty   \n[CLI] \ndotnet ef migrations add AddedCreatorToProperty <\/code><\/pre>\n<p>\u5e94\u7528\u8fc1\u79fb\uff0c\u7136\u540e\u66f4\u65b0\u6570\u636e\u5e93\u4e2d\u7684\u8bb8\u591a\u5c5e\u6027\uff0c\u4ee5\u4fbf CreatorId \u5217\u5305\u542b\u7528\u6237\u7684 Id \u503c\u3002\u6211\u624b\u52a8\u5c06\u4e09\u4e2a\u7528\u6237\u7684 Id \u5e94\u7528\u4e8e\u6570\u636e\u5e93\u8868\u4e2d\u7684\u524d 20 \u6761\u8bb0\u5f55\uff08\u56fe 10.8\uff09\u3002\u5b8c\u6210\u6b64\u4f5c\u540e\uff0c\u60a8\u5c31\u53ef\u4ee5\u5f00\u59cb\u4e86\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1008.png\" ><\/p>\n<p>\u56fe 10.8 \u66f4\u65b0\u5c5e\u6027\uff0c\u4f7f CreatorId \u5217\u586b\u5145\u73b0\u6709\u7528\u6237\u7684 Id \u503c\u3002<\/p>\n<h3>\u300010.4.1 \u521b\u5efa\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f<\/h3>\n<p>\u8d44\u6e90\u6388\u6743\u6216\u591a\u6216\u5c11\u4e0e\u5176\u4ed6\u6388\u6743\u76f8\u540c\u3002\u5b83\u9700\u8981\u4e00\u4e2a requirement \u548c\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002\u5bf9\u4e8e\u8981\u6c42\uff0c\u6211\u5c06\u4f7f\u7528 ASP.NET Core \u6388\u6743\u9644\u5e26\u7684 OperationAuthorizationRequirement \u7c7b\u3002\u8fd9\u662f\u4e00\u4e2a\u5177\u6709\u5355\u4e2a\u5c5e\u6027\u7684\u5e2e\u52a9\u7a0b\u5e8f\u7c7b\uff1aName\u3002\u8be5\u7c7b\u65e8\u5728\u8868\u793a\u7279\u5b9a\u4e8e\u5bf9\u6570\u636e\u6267\u884c\u7684\u6700\u5e38\u89c1\u4f5c\u7684\u6388\u6743\u8981\u6c42\u3002\u4e3a\u8981\u6388\u6743\u7684\u6bcf\u4e2a\u4f5c\u521b\u5efa\u6b64\u7c7b\u7684\u5b9e\u4f8b\uff0c\u7136\u540e\u76f8\u5e94\u5730\u8bbe\u7f6e Name \u5c5e\u6027\u3002\u6e05\u5355 10.25 \u663e\u793a\u4e86\u8bb8\u591a\u5b9e\u4f8b\uff0c\u4ee3\u8868\u57fa\u672c\u7684 CRUD\u4f5c\uff0c\u5b83\u4eec\u88ab\u5206\u7ec4\u5230\u4e00\u4e2a\u540d\u4e3a PropertyOperations \u7684\u7c7b\u4e2d\u3002\u6b64\u7c7b\u4f4d\u4e8e AuthorizationRequirements \u6587\u4ef6\u5939\u4e2d\u3002<\/p>\n<p>\u6e05\u5355 10.25 \u5b9e\u73b0 OperationAuthorizationRequirementss<\/p>\n<pre><code>using Microsoft.AspNetCore.Authorization.Infrastructure;             \u2776\n\nnamespace CityBreaks.AuthorizationRequirements\n{\n    public static class PropertyOperations                           \u2777\n    {\n        public static OperationAuthorizationRequirement Create =\n            new () { Name = nameof(Create) };                        \u2778\n        public static OperationAuthorizationRequirement Read =\n            new () { Name = nameof(Read) };\n        public static OperationAuthorizationRequirement Edit =\n            new () { Name = nameof(Edit) };\n        public static OperationAuthorizationRequirement Delete =\n            new () { Name = nameof(Delete) };\n    }\n}<\/code><\/pre>\n<p>\u2776 OperationAuthorizationRequirement \u5e2e\u52a9\u7a0b\u5e8f\u7c7b\u4f4d\u4e8e Microsoft.AspNetCore.Authorization.Infrastructure \u547d\u540d\u7a7a\u95f4\u4e2d\u3002<br \/>\n\u2777 PropertyOperations \u662f\u4e00\u4e2a\u5305\u88c5\u7c7b\uff0c\u7528\u4e8e\u6ee1\u8db3\u4e0e Property \u7c7b\u578b\u4f5c\u76f8\u5173\u7684\u591a\u4e2a\u6388\u6743\u8981\u6c42\u3002<br \/>\n\u2778 \u5b9e\u4f8b\u5316 OperationAuthorizationRequirement \u7684\u5b9e\u4f8b\uff0c\u5e76\u5c06\u5176 Name \u8bbe\u7f6e\u4e3a Create\u3002\u5176\u4ed6 S \u5b9e\u4f8b\u5316\u65f6\uff0c\u5176\u540d\u79f0\u8bbe\u7f6e\u4e3a\u5176\u4ed6 CRUD\u4f5c\u3002<\/p>\n<p>\u73b0\u5728\uff0c\u60a8\u5df2\u7ecf\u62e5\u6709\u4e86\u9700\u6c42\u7c7b\uff0c\u53ef\u4ee5\u521b\u5efa\u5904\u7406\u7a0b\u5e8f\u3002\u4e8b\u5b9e\u4e0a\uff0c\u7531\u4e8e\u6240\u6709\u4f5c\u7684\u8981\u6c42\u7c7b\u578b\u90fd\u662f\u76f8\u540c\u7684\uff08\u4f7f\u7528 OperationAuthorizationRequirement \u7c7b\u7684\u4e00\u4e2a\u4e3b\u8981\u597d\u5904\uff09\uff0c\u56e0\u6b64\u60a8\u53ea\u9700\u521b\u5efa\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f \u2014 \u4e00\u4e2a\u57fa\u4e8e AuthorizationHandler \u7684\u5904\u7406\u7a0b\u5e8f\uff0c\u5176\u4e2d TResource \u8868\u793a\u88ab\u6388\u6743\u7684\u8d44\u6e90\u7684\u7c7b\u578b\u3002<\/p>\n<p>\u5904\u7406\u7a0b\u5e8f\u7c7b\u540d\u4e3a PropertyAuthorizationhandler\uff0c\u5e76\u653e\u7f6e\u5728 AuthorizationHandlers \u6587\u4ef6\u5939\u4e2d\u3002\u4e3a\u7b80\u6d01\u8d77\u89c1\uff0c\u5b83\u4ec5\u5305\u542b\u5bf9\u4e24\u4e2a\u4f5c\u7684\u68c0\u67e5\uff1aEdit \u548c Delete\u3002\u7531\u4e8e\u5c06\u9488\u5bf9\u6240\u6709\u5c5e\u6027\u6388\u6743\u8981\u6c42\u8c03\u7528\u5904\u7406\u7a0b\u5e8f\uff0c\u56e0\u6b64\u8bf7\u68c0\u67e5\u8981\u6c42\u7684 Name \u5c5e\u6027\u4ee5\u786e\u5b9a\u6b63\u5728\u8bc4\u4f30\u54ea\u4e2a\u7279\u5b9a\u8981\u6c42\u3002\u5982\u679c\u6b63\u5728\u8bc4\u4f30 Edit \u8981\u6c42\uff0c\u8bf7\u68c0\u67e5\u5f53\u524d\u7528\u6237\u7684 NameIdentifier \u58f0\u660e\u4e2d\u7684\u5176 ID\uff0c\u5e76\u5c06\u5176\u4e0e\u8d44\u6e90\u7684 CreatorId \u5c5e\u6027\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u5b58\u5728\u5339\u914d\u9879\uff0c\u5219\u5f53\u524d\u7528\u6237\u521b\u5efa\u4e86\u8d44\u6e90\uff0c\u56e0\u6b64\u60a8\u5e94\u8be5\u5c06\u8981\u6c42\u6807\u8bb0\u4e3a\u6210\u529f\u3002<\/p>\n<p>\u60a8\u8fd8\u51b3\u5b9a\uff0c\u53ea\u6709\u5177\u6709 Admin \u89d2\u8272\u7684\u7528\u6237\u624d\u80fd\u5220\u9664\u5c5e\u6027\u3002\u56e0\u6b64\uff0c\u5982\u679c\u5f53\u524d\u8981\u6c42\u662f Delete \u8981\u6c42\uff0c\u5219\u4ec5\u5728\u8fd9\u4e9b\u60c5\u51b5\u4e0b\u5c06\u5176\u6807\u8bb0\u4e3a\u6210\u529f\u3002\u60a8\u5b9e\u9645\u4e0a\u4e0d\u9700\u8981\u8bbf\u95ee\u8d44\u6e90\u6765\u8fdb\u884c\u6b64\u8bc4\u4f30\uff0c\u4f46\u5c06\u8d44\u6e90\u7684\u6240\u6709\u6388\u6743\u903b\u8f91\u4fdd\u5b58\u5728\u4e00\u4e2a\u4f4d\u7f6e\u662f\u6709\u610f\u4e49\u7684\u3002\u5904\u7406\u7a0b\u5e8f\u7684\u4ee3\u7801\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>\u5217\u8868 10.26 PropertyAuthorizationHandler \u7c7b<\/p>\n<pre><code>using CityBreaks.AuthorizationRequirements;\nusing CityBreaks.Models;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Authorization.Infrastructure;\nusing System.Security.Claims;\n\nnamespace CityBreaks.AuthorizationHandlers\n{\n    public class PropertyAuthorizationHandler : \n        AuthorizationHandler&lt;OperationAuthorizationRequirement, Property&gt;    \u2776\n    {\n        protected override Task                                              \u2777\n        \u27a5 HandleRequirementAsync(AuthorizationHandlerContext context,       \u2777\n            OperationAuthorizationRequirement requirement, Property resource)\u2777\n        {\n            if(requirement.Name == PropertyOperations.Edit.Name)           \u2778\u2779\n            {                                                              \u2778\n                if (resource.CreatorId ==                                  \u2778\n                \u27a5 context.User.FindFirst(c =&gt; c.Type ==                   \u2778\n                \u27a5 ClaimTypes.NameIdentifier).Value)                       \u2778\n                {                                                          \u2778\n                    context.Succeed(requirement);                          \u2778\n                }                                                          \u2778\n            }                                                              \u2778\n            if(requirement.Name == PropertyOperations.Delete.Name)           \u277a\n            {                                                                \u277a\n                if (context.User.IsInRole(&quot;Admin&quot;))                          \u277a\n                {                                                            \u277a\n                    context.Succeed(requirement);                            \u277a\n                }                                                            \u277a\n            }                                                                \u277a\n            return Task.CompletedTask;\n        }\n    }\n}<\/code><\/pre>\n<p>\u2776 TRequirement \u662f OperationAuthorizationRequirement\uff0cTResource \u662f Property\u3002<br \/>\n\u2777 HandleRequirementAsync \u65b9\u6cd5\u540c\u65f6\u91c7\u7528\u9700\u6c42\u548c\u8d44\u6e90\u4ee5\u53ca Authorization-HandlerContext\u3002<br \/>\n\u2778 \u8bbf\u95ee\u8d44\u6e90\u7684 CreatorId \u5c5e\u6027\uff0c\u5e76\u6839\u636e\u5f53\u524d\u7528\u6237\u7684 Id \u68c0\u67e5\u5176\u503c\u3002\u5982\u679c\u5b83\u4eec\u5339\u914d\uff0c\u5219\u8981\u6c42\u6210\u529f\u3002<br \/>\n\u2779 \u68c0\u67e5\u5f53\u524d\u8981\u6c42\u7684 Name \u5c5e\u6027\u3002\u5982\u679c\u5b83\u4e0e Edit requirement's name \u76f8\u540c\uff0c\u5219\u5904\u7406\u6388\u6743\u68c0\u67e5\u3002<br \/>\n\u277a \u5982\u679c\u8981\u6c42\u662f Delete \u8981\u6c42\uff0c\u5219\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u4e3a Admin\u3002<\/p>\n<p>\u5728\u8fd9\u4e2a\u9636\u6bb5\uff0c\u60a8\u6709\u4e00\u4e2a\u9009\u62e9\u3002\u60a8\u53ef\u4ee5\u50cf\u4ee5\u524d\u4e00\u6837\u4e3a\u60a8\u7684\u9700\u6c42\u6ce8\u518c\u6b63\u5f0f\u7b56\u7565\uff0c\u4e5f\u53ef\u4ee5\u9009\u62e9\u76f4\u63a5\u6839\u636e\u9700\u6c42\u8fdb\u884c\u8bc4\u4f30\u3002\u7531\u4e8e\u540e\u8005\u6d89\u53ca\u7684\u5de5\u4f5c\u91cf\u8f83\u5c11\uff0c\u56e0\u6b64\u8bf7\u9009\u62e9\u8be5\u9009\u9879\u3002<\/p>\n<p>\u4ece\u6570\u636e\u5e93\u4e2d\u68c0\u7d22\u8981\u7f16\u8f91\u7684\u5c5e\u6027\u540e\uff0c\u5c06\u5728\u5c5e\u6027\u7ba1\u7406\u5668 Edit \u9875\u9762\u7684 OnGetAsync \u5904\u7406\u7a0b\u5e8f\u4e2d\u8fdb\u884c Edit authorization \u68c0\u67e5\u3002\u60a8\u5c06\u76f4\u63a5\u4f7f\u7528 IAuthorizationService \u6267\u884c\u68c0\u67e5\u3002\u5b83\u6709\u4e00\u4e2a AuthorizeUserAsync \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u5c06\u7528\u6237\u3001\u8d44\u6e90\u548c\u8981\u6c42\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u5177\u6709\u5e03\u5c14 Succeeded \u5c5e\u6027\u7684 AuthorizationResult \u5bf9\u8c61\u3002\u60a8\u5c06\u4f20\u5165\u5f53\u524d\u7528\u6237\u3001\u8981\u7f16\u8f91\u7684\u5c5e\u6027\u4ee5\u53ca Edit \u8981\u6c42\u3002\u5982\u679c Succeeded \u4e3a true\uff0c\u5219\u5f53\u524d\u7528\u6237\u5df2\u83b7\u5f97\u6388\u6743\u3002\u5426\u5219\uff0c\u60a8\u5c06\u8fd4\u56de Forbid \u7ed3\u679c\uff0c\u8be5\u7ed3\u679c\u4f1a\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230 Access Denied \u7ec8\u7aef\u8282\u70b9\u3002\u9996\u5148\uff0c\u60a8\u9700\u8981\u6ce8\u5165 IAuthorizationService \u5e76\u5728\u79c1\u6709\u5b57\u6bb5\u4e2d\u6355\u83b7\u5b83\u3002<\/p>\n<p>\u6e05\u5355 10.27 \u5c06 IAuthorizationService \u6ce8\u5165 EditModel<\/p>\n<pre><code>public class EditModel : PageModel\n{\n    private readonly IPropertyService _propertyService;\n    private readonly ICityService _cityService;\n    private readonly IAuthorizationService _authService;\n\n    public EditModel(IPropertyService propertyService, \n                    ICityService cityService, \n                    IAuthorizationService authService)\n    {\n        _propertyService = propertyService;\n        _cityService = cityService;\n        _authService = authService;\n    }\n...<\/code><\/pre>\n<p>\u7136\u540e\uff0c\u4fee\u6539 OnGetAsync \u65b9\u6cd5\u4ee5\u6267\u884c\u6388\u6743\u68c0\u67e5\u3002<\/p>\n<p>\u6e05\u5355 10.28 \u4f7f\u7528 AuthorizeUserAsync \u8bc4\u4f30\u7528\u6237\u3001\u8d44\u6e90\u548c\u9700\u6c42<\/p>\n<pre><code>public async Task&lt;IActionResult&gt; OnGetAsync()\n{\n    var property = await _propertyService.FindAsync(Id);\n\n    if (property == null)\n    {\n        return NotFound();\n    }\n    var result = await _authService.AuthorizeAsync(User, \n    \u27a5 property, PropertyOperations.Edit);\n    if (!result.Succeeded) \n    { \n        return Forbid();\n    } <\/code><\/pre>\n<p>\u5728\u6211\u7684\u5e94\u7528\u7a0b\u5e8f\u7248\u672c\u4e2d\uff0cPaul \u662f Id \u4ee5 beed \u5f00\u5934\u7684\u7528\u6237\u3002\u4ece\u56fe 10.8 \u4e2d\u53ef\u4ee5\u770b\u51fa\uff0c\u4ed6\u662f Id \u4e3a 1 \u7684\u5c5e\u6027\u7684\u521b\u5efa\u8005\u3002\u5982\u679c\u6211\u4ee5 Paul \u8eab\u4efd\u767b\u5f55\u5e76\u5bfc\u822a\u5230 \/property-manager \/edit\/1\uff0c\u5219\u6211\u53ef\u4ee5\u8bbf\u95ee\u201c\u7f16\u8f91\u201d\u8868\u5355\u3002\u5982\u679c\u6211\u5c1d\u8bd5\u5c06 URL \u4e2d\u7684 1 \u66ff\u6362\u4e3a 2\uff0c\u5219\u4f1a\u663e\u793a Access Denied \u9875\u9762\uff0c\u56e0\u4e3a Paul \u4e0d\u662f ID \u4e3a 2 \u7684\u5c5e\u6027\u7684\u521b\u5efa\u8005\u3002<\/p>\n<p>\u5982\u679c\u60a8\u66f4\u559c\u6b22\u6839\u636e\u7b56\u7565\u8fdb\u884c\u68c0\u67e5\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u68c0\u67e5\u9700\u6c42\uff0c\u5219\u53ef\u4ee5\u50cf\u8fd9\u6837\u6ce8\u518c\u7b56\u7565\uff1a<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt;\n{\n    options.AddPolicy(&quot;EditPropertyPolicy&quot;, policyBuilder =&gt; \n        policyBuilder.AddRequirements(PropertyOperations.Edit));\n});<\/code><\/pre>\n<p>\u7136\u540e\uff0c\u5c06\u7b56\u7565\u7684\u540d\u79f0\u4f20\u9012\u7ed9 AuthorizeUserAsync \u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u8981\u6c42\u7684\u540d\u79f0\uff1a<\/p>\n<pre><code>var result = await _authService.AuthorizeAsync(User, property, \n\u27a5 &quot;EditPropertyPolicy&quot;);<\/code><\/pre>\n<p>\u9664\u4e86\u9700\u8981\u66f4\u591a\u7684\u5de5\u4f5c\u5916\uff0c\u68c0\u67e5\u7b56\u7565\u8fd8\u9700\u8981\u4f7f\u7528\u5b57\u7b26\u4e32\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u5e38\u91cf\u6765\u89e3\u51b3\u8fd9\u79cd\u60c5\u51b5\uff0c\u4f46\u8fd9\u9700\u8981\u66f4\u591a\u7684\u5de5\u4f5c\u3002<\/p>\n<p>\u8fd8\u6709\u4e00\u4ef6\u4e8b\u9700\u8981\u6ce8\u610f\u3002\u76ee\u524d\uff0c\u5c5e\u6027\u7ba1\u7406\u5668\u7d22\u5f15\u9875\u9762\u5217\u51fa\u4e86\u6240\u6709\u5c5e\u6027\uff0c\u5e76\u5e26\u6709\u94fe\u63a5\uff0c\u53ef\u4ee5\u67e5\u770b\u5176\u8be6\u7ec6\u4fe1\u606f\u3001\u7f16\u8f91\u548c\u5220\u9664\u5b83\u4eec\u3002\u5f53\u7528\u6237\u6ca1\u6709\u6388\u6743\u65f6\uff0c\u5411\u7528\u6237\u63d0\u4f9b\u7f16\u8f91\u6216\u5220\u9664\u5c5e\u6027\u7684\u94fe\u63a5\u4f3c\u4e4e\u6beb\u65e0\u610f\u4e49\u3002\u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u60a8\u4ec5\u5728\u7528\u6237\u521b\u5efa\u8d44\u4ea7\u65f6\u63d0\u4f9b\u7f16\u8f91\u94fe\u63a5\uff0c\u5982\u679c\u4ed6\u4eec\u5177\u6709 Admin \u89d2\u8272\uff0c\u5219\u5220\u9664\u94fe\u63a5\u3002\u5728\u672c\u7ae0\u7684\u6700\u540e\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u4f7f\u7528 IAuthorizationService \u6839\u636e\u5f53\u524d\u7528\u6237\u548c\u8d44\u6e90\u7ba1\u7406\u6f14\u793a\u6587\u7a3f\u3002<\/p>\n<h3>10.4.2 \u5c06\u6388\u6743\u5e94\u7528\u4e8e UI<\/h3>\n<p>\u5f53\u60a8\u5e0c\u671b\u6839\u636e\u8d44\u6e90\u5728 UI \u4e2d\u8bc4\u4f30\u6388\u6743\u65f6\uff0c\u8bf7\u5728 IAuthorizationService \u4e0a\u4f7f\u7528\u4e0e\u521a\u624d\u5728\u5c5e\u6027\u7ba1\u7406\u5668\u7684 EditModel \u4e2d\u4f7f\u7528\u7684\u76f8\u540c\u7684 AuthorizeAsync \u65b9\u6cd5\u3002\u60a8\u9700\u8981\u4f7f\u8be5\u670d\u52a1\u53ef\u7528\u4e8e Razor \u9875\u9762\uff0c\u56e0\u6b64\u4f7f\u7528 inject \u6307\u4ee4\u6ce8\u5165\u8be5\u670d\u52a1\u3002\u7136\u540e\uff0c\u6839\u636e\u65b9\u6cd5\u8c03\u7528\u7684\u7ed3\u679c\u663e\u793a Edit \u548c Delete \u94fe\u63a5\u3002<\/p>\n<p>\u4ee5\u4e0b\u5217\u8868\u8be6\u7ec6\u4ecb\u7ecd\u4e86\u5bf9 PropertyManager \\Index.cshtml \u6587\u4ef6\u7684\u4ee3\u7801\u66f4\u6539\u3002\u5b83\u9700\u8981\u5728\u9875\u9762\u9876\u90e8\u4f7f\u7528\u51e0\u4e2a using \u6307\u4ee4\u4ee5\u53ca inject \u6307\u4ee4\u624d\u80fd\u4f7f IAuthorizationService \u53ef\u7528\u3002<\/p>\n<p>\u6e05\u5355 10.29 \u5c06 IAuthorizationService \u6ce8\u5165\u5230\u7d22\u5f15\u9875\u4e2d<\/p>\n<pre><code>@page\n@model CityBreaks.Pages.PropertyManager.IndexModel\n@using CityBreaks.AuthorizationRequirements\n@using Microsoft.AspNetCore.Authorization\n@inject IAuthorizationService authService<\/code><\/pre>\n<p>\u552f\u4e00\u5176\u4ed6\u5fc5\u9700\u7684\u66f4\u6539\u53d1\u751f\u5728\u5305\u542b\u94fe\u63a5\u7684 td \u5143\u7d20\u4e2d\u3002\u5c06\u8be5\u5143\u7d20\u66ff\u6362\u4e3a\u4ee5\u4e0b\u6e05\u5355\u4e2d\u7684\u4ee3\u7801\u3002<\/p>\n<p>\u6e05\u5355 10.30 \u4f7f\u7528 IAuthorizationService<\/p>\n<pre><code>&lt;td&gt;\n    &lt;a asp-page=&quot;.\/Details&quot; asp-route-id=&quot;@item.Id&quot;&gt;Details&lt;\/a&gt; \n    @{\n        var result = await authService.AuthorizeAsync(User, \n        \u27a5 item, PropertyOperations.Edit);\n        if (result.Succeeded)\n        {\n            @:|\n            &lt;a asp-page=&quot;.\/Edit&quot; asp-route-id=&quot;@item.Id&quot;&gt;Edit&lt;\/a&gt;\n        }\n        result = await authService.AuthorizeAsync(User, \n        \u27a5 item, PropertyOperations.Delete);\n        if (result.Succeeded)\n        {\n                @:|\n                &lt;a asp-page=&quot;.\/Delete&quot; asp-route-id=&quot;@item.Id&quot;&gt;Delete&lt;\/a&gt;\n        }\n    }\n&lt;\/td&gt;<\/code><\/pre>\n<p>\u5728\u8fd9\u91cc\uff0c\u60a8\u5c06\u4f7f\u7528\u4e0e\u4f7f\u7528 EditModel \u7684 OnGetAsync \u65b9\u6cd5\u76f8\u540c\u7684\u65b9\u6cd5\u548c\u76f8\u540c\u7684\u53c2\u6570\u3002\u8fd9\u4e00\u6b21\uff0c\u5982\u679c\u6388\u6743\u8bc4\u4f30\u6210\u529f\uff0c\u5219\u5448\u73b0\u4e00\u4e2a\u94fe\u63a5\u3002<\/p>\n<p>\u5f53 Paul \u767b\u5f55\u65f6\uff0c\u4ed6\u770b\u5230\u4e00\u4e9b Edit \u94fe\u63a5\uff0c\u4f46\u6839\u672c\u770b\u4e0d\u5230 Delete \u94fe\u63a5\uff0c\u56e0\u4e3a\u4ed6\u6ca1\u6709 Admin \u89d2\u8272\u3002\u5f53 Anna \u767b\u5f55\u65f6\uff0c\u5979\u53ef\u4ee5\u5220\u9664\u4efb\u4f55\u5c5e\u6027\uff0c\u4f46\u53ea\u6709 Edit \u94fe\u63a5\u53ef\u7528\u4e8e\u60a8\u4e3a\u5176\u5206\u914d\u4e3a\u521b\u5efa\u8005\u7684\u5c5e\u6027\uff08\u56fe 10.9\uff09\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcorerazorpageinaction\/1009.png\" ><\/p>\n<p>\u56fe 10.9\u4f5c\u94fe\u63a5\u4e0d\u540c\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u767b\u5f55\u8005\u3002<\/p>\n<p>\u8fd8\u6709\u4e00\u4ef6\u91cd\u8981\u7684\u4e8b\u60c5\u9700\u8981\u7262\u8bb0\u3002\u867d\u7136\u60a8\u5df2\u4ece\u9875\u9762\u4e2d\u5220\u9664\u4e86 Delete \u94fe\u63a5\uff0c\u4f46\u4e86\u89e3\u5e94\u7528\u7a0b\u5e8f URL \u7684\u4eba\u5458\u4ecd\u53ef\u4ee5\u5411 Delete \u7aef\u70b9\u63d0\u4ea4\u8bf7\u6c42\u3002\u60a8\u9700\u8981\u5e94\u7528\u6388\u6743\u68c0\u67e5\uff0c\u4ec5\u5141\u8bb8 Admin \u89d2\u8272\u4e2d\u7684\u7528\u6237\u80fd\u591f\u6267\u884c\u6b64\u4f5c\u3002\u60a8\u51b3\u5b9a\u662f\u4f7f\u7528 Authorize \u5c5e\u6027\u8fd8\u662f\u9875\u9762\u7ea6\u5b9a\u6765\u5e94\u7528\u6388\u6743\u68c0\u67e5\uff0c\u4f46\u9700\u8981\u6dfb\u52a0\u68c0\u67e5\u3002\u60a8\u53ef\u4ee5\u50cf\u5728\u7b2c 5 \u7ae0\u4e2d\u4ecb\u7ecd\u7684\u90a3\u6837\u8003\u8651\u57fa\u4e8e UI \u7684\u6388\u6743\uff1a\u5f88\u9ad8\u5174\u6709\uff0c\u4f46\u60a8\u4ecd\u7136\u5fc5\u987b\u5728\u670d\u52a1\u5668\u4e0a\u5e94\u7528\u68c0\u67e5\uff0c\u5e76\u4e14\u7ec8\u7aef\u8282\u70b9\u6388\u6743\u7b49\u540c\u4e8e\u670d\u52a1\u5668\u7aef\u8f93\u5165\u9a8c\u8bc1\u3002<\/p>\n<p>\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u5df2\u7ecf\u5b8c\u6210\u4e86\u5bf9\u6240\u6709\u4e3b\u8981\u6846\u67b6\u529f\u80fd\u7684\u56de\u987e\u3002\u6700\u540e\u56db\u7ae0\u6db5\u76d6\u4e86\u60a8\u9700\u8981\u4e86\u89e3\u7684\u4e00\u7cfb\u5217\u4e3b\u9898\uff0c\u4ee5\u4fbf\u5bf9\u5e94\u7528\u7a0b\u5e8f\u8fdb\u884c\u6545\u969c\u6392\u9664\u3001\u4fdd\u62a4\u5e94\u7528\u7a0b\u5e8f\u5e76\u53d1\u5e03\u5e94\u7528\u7a0b\u5e8f\u3002\u5728\u6b64\u4e4b\u524d\uff0c\u6211\u4eec\u5c06\u5728\u4e0b\u4e00\u7ae0\u4e2d\u4ecb\u7ecd\u4e0e Razor Pages \u6846\u67b6\u76f8\u5173\u7684\u5ba2\u6237\u7aef\u5f00\u53d1\u7684\u67d0\u4e9b\u65b9\u9762\uff0c\u7279\u522b\u662f AJAX \u6280\u672f\u7684\u4f7f\u7528\u3002<\/p>\n<h2>\u603b\u7ed3<\/h2>\n<p>\u6388\u6743\u662f\u786e\u5b9a\u5141\u8bb8\u7528\u6237\u6267\u884c\u54ea\u4e9b\u4f5c\u7684\u8fc7\u7a0b\u3002<br \/>\n\u6388\u6743\u901a\u8fc7 AddAuthorization \u6dfb\u52a0\u4e3a\u670d\u52a1\uff0c\u5e76\u901a\u8fc7 UseAuthorization \u4f5c\u4e3a\u4e2d\u95f4\u4ef6\u542f\u7528\u3002\u8fd9\u5e94\u8be5\u653e\u5728\u8eab\u4efd\u9a8c\u8bc1\u4e4b\u540e\u3002\u5982\u679c\u7528\u6237\u672a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5219\u65e0\u6cd5\u6388\u6743\u7528\u6237\u3002<br \/>\n\u60a8\u53ef\u4ee5\u5c06\u6388\u6743\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9 \uff08\u9875\u9762\uff09 \u548c\u8d44\u6e90\u3002<br \/>\n\u4f7f\u7528 Authorize \u5c5e\u6027\uff0c\u53ef\u4ee5\u5c06\u7b80\u5355\u6388\u6743\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u53ea\u5141\u8bb8\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u3002<br \/>\n\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u9875\u9762\u7ea6\u5b9a\u5411\u9875\u9762\u3001\u6587\u4ef6\u5939\u548c\u533a\u57df\u6dfb\u52a0\u6388\u6743\uff0c\u4ece\u800c\u5141\u8bb8\u60a8\u96c6\u4e2d\u6388\u6743\u914d\u7f6e\u3002<br \/>\nASP.NET Identity \u652f\u6301\u57fa\u4e8e\u89d2\u8272\u7684\u6388\u6743\uff0c\u8fd9\u4f7f\u60a8\u80fd\u591f\u5c06\u5177\u6709\u76f8\u540c\u6743\u9650\u7684\u7528\u6237\u5206\u7ec4\u5728\u4e00\u8d77\u3002<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u5f53\u524d\u7528\u6237\u7684\u58f0\u660e\u4f5c\u4e3a\u6388\u6743\u7684\u57fa\u7840\uff0c\u8fd9\u4e9b\u58f0\u660e\u8868\u793a\u6709\u5173\u7528\u6237\u7684\u6570\u636e\u5e76\u6784\u6210\u5176\u8eab\u4efd\u7684\u4e00\u90e8\u5206\u3002<br \/>\n\u6388\u6743\u5efa\u7acb\u5728\u8981\u6c42\u3001\u5904\u7406\u7a0b\u5e8f\u548c\u7b56\u7565\u4e4b\u4e0a\u3002\u6bcf\u4e2a\u7b56\u7565\u90fd\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u9700\u6c42\u7ec4\u6210\uff0c\u6bcf\u4e2a\u9700\u6c42\u90fd\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002<br \/>\n\u8981\u6c42\u5904\u7406\u7a0b\u5e8f\u5305\u542b\u7528\u4e8e\u786e\u5b9a\u5f53\u524d\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\u7684\u903b\u8f91\u3002\u5904\u7406\u7a0b\u5e8f\u8c03\u7528 context.Succeed\uff08requirement\uff09 \u5c06\u8981\u6c42\u6807\u8bb0\u4e3a\u6210\u529f\u3002<br \/>\n\u53ea\u6709\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f\u9700\u8981\u6210\u529f\uff0c\u8981\u6c42\u5c31\u4f1a\u6210\u529f\u3002\u5fc5\u987b\u6ee1\u8db3\u6240\u6709\u8981\u6c42\u624d\u80fd\u6388\u4e88\u6388\u6743\u3002<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528 context \u6765\u786e\u4fdd\u6388\u6743\u5931\u8d25\u3002Fail \u65b9\u6cd5\u3002<br \/>\n\u6388\u6743\u5305\u62ec\u8bb8\u591a\u5185\u7f6e\u7b56\u7565\uff0c\u5305\u62ec\u9700\u8981\u4e00\u4e2a\u6216\u591a\u4e2a\u89d2\u8272\u3001\u4e00\u4e2a\u6216\u591a\u4e2a\u58f0\u660e\u3001\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u548c\u7279\u5b9a\u7528\u6237\u540d\u7684\u7b56\u7565\u3002<br \/>\n\u60a8\u53ef\u4ee5\u521b\u5efa\u81ea\u5df1\u7684\u81ea\u5b9a\u4e49\u8981\u6c42\u3001\u5904\u7406\u7a0b\u5e8f\u548c\u7b56\u7565\u3002\u81ea\u5b9a\u4e49\u5904\u7406\u7a0b\u5e8f\u5fc5\u987b\u6ce8\u518c\u4e3a\u670d\u52a1\u3002<br \/>\n\u8d44\u6e90\u6388\u6743\u4f7f\u60a8\u80fd\u591f\u5bf9\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u5143\u7d20\u7684\u8bbf\u95ee\u5e94\u7528\u7cbe\u7ec6\u63a7\u5236\u3002<br \/>\nOperationAuthorizationRequirement \u5e2e\u52a9\u7a0b\u5e8f\u7c7b\u65e8\u5728\u5e2e\u52a9\u5b9a\u4e49\u7528\u4e8e\u6388\u6743\u5bf9\u8d44\u6e90\u6267\u884c\u7279\u5b9a\u4f5c\u7684\u5904\u7406\u7a0b\u5e8f\u3002<br \/>\n\u53ef\u4ee5\u5c06 IAuthorizationService \u6ce8\u5165 Razor \u9875\u9762\uff0c\u4ee5\u5c06\u6388\u6743\u5e94\u7528\u4e8e UI \u7684\u5448\u73b0\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>ASP.NET Core Razor Pages in Action 10 \u901a\u8fc7\u6388\u6743\u63a7\u5236\u8bbf\u95ee \u672c\u7ae0\u6db5\u76d6 \u2022 \u5728 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u4e2d\u542f\u7528\u6388\u6743\u670d\u52a1 \u2022 \u4f7f\u7528\u89d2\u8272\u548c\u58f0\u660e\u6388\u6743\u7ec8\u7aef\u8282\u70b9 \u2022 \u6839\u636e\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u521b\u5efa\u6388\u6743\u7b56\u7565 \u2022 \u6388\u6743\u8bbf\u95ee\u8d44\u6e90 \u5728\u4e0a\u4e00\u7ae0\u4e2d\uff0c\u60a8\u5b66\u4e60\u4e86\u5982\u4f55\u901a\u8fc7\u8981\u6c42\u7528\u6237\u5bf9\u81ea\u5df1\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u6765\u8bc6\u522b\u7528\u6237\u3002\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u540e\uff0c\u7528\u6237\u4e0d\u518d\u662f\u533f\u540d\u7684;\u4ed6\u4eec\u6709\u4e00\u4e2a\u8eab\u4efd\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u9650\u5236\u5bf9\u5e94\u7528\u7a0b\u5e8f\u5404\u4e2a\u90e8\u5206\u7684\u8bbf\u95ee\u3002\u6b64\u8fc7\u7a0b\u79f0\u4e3a\u6388\u6743\uff0c\u5bf9\u4e8e\u4fdd\u62a4\u5e94\u7528\u7a0b\u5e8f\u7684\u67d0\u4e9b\u90e8\u5206\u514d\u53d7\u4e0d\u5e94\u8bbf\u95ee\u7684\u7528\u6237\u7684\u653b\u51fb\u81f3\u5173\u91cd\u8981\u3002 \u5373\u4f7f\u662f\u6700\u7b80\u5355\u7684\u52a8\u6001 Web \u5e94\u7528\u7a0b\u5e8f\u4e5f\u53ef\u80fd\u5305\u62ec\u4e00\u4e2a\u6240\u6709\u8005\u7ef4\u62a4\u5185\u5bb9\u7684\u533a\u57df\uff0c\u5373\u7ba1\u7406\u533a\u57df\u3002\u8fd9\u5c06\u9700\u8981\u9632\u6b62\u672a\u7ecf\u6388\u6743\u7684\u8bbf\u95ee\uff0c\u9664\u975e\u60a8\u5e0c\u671b\u968f\u673a\u7528\u6237\u5f00\u59cb\u53d1\u5e03\u4ed6\u4eec\u81ea\u5df1\u7684\u5185\u5bb9\uff0c\u6216\u8005\u66f4\u7cdf\u7684\u662f\uff1a\u6c61\u635f\u6216\u5220\u9664\u60a8\u73b0\u6709\u7684\u5185\u5bb9\u3002\u66f4\u590d\u6742\u7684\u5e94\u7528\u7a0b\u5e8f\u53ef\u80fd\u9700\u8981\u590d\u6742\u7684\u8bbf\u95ee\u7b56\u7565\uff0c\u5176\u4e2d\u4e0d\u540c\u7684\u7528\u6237\u5bf9\u5e94\u7528\u7a0b\u5e8f\u7684\u67d0\u4e9b\u90e8\u5206\u5177\u6709\u4e0d\u540c\u7ea7\u522b\u7684\u6743\u9650\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u5141\u8bb8\u9009\u5b9a\u6570\u91cf\u7684\u7528\u6237\u6dfb\u52a0\u5230\u60a8\u7684\u7f51\u7ad9\u63d0\u4f9b\u7684\u5ea6\u5047\u5730\u70b9\u8303\u56f4\uff0c\u4f46\u8fdb\u4e00\u6b65\u9650\u5236\u8c01\u53ef\u4ee5\u7ba1\u7406\u4ef7\u683c\u3002\u5ba2\u6237\u5c06\u80fd\u591f\u9884\u8ba2\u5047\u671f\u5e76\u67e5\u770b\u4ed6\u4eec\u81ea\u5df1\u7684\u8ba2\u5355\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f46\u53ea\u6709\u7ba1\u7406\u5458\u624d\u80fd\u67e5\u770b\u6240\u6709\u8ba2\u5355\u7684\u8be6\u7ec6\u4fe1\u606f\u3002\u8d85\u7ea7\u7528\u6237\u53ef\u80fd\u662f\u552f\u4e00\u53ef\u4ee5\u66f4\u6539\u8ba2\u5355\u90e8\u5206\u5185\u5bb9\u7684\u7528\u6237\u3002 \u5728\u6700\u7b80\u5355\u7684\u7ea7\u522b\u4e0a\uff0c\u60a8\u53ef\u4ee5\u4fdd\u62a4\u5e94\u7528\u7a0b\u5e8f\u7684\u67d0\u4e9b\u90e8\u5206\uff0c\u4ee5\u4fbf\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u8bbf\u95ee\u5b83\u4eec\u3002\u60a8\u5c06\u9996\u5148\u5b66\u4e60\u5982\u4f55\u5bf9\u5355\u4e2a\u9875\u9762\u6216\u7ec8\u7aef\u8282\u70b9\u6267\u884c\u6b64\u4f5c\u3002\u60a8\u8fd8\u5c06\u4e86\u89e3\u5982\u4f55\u4fdd\u62a4\u7279\u5b9a\u6587\u4ef6\u5939\u6216\u6574\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6240\u6709\u9875\u9762\u3002\u7136\u540e\uff0c\u60a8\u5c06\u63a2\u7d22 ASP.NET Core Identity \u63d0\u4f9b\u7684\u4e00\u4e9b\u529f\u80fd\uff0c\u7528\u4e8e\u66f4\u7cbe\u7ec6\u5730\u7ba1\u7406\u6388\u6743\u3002\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u6839\u636e\u7528\u6237\u7684\u89d2\u8272\u5c06\u7528\u6237\u5206\u7ec4\u5728\u4e00\u8d77\uff0c\u5e76\u5728\u6b64\u57fa\u7840\u4e0a\u7ba1\u7406\u5bf9\u7ec8\u7aef\u8282\u70b9\u7684\u8bbf\u95ee\u3002\u7136\u540e\uff0c\u60a8\u5c06\u66f4\u8be6\u7ec6\u5730\u63a2\u8ba8\u4e0a\u4e00\u7ae0\u4e2d\u4ecb\u7ecd\u7684\u58f0\u660e\u6982\u5ff5\uff0c\u5e76\u786e\u5b9a\u5982\u4f55\u57fa\u4e8e\u58f0\u660e\u5236\u5b9a\u6388\u6743\u7b56\u7565\u5e76\u5e94\u7528\u5b83\u4eec\u6765\u7ba1\u7406\u5bf9\u7ec8\u7aef\u8282\u70b9\u7684\u8bbf\u95ee\u3002\u963b\u6b62\u8bbf\u95ee\u7ec8\u7aef\u8282\u70b9\u79f0\u4e3a\u57fa\u4e8e\u8bf7\u6c42\u7684\u6388\u6743\u3002\u5728\u5b66\u4e60\u5982\u4f55\u521b\u5efa\u7b56\u7565\u65f6\uff0c\u60a8\u5c06\u4e86\u89e3\u5b83\u4eec\u5982\u4f55\u57fa\u4e8e\u8981\u6c42\u53ca\u5176\u5904\u7406\u7a0b\u5e8f\u3002\u60a8\u5c06\u7f16\u5199\u81ea\u5df1\u7684\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\uff0c\u5e76\u4f7f\u7528\u5b83\u4eec\u6765\u5236\u5b9a\u4e00\u4e9b\u7b56\u7565\u3002 \u6700\u540e\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5728\u9875\u9762\u4e2d\u5b9e\u73b0 fine-grained \u6388\u6743\u3002\u4f8b\u5982\uff0c\u8bb8\u591a\u7528\u6237\u53ef\u80fd\u6709\u6743\u8bbf\u95ee\u5217\u51fa\u8981\u51fa\u79df\u7684\u623f\u4ea7\u7684\u9875\u9762\uff0c\u4f46\u53ea\u6709\u9009\u5b9a\u7684\u7528\u6237\u624d\u6709\u6743\u7f16\u8f91\u8fd9\u4e9b\u623f\u4ea7\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u4e0d\u5e0c\u671b\u5411\u6ca1\u6709\u8db3\u591f\u6743\u9650\u7684\u7528\u6237\u663e\u793a Edit \u5bfc\u822a\u3002\u5728\u6b64\u7c7b\u9875\u9762\u4e2d\u5e94\u7528\u6388\u6743\u7b56\u7565\u79f0\u4e3a\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u3002 \u6211\u4e00\u76f4\u8ba4\u4e3a\u6388\u6743\u4e0e\u4f9d\u8d56\u9879\u6ce8\u5165\u6709\u4e00\u4e9b\u5171\u540c\u70b9\u3002\u8fd9\u4e24\u4e2a\u4e3b\u9898\u5b9e\u9645\u4e0a\u90fd\u662f\u76f8\u5bf9\u5bb9\u6613\u7406\u89e3\u7684\u8bdd\u9898\uff0c\u4f46\u90fd\u7b3c\u7f69\u5728\u62bd\u8c61\u6982\u5ff5\u7684\u8ff7\u96fe\u4e2d\u3002\u6b63\u5982\u6211\u5e0c\u671b\u5728\u6709\u5173\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165\u7684\u7ae0\u8282\u4e2d\u6d88\u9664\u8ff7\u96fe\u4e00\u6837\uff0c\u6211\u5c06\u9996\u5148\u89e3\u91ca\u60a8\u5c06\u4f7f\u7528\u7684\u6709\u5173\u6388\u6743\u7684\u4e00\u4e9b\u6982\u5ff5\u3002 10.1 Razor Pages \u4e2d\u7684\u57fa\u672c\u6388\u6743 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6388\u6743\u7531\u8bb8\u591a\u670d\u52a1\u63d0\u4f9b\uff0c\u5305\u62ec IAuthorizationService\u3002\u8fd9\u4e9b\u5fc5\u987b\u5728\u5e94\u7528\u7a0b\u5e8f\u542f\u52a8\u65f6\u6dfb\u52a0\u5230\u670d\u52a1\u5bb9\u5668\u4e2d\u3002\u4e00\u79cd\u4fbf\u6377\u7684\u65b9\u6cd5 AddAuthorization \u8d1f\u8d23\u6dfb\u52a0\u6240\u6709\u5fc5\u9700\u7684\u670d\u52a1\uff1a builder.Services.AddAuthorization(); \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u5728 Web \u5e94\u7528\u7a0b\u5e8f\u6a21\u677f\u4e2d\u901a\u8fc7\u5305\u542b app \u6765\u542f\u7528\u3002UseAuthorization\uff08\uff09 \u5728 Program \u7c7b\u4e2d\u3002 \u6388\u6743\u53d6\u51b3\u4e8e\u77e5\u9053\u7528\u6237\u662f\u8c01\u4ee5\u53ca\u4ed6\u4eec\u8bd5\u56fe\u505a\u4ec0\u4e48\uff0c\u4ee5\u53ca\u5728\u57fa\u4e8e\u8bf7\u6c42\u7684\u6388\u6743\u7684\u60c5\u51b5\u4e0b\uff0c\u4ed6\u4eec\u8bd5\u56fe\u8bbf\u95ee\u54ea\u4e2a\u9875\u9762\u3002\u5982\u7b2c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1075","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1075","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1075"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/1075\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1075"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1075"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1075"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}