{"id":619,"date":"2025-04-05T11:42:42","date_gmt":"2025-04-05T03:42:42","guid":{"rendered":"https:\/\/www.hyy.net\/?p=619"},"modified":"2025-04-05T11:42:42","modified_gmt":"2025-04-05T03:42:42","slug":"asp-net-core-in-action-24-authorization-securing-your-application","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=619","title":{"rendered":"ASP.NET Core in Action 24 Authorization: Securing your application"},"content":{"rendered":"<p>24 Authorization: Securing your application\u200c<br \/>\n24 Authorization\uff1a \u4fdd\u62a4\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f<\/p>\n<h2>This chapter covers<\/h2>\n<p>\u672c\u7ae0\u6db5\u76d6<\/p>\n<p>\u2022  Using authorization to control who can use your app<br \/>\n\u4f7f\u7528\u6388\u6743\u6765\u63a7\u5236\u8c01\u53ef\u4ee5\u4f7f\u7528\u4f60\u7684\u5e94\u7528<br \/>\n\u2022  Using claims-based authorization with policies<br \/>\n\u5c06\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u4e0e\u7b56\u7565\u7ed3\u5408\u4f7f\u7528<br \/>\n\u2022  Creating custom policies to handle complex requirements<br \/>\n\u521b\u5efa\u81ea\u5b9a\u4e49\u7b56\u7565\u4ee5\u5904\u7406\u590d\u6742\u8981\u6c42<br \/>\n\u2022  Authorizing a request depending upon the resource being accessed<br \/>\n\u6839\u636e\u6b63\u5728\u8bbf\u95ee\u7684\u8d44\u6e90\u6388\u6743\u8bf7\u6c42<br \/>\n\u2022  Hiding elements from a Razor template that the user is unauthorized to access<br \/>\n\u9690\u85cf\u7528\u6237\u65e0\u6743\u8bbf\u95ee\u7684 Razor \u6a21\u677f\u4e2d\u7684\u5143\u7d20<\/p>\n<p>In chapter 23 I showed you how to add users to an ASP.NET Core application by adding authentication. With authentication, users can register and log in to your app using an email address and password. Whenever you add authentication to an app, you inevitably \ufb01nd you want to be able to restrict what some users can do. The process of determining whether a user can perform a given action on your app is called authorization.<br \/>\n\u5728\u7b2c 23 \u7ae0\u4e2d\uff0c\u6211\u5411\u60a8\u5c55\u793a\u4e86\u5982\u4f55\u901a\u8fc7\u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u5c06\u7528\u6237\u6dfb\u52a0\u5230 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u3002\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u7528\u6237\u53ef\u4ee5\u4f7f\u7528\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u548c\u5bc6\u7801\u6ce8\u518c\u548c\u767b\u5f55\u60a8\u7684\u5e94\u7528\u3002\u6bcf\u5f53\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u65f6\uff0c\u60a8\u90fd\u4e0d\u53ef\u907f\u514d\u5730\u4f1a\u53d1\u73b0\u60a8\u5e0c\u671b\u80fd\u591f\u9650\u5236\u67d0\u4e9b\u7528\u6237\u53ef\u4ee5\u6267\u884c\u7684\u4f5c\u3002\u786e\u5b9a\u7528\u6237\u662f\u5426\u53ef\u4ee5\u5bf9\u60a8\u7684\u5e94\u7528\u6267\u884c\u7ed9\u5b9a\u4f5c\u7684\u8fc7\u7a0b\u79f0\u4e3a\u6388\u6743\u3002<\/p>\n<p>On an e-commerce site, for example, you may have admin users who are allowed to add new products and change prices, sales users who are allowed to view completed orders, and customer users who are allowed only to place orders and buy products.<br \/>\n\u4f8b\u5982\uff0c\u5728\u7535\u5b50\u5546\u52a1\u7f51\u7ad9\u4e0a\uff0c\u60a8\u53ef\u80fd\u62e5\u6709\u5141\u8bb8\u6dfb\u52a0\u65b0\u4ea7\u54c1\u548c\u66f4\u6539\u4ef7\u683c\u7684\u7ba1\u7406\u5458\u7528\u6237\u3001\u5141\u8bb8\u67e5\u770b\u5df2\u5b8c\u6210\u8ba2\u5355\u7684\u9500\u552e\u7528\u6237\u4ee5\u53ca\u4ec5\u5141\u8bb8\u4e0b\u8ba2\u5355\u548c\u8d2d\u4e70\u4ea7\u54c1\u7684\u5ba2\u6237\u7528\u6237\u3002<\/p>\n<p>In this chapter I show how to use authorization in an app to control what your users can do. In section 24.1 I introduce authorization and put it in the context of a real-life scenario you\u2019ve probably experienced: an airport. I describe the sequence of events, from checking in, to passing through security, to entering an airport lounge, and you\u2019ll see how these relate to the authorization concepts in this chapter.<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u5982\u4f55\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528\u6388\u6743\u6765\u63a7\u5236\u7528\u6237\u53ef\u4ee5\u6267\u884c\u7684\u4f5c\u3002\u5728 Section 24.1 \u4e2d\uff0c\u6211\u4ecb\u7ecd\u4e86 Authorization \u5e76\u5c06\u5176\u7f6e\u4e8e\u60a8\u53ef\u80fd\u7ecf\u5386\u8fc7\u7684\u771f\u5b9e\u573a\u666f\u7684\u4e0a\u4e0b\u6587\u4e2d\uff1a\u673a\u573a\u3002\u6211\u5c06\u4ecb\u7ecd\u4e8b\u4ef6\u7684\u987a\u5e8f\uff0c\u4ece\u529e\u7406\u767b\u673a\u624b\u7eed\u5230\u901a\u8fc7\u5b89\u68c0\uff0c\u518d\u5230\u8fdb\u5165\u673a\u573a\u4f11\u606f\u5ba4\uff0c\u60a8\u5c06\u4e86\u89e3\u8fd9\u4e9b\u4e8b\u4ef6\u4e0e\u672c\u7ae0\u4e2d\u7684\u6388\u6743\u6982\u5ff5\u6709\u4f55\u5173\u7cfb\u3002<\/p>\n<p>In section 24.2 I show how authorization \ufb01ts into an ASP.NET Core web application and how it relates to the ClaimsPrincipal class you saw in the previous chapter. You\u2019ll see how to enforce the simplest level of authorization in an ASP.NET Core app, ensuring that only authenticated users can execute a Razor Page or MVC action. This chapter focuses on authorization in Razor Pages and Model-View- Controller (MVC) controllers; in chapter 25 you\u2019ll learn how the same principles apply to minimal API applications.<br \/>\n\u5728\u7b2c 24.2 \u8282\u4e2d\uff0c\u6211\u5c06\u5c55\u793a\u6388\u6743\u5982\u4f55\u9002\u5e94 ASP.NET Core Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u53ca\u5b83\u4e0e\u60a8\u5728\u4e0a\u4e00\u7ae0\u4e2d\u770b\u5230\u7684 ClaimsPrincipal \u7c7b\u7684\u5173\u7cfb\u3002\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u5728 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u5f3a\u5236\u5b9e\u65bd\u6700\u7b80\u5355\u7684\u6388\u6743\u7ea7\u522b\uff0c\u786e\u4fdd\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u6267\u884c Razor Page \u6216 MVC\u4f5c\u3002\u672c\u7ae0\u91cd\u70b9\u4ecb\u7ecd Razor Pages \u548c\u6a21\u578b\u89c6\u56fe\u63a7\u5236\u5668 \uff08MVC\uff09 \u63a7\u5236\u5668\u4e2d\u7684\u6388\u6743;\u5728\u7b2c 25 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u76f8\u540c\u7684\u539f\u5219\u5982\u4f55\u5e94\u7528\u4e8e\u6700\u5c0f\u7684 API \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>We\u2019ll extend that approach in section 24.3 by adding the concept of policies. These let you set speci\ufb01c requirements for a given authenticated user, requiring that they have speci\ufb01c pieces of information to execute an action or Razor Page.<br \/>\n\u6211\u4eec\u5c06\u5728 Section 24.3 \u4e2d\u901a\u8fc7\u6dfb\u52a0 policies \u7684\u6982\u5ff5\u6765\u6269\u5c55\u8be5\u65b9\u6cd5\u3002\u8fd9\u4e9b\u5141\u8bb8\u60a8\u4e3a\u7ed9\u5b9a\u7684\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u8bbe\u7f6e\u7279\u5b9a\u8981\u6c42\uff0c\u8981\u6c42\u4ed6\u4eec\u5177\u6709\u6267\u884c\u4f5c\u6216 Razor \u9875\u9762\u7684\u7279\u5b9a\u4fe1\u606f\u3002<\/p>\n<p>You\u2019ll use policies extensively in the ASP.NET Core authorization system, so in section 24.4 we\u2019ll explore how to handle more complex scenarios. You\u2019ll learn about authorization requirements and handlers, and how you can combine them to create speci\ufb01c policies that you can apply to your Razor Pages and actions.<br \/>\n\u60a8\u5c06\u5728 ASP.NET Core \u6388\u6743\u7cfb\u7edf\u4e2d\u5e7f\u6cdb\u4f7f\u7528\u7b56\u7565\uff0c\u56e0\u6b64\u5728\u7b2c 24.4 \u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u63a2\u8ba8\u5982\u4f55\u5904\u7406\u66f4\u590d\u6742\u7684\u60c5\u51b5\u3002\u4f60\u5c06\u4e86\u89e3\u6388\u6743\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\uff0c\u4ee5\u53ca\u5982\u4f55\u5c06\u5b83\u4eec\u7ec4\u5408\u8d77\u6765\u4ee5\u521b\u5efa\u53ef\u5e94\u7528\u4e8e Razor Pages \u548c\u4f5c\u7684\u7279\u5b9a\u7b56\u7565\u3002<\/p>\n<p>Sometimes whether a user is authorized depends on which resource or document they\u2019re attempting to access. A resource is anything that you\u2019re trying to protect, so it could be a document or a post in a social media app. For example, you may allow users to create documents or to read documents from other users, but to edit only documents that they created themselves. This type of authorization, where you need the details of the document to determine if the user is authorized, is called resource-based authorization, and it\u2019s the focus of section 24.5.<br \/>\n\u6709\u65f6\uff0c\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\u53d6\u51b3\u4e8e\u4ed6\u4eec\u5c1d\u8bd5\u8bbf\u95ee\u7684\u8d44\u6e90\u6216\u6587\u6863\u3002\u8d44\u6e90\u662f\u60a8\u5c1d\u8bd5\u4fdd\u62a4\u7684\u4efb\u4f55\u5185\u5bb9\uff0c\u56e0\u6b64\u5b83\u53ef\u4ee5\u662f\u793e\u4ea4\u5a92\u4f53\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6587\u6863\u6216\u5e16\u5b50\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u5141\u8bb8\u7528\u6237\u521b\u5efa\u6587\u6863\u6216\u8bfb\u53d6\u5176\u4ed6\u7528\u6237\u7684\u6587\u6863\uff0c\u4f46\u53ea\u80fd\u7f16\u8f91\u4ed6\u4eec\u81ea\u5df1\u521b\u5efa\u7684\u6587\u6863\u3002\u8fd9\u79cd\u7c7b\u578b\u7684\u6388\u6743\uff0c\u60a8\u9700\u8981\u6587\u6863\u7684\u8be6\u7ec6\u4fe1\u606f\u6765\u786e\u5b9a\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\uff0c\u79f0\u4e3a\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\uff0c\u8fd9\u662f Section 24.5 \u7684\u91cd\u70b9\u3002<\/p>\n<p>In the \ufb01nal section of this chapter I show how you can extend the resource-based authorization approach to your Razor view templates. This lets you modify the UI to hide elements that users aren\u2019t authorized to interact with. In particular, you\u2019ll see how to hide the Edit button when a user isn\u2019t authorized to edit the entity.<br \/>\n\u5728\u672c\u7ae0\u7684\u6700\u540e\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u5982\u4f55\u5c06\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u65b9\u6cd5\u6269\u5c55\u5230 Razor \u89c6\u56fe\u6a21\u677f\u3002\u8fd9\u6837\uff0c\u60a8\u5c31\u53ef\u4ee5\u4fee\u6539 UI \u4ee5\u9690\u85cf\u7528\u6237\u65e0\u6743\u4e0e\u4e4b\u4ea4\u4e92\u7684\u5143\u7d20\u3002\u5177\u4f53\u800c\u8a00\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5728\u7528\u6237\u65e0\u6743\u7f16\u8f91\u5b9e\u4f53\u65f6\u9690\u85cf Edit \uff08\u7f16\u8f91\uff09 \u6309\u94ae\u3002<\/p>\n<p>We\u2019ll start by looking more closely at the concept of authorization, how it di\ufb00ers from authentication, and how it relates to real-life concepts you might see in an airport.<br \/>\n\u9996\u5148\uff0c\u6211\u4eec\u5c06\u66f4\u4ed4\u7ec6\u5730\u7814\u7a76\u6388\u6743\u7684\u6982\u5ff5\uff0c\u5b83\u4e0e\u8eab\u4efd\u9a8c\u8bc1\u6709\u4f55\u4e0d\u540c\uff0c\u4ee5\u53ca\u5b83\u4e0e\u60a8\u53ef\u80fd\u5728\u673a\u573a\u770b\u5230\u7684\u73b0\u5b9e\u751f\u6d3b\u4e2d\u7684\u6982\u5ff5\u6709\u4f55\u5173\u7cfb\u3002<\/p>\n<h2>24.1 Introduction to authorization\u200c<\/h2>\n<p>24.1 \u6388\u6743\u7b80\u4ecb<\/p>\n<p>In this section I provide an introduction to authorization and discuss how it compares with authentication. I use the real- life example of an airport as a case study to illustrate how claims-based authorization works.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u6388\u6743\u5e76\u8ba8\u8bba\u5b83\u4e0e\u8eab\u4efd\u9a8c\u8bc1\u7684\u6bd4\u8f83\u3002\u6211\u4f7f\u7528\u673a\u573a\u7684\u771f\u5b9e\u793a\u4f8b\u4f5c\u4e3a\u6848\u4f8b\u7814\u7a76\u6765\u8bf4\u660e\u57fa\u4e8e\u7d22\u8d54\u7684\u6388\u6743\u662f\u5982\u4f55\u8fd0\u4f5c\u7684\u3002<\/p>\n<p>For people who are new to web apps and security, authentication and authorization can be a little daunting. It certainly doesn\u2019t help that the words look so similar! The two concepts are often used together, but they\u2019re de\ufb01nitely distinct:<br \/>\n\u5bf9\u4e8e\u521a\u63a5\u89e6 Web \u5e94\u7528\u7a0b\u5e8f\u548c\u5b89\u5168\u6027\u7684\u4eba\u6765\u8bf4\uff0c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u53ef\u80fd\u6709\u70b9\u4ee4\u4eba\u751f\u754f\u3002\u8fd9\u4e9b\u8bcd\u770b\u8d77\u6765\u5982\u6b64\u76f8\u4f3c\u5f53\u7136\u65e0\u6d4e\u4e8e\u4e8b\uff01\u8fd9\u4e24\u4e2a\u6982\u5ff5\u7ecf\u5e38\u4e00\u8d77\u4f7f\u7528\uff0c\u4f46\u5b83\u4eec\u7edd\u5bf9\u662f\u4e0d\u540c\u7684\uff1a<\/p>\n<p>\u2022  Authentication\u2014The process of determining who made a request<br \/>\n\u8eab\u4efd\u9a8c\u8bc1 - \u786e\u5b9a\u8bf7\u6c42\u53d1\u51fa\u8005\u7684\u8fc7\u7a0b<br \/>\n\u2022  Authorization\u2014The process of determining whether the requested action is allowed<br \/>\n\u6388\u6743 - \u786e\u5b9a\u662f\u5426\u5141\u8bb8\u8bf7\u6c42\u7684\u4f5c\u7684\u8fc7\u7a0b<\/p>\n<p>Typically, authentication occurs \ufb01rst so that you know who is making a request to your app. For traditional web apps, your app authenticates a request by checking the encrypted cookie that was set when the user logged in (as you saw in chapter 23). API applications typically use a header instead of a cookie for authentication, but the overall process is the same, as you\u2019ll see in chapter 25.<br \/>\n\u901a\u5e38\uff0c\u9996\u5148\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4ee5\u4fbf\u60a8\u77e5\u9053\u8c01\u5728\u5411\u60a8\u7684\u5e94\u7528\u53d1\u51fa\u8bf7\u6c42\u3002\u5bf9\u4e8e\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u901a\u8fc7\u68c0\u67e5\u7528\u6237\u767b\u5f55\u65f6\u8bbe\u7f6e\u7684\u52a0\u5bc6 cookie \u6765\u9a8c\u8bc1\u8bf7\u6c42\uff08\u5982\u7b2c 23 \u7ae0\u6240\u793a\uff09\u3002API \u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4f7f\u7528 Headers \u800c\u4e0d\u662f cookie \u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4f46\u6574\u4e2a\u8fc7\u7a0b\u662f\u76f8\u540c\u7684\uff0c\u60a8\u5c06\u5728\u7b2c 25 \u7ae0\u4e2d\u770b\u5230\u3002<\/p>\n<p>Once a request is authenticated and you know who is making the request, you can determine whether they\u2019re allowed to execute an action on your server. This process is called authorization and is the focus of this chapter.<br \/>\n\u5728\u8bf7\u6c42\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u5e76\u4e14\u60a8\u77e5\u9053\u8c01\u5728\u53d1\u51fa\u8bf7\u6c42\u540e\uff0c\u60a8\u53ef\u4ee5\u786e\u5b9a\u662f\u5426\u5141\u8bb8\u4ed6\u4eec\u5728\u60a8\u7684\u670d\u52a1\u5668\u4e0a\u6267\u884c\u4f5c\u3002\u6b64\u8fc7\u7a0b\u79f0\u4e3a authorization\uff0c\u662f\u672c\u7ae0\u7684\u91cd\u70b9\u3002<\/p>\n<p>Before we dive into code and start looking at authorization in ASP.NET Core, I\u2019ll put these concepts into a real-life scenario that I hope you\u2019re familiar with: checking in at an airport. To enter an airport and board a plane, you must pass through several steps: an initial step to prove who you are (authentication) and subsequent steps that check whether you\u2019re allowed to proceed (authorization). In simpli\ufb01ed form, these might look like this:<br \/>\n\u5728\u6211\u4eec\u6df1\u5165\u7814\u7a76\u4ee3\u7801\u5e76\u5f00\u59cb\u7814\u7a76 ASP.NET Core \u4e2d\u7684\u6388\u6743\u4e4b\u524d\uff0c\u6211\u5c06\u628a\u8fd9\u4e9b\u6982\u5ff5\u653e\u5165\u4e00\u4e2a\u6211\u5e0c\u671b\u60a8\u719f\u6089\u7684\u771f\u5b9e\u573a\u666f\u4e2d\uff1a\u5728\u673a\u573a\u529e\u7406\u767b\u673a\u624b\u7eed\u3002\u8981\u8fdb\u5165\u673a\u573a\u5e76\u767b\u673a\uff0c\u60a8\u5fc5\u987b\u901a\u8fc7\u51e0\u4e2a\u6b65\u9aa4\uff1a\u8bc1\u660e\u60a8\u7684\u8eab\u4efd\u7684\u521d\u59cb\u6b65\u9aa4\uff08\u8eab\u4efd\u9a8c\u8bc1\uff09\u548c\u68c0\u67e5\u60a8\u662f\u5426\u88ab\u5141\u8bb8\u7ee7\u7eed\u7684\u540e\u7eed\u6b65\u9aa4\uff08\u6388\u6743\uff09\u3002\u5728\u7b80\u5316\u5f62\u5f0f\u4e2d\uff0c\u8fd9\u4e9b\u53ef\u80fd\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<ol>\n<li>Show your passport at the check-in desk. Receive a boarding pass.<br \/>\n\u5728\u503c\u673a\u67dc\u53f0\u51fa\u793a\u60a8\u7684\u62a4\u7167\u3002\u6536\u5230\u767b\u673a\u724c\u3002<\/li>\n<li>Show your boarding pass to enter security. Pass through security.<br \/>\n\u51fa\u793a\u767b\u673a\u724c\u8fdb\u5165\u5b89\u68c0\u3002\u901a\u8fc7\u5b89\u68c0\u3002<\/li>\n<li>Show your frequent-\ufb02yer card to enter the airline lounge. Enter the lounge.<br \/>\n\u51fa\u793a\u60a8\u7684\u5e38\u65c5\u5ba2\u5361\u8fdb\u5165\u822a\u7a7a\u516c\u53f8\u4f11\u606f\u5ba4\u3002\u8fdb\u5165\u4f11\u606f\u5ba4\u3002<\/li>\n<li>Show your boarding pass to board the \ufb02ight. Enter the airplane.<br \/>\n\u51fa\u793a\u60a8\u7684\u767b\u673a\u724c\u767b\u673a\u3002\u8fdb\u5165\u98de\u673a\u3002<\/li>\n<\/ol>\n<p>Obviously, these steps, also shown in \ufb01gure 24.1, will vary somewhat in real life (I don\u2019t have a frequent-\ufb02yer card!), but we\u2019ll go with them for now. Let\u2019s explore each step a little further.<br \/>\n\u663e\u7136\uff0c\u8fd9\u4e9b\u6b65\u9aa4\uff08\u5982\u56fe 24.1 \u6240\u793a\uff09\u5728\u73b0\u5b9e\u751f\u6d3b\u4e2d\u4f1a\u6709\u6240\u4e0d\u540c\uff08\u6211\u6ca1\u6709\u5e38\u65c5\u5ba2\u5361\uff01\uff09\uff0c\u4f46\u6211\u4eec\u73b0\u5728\u5c31\u6765\u4ecb\u7ecd\u4e00\u4e0b\u3002\u8ba9\u6211\u4eec\u8fdb\u4e00\u6b65\u63a2\u8ba8\u6bcf\u4e2a\u6b65\u9aa4\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2401-1.jpg\" alt=\"alt text\" \/><br \/>\n<img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2401-2.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.1 When boarding a plane at an airport, you pass through several authorization steps. At each authorization step, you must present a claim in the form of a boarding pass or a frequent-\ufb02yer card. If you\u2019re not authorized, access is denied.<br \/>\n\u56fe 24.1 \u5728\u673a\u573a\u767b\u673a\u65f6\uff0c\u60a8\u9700\u8981\u5b8c\u6210\u51e0\u4e2a\u6388\u6743\u6b65\u9aa4\u3002\u5728\u6bcf\u4e2a\u6388\u6743\u6b65\u9aa4\u4e2d\uff0c\u60a8\u5fc5\u987b\u4ee5\u767b\u673a\u724c\u6216\u5e38\u65c5\u5ba2\u5361\u7684\u5f62\u5f0f\u51fa\u793a\u7d22\u8d54\u3002\u5982\u679c\u60a8\u672a\u83b7\u5f97\u6388\u6743\uff0c\u5219\u8bbf\u95ee\u5c06\u88ab\u62d2\u7edd\u3002<\/p>\n<p>When you arrive at the airport, the \ufb01rst thing you do is go to the check-in counter. Here, you can purchase a plane ticket, but to do so, you need to prove who you are by providing a passport; you authenticate yourself. If you\u2019ve forgotten your passport, you can\u2019t authenticate, and you can\u2019t go any further.<br \/>\n\u5f53\u60a8\u5230\u8fbe\u673a\u573a\u65f6\uff0c\u60a8\u505a\u7684\u7b2c\u4e00\u4ef6\u4e8b\u662f\u524d\u5f80\u503c\u673a\u67dc\u53f0\u3002\u5728\u8fd9\u91cc\uff0c\u60a8\u53ef\u4ee5\u8d2d\u4e70\u673a\u7968\uff0c\u4f46\u8981\u8d2d\u4e70\u673a\u7968\uff0c\u60a8\u9700\u8981\u901a\u8fc7\u63d0\u4f9b\u62a4\u7167\u6765\u8bc1\u660e\u60a8\u7684\u8eab\u4efd;\u60a8\u9a8c\u8bc1\u81ea\u5df1\u3002\u5982\u679c\u60a8\u5fd8\u8bb0\u4e86\u62a4\u7167\uff0c\u5219\u65e0\u6cd5\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4e5f\u65e0\u6cd5\u7ee7\u7eed\u3002<\/p>\n<p>Once you\u2019ve purchased your ticket, you\u2019re issued a boarding pass, which says which \ufb02ight you\u2019re on. We\u2019ll assume that it also includes a BoardingPassNumber. You can think of this number as an additional claim associated with your identity.<br \/>\n\u8d2d\u4e70\u673a\u7968\u540e\uff0c\u60a8\u5c06\u6536\u5230\u4e00\u5f20\u767b\u673a\u724c\uff0c\u4e0a\u9762\u5199\u7740\u60a8\u4e58\u5750\u7684\u822a\u73ed\u3002\u6211\u4eec\u5047\u8bbe\u5b83\u8fd8\u5305\u62ec BoardingPassNumber\u3002\u60a8\u53ef\u4ee5\u5c06\u6b64\u53f7\u7801\u89c6\u4e3a\u4e0e\u60a8\u7684\u8eab\u4efd\u5173\u8054\u7684\u9644\u52a0\u58f0\u660e\u3002<\/p>\n<p><b>DEFINITION<\/b> A claim is a piece of information about a user that consists of a type and an optional value.<br \/>\n\u5b9a\u4e49:\u58f0\u660e\u662f\u6709\u5173\u7528\u6237\u7684\u4e00\u6761\u4fe1\u606f\uff0c\u7531\u7c7b\u578b\u548c\u53ef\u9009\u503c\u7ec4\u6210\u3002<\/p>\n<p>The next step is security. The security guards ask you to present your boarding pass for inspection, which they use to check that you have a \ufb02ight and so are allowed deeper into the airport. This is an authorization process: you must have the required claim (a BoardingPassNumber) to proceed.<br \/>\n\u4e0b\u4e00\u6b65\u662f\u5b89\u5168\u6027\u3002\u4fdd\u5b89\u8981\u6c42\u60a8\u51fa\u793a\u767b\u673a\u724c\u4ee5\u4f9b\u68c0\u67e5\uff0c\u4ed6\u4eec\u7528\u5b83\u6765\u68c0\u67e5\u60a8\u662f\u5426\u6709\u822a\u73ed\uff0c\u56e0\u6b64\u53ef\u4ee5\u8fdb\u5165\u673a\u573a\u66f4\u6df1\u5904\u3002\u8fd9\u662f\u4e00\u4e2a\u6388\u6743\u8fc7\u7a0b\uff1a\u60a8\u5fc5\u987b\u62e5\u6709\u6240\u9700\u7684\u58f0\u660e \uff08BoardingPassNumber\uff09 \u624d\u80fd\u7ee7\u7eed\u3002<\/p>\n<p>If you don\u2019t have a valid BoardingPassNumber, there are two possibilities for what happens next:<br \/>\n\u5982\u679c\u60a8\u6ca1\u6709\u6709\u6548\u7684 BoardingPassNumber\uff0c\u5219\u63a5\u4e0b\u6765\u6709\u4e24\u79cd\u53ef\u80fd\u7684\u60c5\u51b5\uff1a<\/p>\n<p>\u2022  If you haven\u2019t yet purchased a ticket\u2014You\u2019ll be directed back to the check-in desk, where you can authenticate and purchase a ticket. At that point, you can try to enter security again.<br \/>\n\u5982\u679c\u60a8\u5c1a\u672a\u8d2d\u4e70\u673a\u7968 - \u60a8\u5c06\u88ab\u5f15\u5bfc\u56de\u503c\u673a\u67dc\u53f0\uff0c\u5728\u90a3\u91cc\u60a8\u53ef\u4ee5\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u548c\u8d2d\u4e70\u673a\u7968\u3002\u6b64\u65f6\uff0c\u60a8\u53ef\u4ee5\u5c1d\u8bd5\u518d\u6b21\u8fdb\u5165\u5b89\u68c0\u3002<\/p>\n<p>\u2022  If you have an invalid ticket\u2014You won\u2019t be allowed through security, and there\u2019s nothing else you can do. If, for example, you show up with a boarding pass a week late for your \ufb02ight, they probably won\u2019t let you through. (Ask me how I know!)<br \/>\n\u5982\u679c\u60a8\u7684\u673a\u7968\u65e0\u6548 - \u60a8\u5c06\u4e0d\u88ab\u5141\u8bb8\u901a\u8fc7\u5b89\u68c0\uff0c\u5e76\u4e14\u60a8\u65e0\u80fd\u4e3a\u529b\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u7684\u822a\u73ed\u767b\u673a\u724c\u665a\u4e86\u4e00\u5468\uff0c\u4ed6\u4eec\u53ef\u80fd\u4e0d\u4f1a\u8ba9\u60a8\u901a\u8fc7\u3002\uff08\u95ee\u6211\u600e\u4e48\u77e5\u9053\u7684\uff01\uff09<\/p>\n<p>Once you\u2019re through security, you need to wait for your \ufb02ight to start boarding, but unfortunately, there aren\u2019t any seats free. Typical! Luckily, you\u2019re a regular \ufb02yer, and you\u2019ve notched up enough miles to achieve Gold frequent-\ufb02yer status, so you can use the airline lounge.<br \/>\n\u901a\u8fc7\u5b89\u68c0\u540e\uff0c\u60a8\u9700\u8981\u7b49\u5f85\u822a\u73ed\u5f00\u59cb\u767b\u673a\uff0c\u4f46\u4e0d\u5e78\u7684\u662f\uff0c\u6ca1\u6709\u4efb\u4f55\u7a7a\u4f4d\u3002\u5178\u578b\uff01\u5e78\u8fd0\u7684\u662f\uff0c\u60a8\u662f\u4e00\u540d\u666e\u901a\u4e58\u5ba2\uff0c\u5e76\u4e14\u60a8\u5df2\u7ecf\u79ef\u7d2f\u4e86\u8db3\u591f\u7684\u91cc\u7a0b\u6765\u83b7\u5f97\u91d1\u5361\u5e38\u65c5\u5ba2\u8eab\u4efd\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u4f7f\u7528\u822a\u7a7a\u516c\u53f8\u4f11\u606f\u5ba4\u3002<\/p>\n<p>You head to the lounge, where you\u2019re asked to present your Gold frequent-\ufb02yer card to the attendant, and they let you in. This is another example of authorization. You must have a FrequentFlyerClass claim with a value of Gold to proceed.<br \/>\n\u60a8\u524d\u5f80\u4f11\u606f\u5ba4\uff0c\u5728\u90a3\u91cc\u60a8\u88ab\u8981\u6c42\u5411\u670d\u52a1\u5458\u51fa\u793a\u60a8\u7684\u9ec4\u91d1\u5e38\u65c5\u5ba2\u5361\uff0c\u4ed6\u4eec\u8ba9\u60a8\u8fdb\u5165\u3002\u8fd9\u662f\u6388\u6743\u7684\u53e6\u4e00\u4e2a\u793a\u4f8b\u3002\u60a8\u5fc5\u987b\u6709\u4e00\u4e2a\u4ef7\u503c\u4e3a Gold \u7684 FrequentFlyerClass \u7d22\u8d54\u624d\u80fd\u7ee7\u7eed\u3002<\/p>\n<p><b>NOTE<\/b>  You\u2019ve used authorization twice so far in this scenario. Each time, you presented a claim to proceed. In the \ufb01rst case, the presence of any BoardingPassNumber was su\ufb03cient, whereas for the FrequentFlyerClass claim, you needed the speci\ufb01c value of Gold.<br \/>\n\u6ce8\u610f\uff1a\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u5728\u6b64\u65b9\u6848\u4e2d\uff0c\u4f60\u5df2\u4f7f\u7528\u4e24\u6b21\u6388\u6743\u3002\u6bcf\u6b21\uff0c\u60a8\u90fd\u4f1a\u63d0\u51fa\u8981\u7ee7\u7eed\u7684\u7d22\u8d54\u3002\u5728\u7b2c\u4e00\u79cd\u60c5\u51b5\u4e0b\uff0c\u4efb\u4f55 BoardingPassNumber \u7684\u5b58\u5728\u5c31\u8db3\u591f\u4e86\uff0c\u800c\u5bf9\u4e8e FrequentFlyerClass \u58f0\u660e\uff0c\u60a8\u9700\u8981 Gold \u7684\u7279\u5b9a\u503c\u3002<\/p>\n<p>When you\u2019re boarding the airplane, you have one \ufb01nal authorization step, in which you must present the BoardingPassNumber claim again. You presented this claim earlier, but boarding the aircraft is a distinct action from entering security, so you have to present it again.<br \/>\n\u5f53\u60a8\u767b\u673a\u65f6\uff0c\u60a8\u6709\u4e00\u4e2a\u6700\u540e\u7684\u6388\u6743\u6b65\u9aa4\uff0c\u5728\u8be5\u6b65\u9aa4\u4e2d\uff0c\u60a8\u5fc5\u987b\u518d\u6b21\u63d0\u4f9b BoardingPassNumber \u58f0\u660e\u3002\u60a8\u4e4b\u524d\u63d0\u4ea4\u4e86\u6b64\u58f0\u660e\uff0c\u4f46\u767b\u673a\u4e0e\u8fdb\u5165\u5b89\u68c0\u662f\u4e0d\u540c\u7684\u4f5c\uff0c\u56e0\u6b64\u60a8\u5fc5\u987b\u518d\u6b21\u63d0\u4ea4\u3002<\/p>\n<p>This whole scenario has lots of parallels with requests to a web app:<br \/>\n\u6574\u4e2a\u573a\u666f\u4e0e\u5bf9 Web \u5e94\u7528\u7a0b\u5e8f\u7684\u8bf7\u6c42\u6709\u5f88\u591a\u76f8\u4f3c\u4e4b\u5904\uff1a<\/p>\n<p>\u2022  Both processes start with authentication.<br \/>\n\u4e24\u4e2a\u8fc7\u7a0b\u90fd\u4ece\u8eab\u4efd\u9a8c\u8bc1\u5f00\u59cb\u3002<br \/>\n\u2022  You must prove who you are to retrieve the claims you need for authorization.<br \/>\n\u60a8\u5fc5\u987b\u8bc1\u660e\u60a8\u662f\u8c01\u624d\u80fd\u68c0\u7d22\u6388\u6743\u6240\u9700\u7684\u7d22\u8d54\u3002<br \/>\n\u2022  You use authorization to protect sensitive actions like entering security and the airline lounge.<br \/>\n\u60a8\u4f7f\u7528\u6388\u6743\u6765\u4fdd\u62a4\u654f\u611f\u4f5c\uff0c\u4f8b\u5982\u8fdb\u5165\u5b89\u68c0\u548c\u822a\u7a7a\u516c\u53f8\u4f11\u606f\u5ba4\u3002<\/p>\n<p>I\u2019ll reuse this airport scenario throughout the chapter to build a simple web application that simulates the steps you take in an airport. We\u2019ve covered the concept of authorization in general, so in the next section we\u2019ll look at how authorization works in ASP.NET Core. We\u2019ll start with the most basic level of authorization, ensuring that only authenticated users can execute an action, and look at what happens when you try to execute such an action.<br \/>\n\u6211\u5c06\u5728\u672c\u7ae0\u4e2d\u91cd\u7528\u8fd9\u4e2a\u673a\u573a\u573a\u666f\u6765\u6784\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u7528\u4e8e\u6a21\u62df\u60a8\u5728\u673a\u573a\u4e2d\u91c7\u53d6\u7684\u6b65\u9aa4\u3002\u6211\u4eec\u5df2\u7ecf\u5927\u81f4\u4ecb\u7ecd\u4e86\u6388\u6743\u7684\u6982\u5ff5\uff0c\u56e0\u6b64\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5982\u4f55\u5728 ASP.NET Core \u4e2d\u5de5\u4f5c\u3002\u6211\u4eec\u5c06\u4ece\u6700\u57fa\u672c\u7684\u6388\u6743\u7ea7\u522b\u5f00\u59cb\uff0c\u786e\u4fdd\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u6267\u884c\u4f5c\uff0c\u5e76\u67e5\u770b\u5f53\u60a8\u5c1d\u8bd5\u6267\u884c\u6b64\u7c7b\u4f5c\u65f6\u4f1a\u53d1\u751f\u4ec0\u4e48\u3002<\/p>\n<h2>24.2 Authorization in ASP.NET Core\u200c<\/h2>\n<p>24.2 ASP.NET Core \u4e2d\u7684\u6388\u6743<\/p>\n<p>In this section you\u2019ll see how the authorization principles described in the previous section apply to an ASP.NET Core application. You\u2019ll learn about the role of the [Authorize] attribute and AuthorizationMiddleware in authorizing requests to Razor Pages and MVC actions. Finally, you\u2019ll learn about the process of preventing unauthenticated users from executing endpoints and what happens when users are unauthorized.\u200c<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u4e0a\u4e00\u8282\u4e2d\u63cf\u8ff0\u7684\u6388\u6743\u539f\u5219\u5982\u4f55\u5e94\u7528\u4e8e ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u3002\u4f60\u5c06\u4e86\u89e3 [Authorize] \u5c5e\u6027\u548c AuthorizationMiddleware \u5728\u6388\u6743\u5bf9 Razor Pages \u548c MVC\u4f5c\u7684\u8bf7\u6c42\u4e2d\u7684\u4f5c\u7528\u3002\u6700\u540e\uff0c\u60a8\u5c06\u4e86\u89e3\u9632\u6b62\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u6267\u884c\u7ec8\u7aef\u8282\u70b9\u7684\u8fc7\u7a0b\uff0c\u4ee5\u53ca\u5f53\u7528\u6237\u672a\u7ecf\u6388\u6743\u65f6\u4f1a\u53d1\u751f\u4ec0\u4e48\u3002<\/p>\n<p>The ASP.NET Core framework has authorization built in, so you can use it anywhere in your app, but it\u2019s most common to apply authorization via the AuthorizationMiddleware. The AuthorizationMiddleware should be placed after both the routing middleware and the authentication middleware but before the endpoint middleware, as shown in \ufb01gure 24.2.<br \/>\nASP.NET Core \u6846\u67b6\u5185\u7f6e\u4e86\u6388\u6743\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4efb\u4f55\u4f4d\u7f6e\u4f7f\u7528\u5b83\uff0c\u4f46\u6700\u5e38\u89c1\u7684\u662f\u901a\u8fc7 AuthorizationMiddleware \u5e94\u7528\u6388\u6743\u3002AuthorizationMiddleware \u5e94\u8be5\u653e\u5728 routing \u4e2d\u95f4\u4ef6\u548c authentication \u4e2d\u95f4\u4ef6\u4e4b\u540e\uff0c\u4f46\u5728 endpoint middleware \u4e4b\u524d\uff0c\u5982\u56fe 24.2 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2402.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.2 Authorization occurs after an endpoint has been selected and after the request is authenticated, but before the action method or Razor Page endpoint is executed.<br \/>\n\u56fe 24.2 \u5728\u9009\u62e9\u7ec8\u7ed3\u70b9\u4e4b\u540e\u548c\u5bf9\u8bf7\u6c42\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u4e4b\u540e\uff0c\u4f46\u5728\u6267\u884c\u4f5c\u65b9\u6cd5\u6216 Razor Page \u7ec8\u7ed3\u70b9\u4e4b\u524d\uff0c\u8fdb\u884c\u6388\u6743\u3002<\/p>\n<p><b>NOTE<\/b>  Remember that in ASP.NET Core, an endpoint refers to the handler selected by the routing middleware, which generates a response when executed. It is typically a Razor Page, a web API controller action method, or a minimal API endpoint handler.<br \/>\n\u6ce8\u610f\u8bf7\u8bb0\u4f4f\uff0c\u5728 ASP.NET Core \u4e2d\uff0c\u7ec8\u7aef\u8282\u70b9\u662f\u6307\u8def\u7531\u4e2d\u95f4\u4ef6\u9009\u62e9\u7684\u5904\u7406\u7a0b\u5e8f\uff0c\u8be5\u5904\u7406\u7a0b\u5e8f\u5728\u6267\u884c\u65f6\u751f\u6210\u54cd\u5e94\u3002\u5b83\u901a\u5e38\u662f Razor Page\u3001Web API \u63a7\u5236\u5668\u4f5c\u65b9\u6cd5\u6216\u6700\u5c0f API \u7aef\u70b9\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>With this con\ufb01guration, the RoutingMiddleware selects an endpoint to execute based on the request\u2019s URL, such as a Razor Page, as you saw in chapter 14. Metadata about the selected endpoint is available to all middleware that occurs after the routing middleware. This metadata includes details about any authorization requirements for the endpoint, and it\u2019s typically attached by decorating an action or Razor Page with an [Authorize] attribute.<br \/>\n\u4f7f\u7528\u6b64\u914d\u7f6e\uff0cRoutingMiddleware \u6839\u636e\u8bf7\u6c42\u7684 URL \u9009\u62e9\u8981\u6267\u884c\u7684\u7ec8\u7ed3\u70b9\uff0c\u4f8b\u5982 Razor Page\uff0c\u5982\u7b2c 14 \u7ae0\u6240\u793a\u3002\u6709\u5173\u6240\u9009\u7ec8\u7aef\u8282\u70b9\u7684\u5143\u6570\u636e\u53ef\u7528\u4e8e\u8def\u7531\u4e2d\u95f4\u4ef6\u4e4b\u540e\u51fa\u73b0\u7684\u6240\u6709\u4e2d\u95f4\u4ef6\u3002\u6b64\u5143\u6570\u636e\u5305\u62ec\u6709\u5173\u7ec8\u7ed3\u70b9\u7684\u4efb\u4f55\u6388\u6743\u8981\u6c42\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u901a\u5e38\u901a\u8fc7\u4f7f\u7528 [Authorize] \u5c5e\u6027\u4fee\u9970\u4f5c\u6216 Razor \u9875\u9762\u6765\u9644\u52a0\u3002<\/p>\n<p>The AuthenticationMiddleware deserializes the encrypted cookie (or bearer token for APIs) associated with the request to create a ClaimsPrincipal. This object is set as the HttpContext.User for the request, so all subsequent middleware can access this value. It contains all the Claims that were added to the cookie when the user authenticated.<br \/>\nAuthenticationMiddleware \u53cd\u5e8f\u5217\u5316\u4e0e\u521b\u5efa ClaimsPrincipal \u7684\u8bf7\u6c42\u5173\u8054\u7684\u52a0\u5bc6 Cookie\uff08\u6216 API \u7684\u6301\u6709\u8005\u4ee4\u724c\uff09\u3002\u6b64\u5bf9\u8c61\u8bbe\u7f6e\u4e3a\u8bf7\u6c42\u7684 HttpContext.User\uff0c\u56e0\u6b64\u6240\u6709\u540e\u7eed\u4e2d\u95f4\u4ef6\u90fd\u53ef\u4ee5\u8bbf\u95ee\u6b64\u503c\u3002\u5b83\u5305\u542b\u5728\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u65f6\u6dfb\u52a0\u5230 Cookie \u7684\u6240\u6709\u58f0\u660e\u3002<\/p>\n<p><b>NOTE<\/b>  Remember that the authentication middleware may be placed before the routing middleware when the authentication process is the same for all endpoints.<br \/>\n\u6ce8\u610f\uff1a\u8bf7\u8bb0\u4f4f\uff0c\u5f53\u6240\u6709\u7aef\u70b9\u7684\u8eab\u4efd\u9a8c\u8bc1\u8fc7\u7a0b\u90fd\u76f8\u540c\u65f6\uff0c\u53ef\u4ee5\u5c06\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u653e\u5728\u8def\u7531\u4e2d\u95f4\u4ef6\u4e4b\u524d\u3002<\/p>\n<p>Nevertheless, I prefer to place it as shown in \ufb01gure 24.2, after the routing middleware, and always before the authorization middleware.<br \/>\n\u5c3d\u7ba1\u5982\u6b64\uff0c\u6211\u66f4\u559c\u6b22\u5c06\u5b83\u5982\u56fe 24.2 \u6240\u793a\uff0c\u653e\u5728 routing middleware \u4e4b\u540e\uff0c\u5e76\u4e14\u603b\u662f\u653e\u5728 authorization middleware \u4e4b\u524d\u3002<\/p>\n<p>Now we come to the AuthorizationMiddleware. This middleware checks whether the selected endpoint has any authorization requirements, based on the metadata provided by the RoutingMiddleware. If the endpoint has authorization requirements, the AuthorizationMiddleware uses the HttpContext.User to determine whether the current request is authorized to execute the endpoint.<br \/>\n\u73b0\u5728\u6211\u4eec\u6765\u770b\u770b AuthorizationMiddleware\u3002\u6b64\u4e2d\u95f4\u4ef6\u6839\u636e RoutingMiddleware \u63d0\u4f9b\u7684\u5143\u6570\u636e\u68c0\u67e5\u6240\u9009\u7aef\u70b9\u662f\u5426\u5177\u6709\u4efb\u4f55\u6388\u6743\u8981\u6c42\u3002\u5982\u679c\u7aef\u70b9\u6709\u6388\u6743\u8981\u6c42\uff0c\u5219 AuthorizationMiddleware \u4f7f\u7528 HttpContext.User \u6765\u786e\u5b9a\u5f53\u524d\u8bf7\u6c42\u662f\u5426\u88ab\u6388\u6743\u6267\u884c\u7aef\u70b9\u3002<\/p>\n<p>If the request is authorized, the next middleware in the pipeline executes as normal. If the request is not authorized, the AuthorizationMiddleware short-circuits the middleware pipeline, and the endpoint middleware is never executed.<br \/>\n\u5982\u679c\u8bf7\u6c42\u83b7\u5f97\u6388\u6743\uff0c\u5219\u7ba1\u9053\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4e2d\u95f4\u4ef6\u5c06\u6b63\u5e38\u6267\u884c\u3002\u5982\u679c\u8bf7\u6c42\u672a\u83b7\u5f97\u6388\u6743\uff0c\u5219 AuthorizationMiddleware \u5c06\u4f7f\u4e2d\u95f4\u4ef6\u7ba1\u9053\u77ed\u8def\uff0c\u5e76\u4e14\u6c38\u8fdc\u4e0d\u4f1a\u6267\u884c\u7aef\u70b9\u4e2d\u95f4\u4ef6\u3002<\/p>\n<p><b>NOTE<\/b>  The call to UseAuthorization() must always be placed after UseRouting() and UseAuthentication(), but before UseEndpoints(). WebApplication automatically adds all this middleware in the correct order, but if you override the position in the pipeline, such as by calling UseRouting(), you must make sure to maintain this overall order.<br \/>\n\u6ce8\u610f\uff1a\u5bf9 UseAuthorization\uff08\uff09 \u7684\u8c03\u7528\u5fc5\u987b\u59cb\u7ec8\u653e\u5728 UseRouting\uff08\uff09 \u548c UseAuthentication\uff08\uff09 \u4e4b\u540e\uff0c\u4f46\u5728 UseEndpoints\uff08\uff09 \u4e4b\u524d\u3002WebApplication \u4f1a\u81ea\u52a8\u4ee5\u6b63\u786e\u7684\u987a\u5e8f\u6dfb\u52a0\u6240\u6709\u8fd9\u4e9b\u4e2d\u95f4\u4ef6\uff0c\u4f46\u662f\u5982\u679c\u4f60\u8986\u76d6\u7ba1\u9053\u4e2d\u7684\u4f4d\u7f6e\uff0c\u4f8b\u5982\u901a\u8fc7\u8c03\u7528 UseRouting\uff08\uff09\uff0c\u5219\u5fc5\u987b\u786e\u4fdd\u4fdd\u6301\u8fd9\u4e2a\u6574\u4f53\u987a\u5e8f\u3002<\/p>\n<p>The AuthorizationMiddleware is responsible for applying authorization requirements and ensuring that only authorized users can execute protected endpoints. In section you\u2019ll learn how to apply the simplest authorization requirement to an endpoint, and in section 24.2.2 you\u2019ll see how the framework responds when a user is not authorized to execute an endpoint.<br \/>\nAuthorizationMiddleware \u8d1f\u8d23\u5e94\u7528\u6388\u6743\u8981\u6c42\u5e76\u786e\u4fdd\u53ea\u6709\u6388\u6743\u7528\u6237\u624d\u80fd\u6267\u884c\u53d7\u4fdd\u62a4\u7684\u7aef\u70b9\u3002\u5728\u90e8\u5206\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5c06\u6700\u7b80\u5355\u7684\u6388\u6743\u8981\u6c42\u5e94\u7528\u4e8e Endpoint\uff0c\u5728 Section 24.2.2 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5f53\u7528\u6237\u65e0\u6743\u6267\u884c Endpoint \u65f6\u6846\u67b6\u5982\u4f55\u54cd\u5e94\u3002<\/p>\n<h3>24.2.1 Preventing anonymous users from accessing your application\u200c<\/h3>\n<p>24.2.1 \u963b\u6b62\u533f\u540d\u7528\u6237\u8bbf\u95ee\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f<\/p>\n<p>When you think about authorization, you typically think about checking whether a particular user has permission to execute an endpoint. In ASP.NET Core you normally achieve this by checking whether a user has a given claim.<br \/>\n\u5728\u8003\u8651\u6388\u6743\u65f6\uff0c\u901a\u5e38\u4f1a\u8003\u8651\u68c0\u67e5\u7279\u5b9a\u7528\u6237\u662f\u5426\u5177\u6709\u6267\u884c\u7ec8\u7aef\u8282\u70b9\u7684\u6743\u9650\u3002\u5728 ASP.NET Core \u4e2d\uff0c\u901a\u5e38\u901a\u8fc7\u68c0\u67e5\u7528\u6237\u662f\u5426\u5177\u6709\u7ed9\u5b9a\u7684\u58f0\u660e\u6765\u5b9e\u73b0\u6b64\u76ee\u7684\u3002<\/p>\n<p>There\u2019s an even more basic level of authorization we haven\u2019t considered yet: allowing only authenticated users to execute an endpoint. This is even simpler than the claims scenario (which we\u2019ll come to later), as there are only two possibilities:<br \/>\n\u8fd8\u6709\u4e00\u4e2a\u66f4\u57fa\u672c\u7684\u6388\u6743\u7ea7\u522b\u6211\u4eec\u8fd8\u6ca1\u6709\u8003\u8651\uff1a\u53ea\u5141\u8bb8\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u6267\u884c\u7aef\u70b9\u3002\u8fd9\u751a\u81f3\u6bd4 claims \u573a\u666f\uff08\u6211\u4eec\u7a0d\u540e\u4f1a\u4ecb\u7ecd\uff09\u8fd8\u8981\u7b80\u5355\uff0c\u56e0\u4e3a\u53ea\u6709\u4e24\u79cd\u53ef\u80fd\u6027\uff1a<\/p>\n<p>\u2022  The user is authenticated\u2014The action executes as normal.<br \/>\n\u7528\u6237\u5df2\u901a\u8fc7 AUTHENTICATED -\u4f5c\u5c06\u6b63\u5e38\u6267\u884c\u3002<br \/>\n\u2022  The user is unauthenticated\u2014The user can\u2019t execute the endpoint.<br \/>\n\u7528\u6237\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1 - \u7528\u6237\u65e0\u6cd5\u6267\u884c\u7aef\u70b9\u3002<\/p>\n<p>You can achieve this basic level of authorization by using the [Authorize] attribute, which you saw in chapter 22 when we discussed authorization \ufb01lters. You can apply this attribute to your actions and Razor Pages, as shown in the following listing, to restrict them to authenticated (logged-in) users only. If an unauthenticated user tries to execute an action or Razor Page protected with the [Authorize] attribute, they\u2019ll be redirected to the login page.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 [Authorize] \u5c5e\u6027\u6765\u5b9e\u73b0\u6b64\u57fa\u672c\u7ea7\u522b\u7684\u6388\u6743\uff0c\u60a8\u5728\u7b2c 22 \u7ae0\u8ba8\u8bba\u6388\u6743\u8fc7\u6ee4\u5668\u65f6\u770b\u5230\u4e86\u8be5\u5c5e\u6027\u3002\u53ef\u4ee5\u5c06\u6b64\u5c5e\u6027\u5e94\u7528\u4e8e\u4f5c\u548c Razor Pages\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\uff0c\u4ee5\u5c06\u5b83\u4eec\u9650\u5236\u4e3a\u4ec5\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff08\u5df2\u767b\u5f55\uff09\u7684\u7528\u6237\u3002\u5982\u679c\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u5c1d\u8bd5\u6267\u884c\u53d7 [Authorize] \u5c5e\u6027\u4fdd\u62a4\u7684\u4f5c\u6216 Razor \u9875\u9762\uff0c\u4ed6\u4eec\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u3002<\/p>\n<p>Listing 24.1 Applying [Authorize] to an action<br \/>\n\u6e05\u5355 24.1 \u5c06 [Authorize] \u5e94\u7528\u4e8e\u4f5c<\/p>\n<pre><code>public class RecipeApiController : ControllerBase\n{\n    public IActionResult List() \u2776\n{\nreturn Ok();\n}\n[Authorize] \u2777\npublic IActionResult View() \u2778\n{\nreturn Ok();\n}\n}<\/code><\/pre>\n<p>\u2776 This action can be executed by anyone, even when not logged in.<br \/>\n\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u6267\u884c\u6b64\u4f5c\uff0c\u5373\u4f7f\u672a\u767b\u5f55\u3002<br \/>\n\u2777 Applies [Authorize] to individual actions, whole controllers, or Razor Pages<br \/>\n\u5c06 [\u6388\u6743] \u5e94\u7528\u4e8e\u5355\u4e2a\u4f5c\u3001\u6574\u4e2a\u63a7\u5236\u5668\u6216 Razor \u9875\u9762<br \/>\n\u2778 This action can be executed only by authenticated users.<br \/>\n\u6b64\u4f5c\u53ea\u80fd\u7531\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u6267\u884c\u3002<\/p>\n<p>Applying the [Authorize] attribute to an endpoint attaches metadata to it, indicating that only authenticated users may access the endpoint. As you saw in \ufb01gure 24.2, this metadata is made available to the AuthorizationMiddleware when an endpoint is selected by the RoutingMiddleware.<br \/>\n\u5c06 [Authorize] \u5c5e\u6027\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\u4f1a\u5c06\u5143\u6570\u636e\u9644\u52a0\u5230\u8be5\u7ec8\u7aef\u8282\u70b9\uff0c\u6307\u793a\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u8bbf\u95ee\u8be5\u7ec8\u7aef\u8282\u70b9\u3002\u5982\u56fe 24.2 \u6240\u793a\uff0c\u5f53 RoutingMiddleware \u9009\u62e9\u7aef\u70b9\u65f6\uff0c\u6b64\u5143\u6570\u636e\u53ef\u4f9b AuthorizationMiddleware \u4f7f\u7528\u3002<\/p>\n<p>You can apply the [Authorize] attribute at the action scope, controller scope, Razor Page scope, or globally, as you saw in chapter 21. Any action or Razor Page that has the [Authorize] attribute applied in this way can be executed only by an authenticated user. Unauthenticated users will be redirected to the login page.<br \/>\n\u53ef\u4ee5\u5728\u4f5c\u8303\u56f4\u3001\u63a7\u5236\u5668\u8303\u56f4\u3001Razor Page \u8303\u56f4\u6216\u5168\u5c40\u5e94\u7528 [Authorize] \u5c5e\u6027\uff0c\u5982\u7b2c 21 \u7ae0\u6240\u793a\u3002\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u5e94\u7528\u4e86 [Authorize] \u5c5e\u6027\u7684\u4efb\u4f55\u4f5c\u6216 Razor \u9875\u9762\u53ea\u80fd\u7531\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u6267\u884c\u3002\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u3002<\/p>\n<p><b>TIP<\/b>  There are several ways to apply the [Authorize] attribute globally. You can read about the options and when to choose which option on my blog: <a href=\"http:\/\/mng.bz\/opQp\">http:\/\/mng.bz\/opQp<\/a>.<br \/>\n\u63d0\u793a\uff1a\u6709\u51e0\u79cd\u65b9\u6cd5\u53ef\u4ee5\u5168\u5c40\u5e94\u7528 [Authorize] \u5c5e\u6027\u3002\u60a8\u53ef\u4ee5\u5728\u6211\u7684\u535a\u5ba2\u4e0a\u9605\u8bfb\u6709\u5173\u9009\u9879\u4ee5\u53ca\u4f55\u65f6\u9009\u62e9\u54ea\u4e2a\u9009\u9879\u7684\u4fe1\u606f\uff1a<a href=\"http:\/\/mng.bz\/opQp\">http:\/\/mng.bz\/opQp<\/a>\u3002<\/p>\n<p>Sometimes, especially when you apply the [Authorize] attribute globally, you might need to poke holes in this authorization requirement. If you apply the [Authorize] attribute globally, any unauthenticated requests are redirected to the login page for your app. But if the [Authorize] attribute is global, when the login page tries to load, you\u2019ll be unauthenticated and redirected to the login page again. And now you\u2019re stuck in an in\ufb01nite redirect loop.<br \/>\n\u6709\u65f6\uff0c\u5c24\u5176\u662f\u5728\u5168\u5c40\u5e94\u7528 [Authorize] \u5c5e\u6027\u65f6\uff0c\u53ef\u80fd\u9700\u8981\u5728\u6b64\u6388\u6743\u8981\u6c42\u4e2d\u6233\u6f0f\u6d1e\u3002\u5982\u679c\u5168\u5c40\u5e94\u7528 [Authorize] \u5c5e\u6027\uff0c\u5219\u4efb\u4f55\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u8bf7\u6c42\u90fd\u5c06\u91cd\u5b9a\u5411\u5230\u5e94\u7528\u7684\u767b\u5f55\u9875\u9762\u3002\u4f46\u662f\uff0c\u5982\u679c [Authorize] \u5c5e\u6027\u662f\u5168\u5c40\u5c5e\u6027\uff0c\u5219\u5f53\u767b\u5f55\u9875\u5c1d\u8bd5\u52a0\u8f7d\u65f6\uff0c\u4f60\u5c06\u88ab\u53d6\u6d88\u8eab\u4efd\u9a8c\u8bc1\u5e76\u518d\u6b21\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u3002\u73b0\u5728\u4f60\u9677\u5165\u4e86\u4e00\u4e2a\u65e0\u9650\u7684\u91cd\u5b9a\u5411\u5faa\u73af\u4e2d\u3002<\/p>\n<p>To get around this, you can direct speci\ufb01c endpoints to ignore the [Authorize] attribute by applying the [AllowAnonymous] attribute to an action or Razor Page, as shown in the next listing. This allows unauthenticated users to execute the action, so you can avoid the redirect loop that would otherwise result.<br \/>\n\u82e5\u8981\u89e3\u51b3\u6b64\u95ee\u9898\uff0c\u53ef\u4ee5\u901a\u8fc7\u5c06 [AllowAnonymous] \u5c5e\u6027\u5e94\u7528\u4e8e\u4f5c\u6216 Razor \u9875\u9762\uff0c\u6307\u793a\u7279\u5b9a\u7ec8\u7ed3\u70b9\u5ffd\u7565 [Authorize] \u5c5e\u6027\uff0c\u5982\u4e0b\u4e00\u4e2a\u5217\u8868\u6240\u793a\u3002\u8fd9\u5141\u8bb8\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u6267\u884c\u4f5c\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u907f\u514d\u5426\u5219\u4f1a\u5bfc\u81f4\u7684\u91cd\u5b9a\u5411\u5faa\u73af\u3002<\/p>\n<p>Listing 24.2 Applying [AllowAnonymous] to allow unauthenticated access<br \/>\n\u6e05\u5355 24.2 \u5e94\u7528 [AllowAnonymous] \u4ee5\u5141\u8bb8\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u8bbf\u95ee<\/p>\n<pre><code>[Authorize] \u2776\npublic class AccountController : ControllerBase\n{\npublic IActionResult ManageAccount() \u2777\n{\nreturn Ok();\n}\n[AllowAnonymous] \u2778\npublic IActionResult Login() \u2779\n{\nreturn Ok();\n}\n}<\/code><\/pre>\n<p>\u2776 Applied at the controller scope, so the user must be authenticated for all actions on the controller<br \/>\n\u5728\u63a7\u5236\u5668\u8303\u56f4\u5185\u5e94\u7528\uff0c\u56e0\u6b64\u7528\u6237\u5fc5\u987b\u5bf9\u63a7\u5236\u5668\u4e0a\u7684\u6240\u6709\u4f5c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1<br \/>\n\u2777 Only authenticated users may execute ManageAccount.<br \/>\n\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u6267\u884c ManageAccount\u3002<br \/>\n\u2778 [AllowAnonymous] overrides [Authorize] to allow unauthenticated users.<br \/>\n[AllowAnonymous] \u8986\u76d6 [Authorize] \u4ee5\u5141\u8bb8\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u3002<br \/>\n\u2779 Login can be executed by anonymous users.<br \/>\n\u533f\u540d\u7528\u6237\u53ef\u4ee5\u6267\u884c\u767b\u5f55\u3002<\/p>\n<p><b>WARNING<\/b> If you apply the [Authorize] attribute globally, be sure to add the [AllowAnonymous] attribute to your login actions, error actions, password reset actions, and any other actions that you need unauthenticated users to execute. If you\u2019re using the default Identity UI described in chapter 23, this is already con\ufb01gured for you.<br \/>\n\u8b66\u544a\uff1a\u5982\u679c\u5168\u5c40\u5e94\u7528 [Authorize] \u5c5e\u6027\uff0c\u8bf7\u786e\u4fdd\u5c06 [AllowAnonymous] \u5c5e\u6027\u6dfb\u52a0\u5230\u767b\u5f55\u4f5c\u3001\u9519\u8bef\u4f5c\u3001\u5bc6\u7801\u91cd\u7f6e\u4f5c\u4ee5\u53ca\u9700\u8981\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u6267\u884c\u7684\u4efb\u4f55\u5176\u4ed6\u4f5c\u3002\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f\u7b2c 23 \u7ae0\u4e2d\u63cf\u8ff0\u7684\u9ed8\u8ba4\u8eab\u4efd UI\uff0c\u5219\u5df2\u4e3a\u60a8\u914d\u7f6e\u4e86\u6b64 UI\u3002<\/p>\n<p>If an unauthenticated user attempts to execute an action protected by the [Authorize] attribute, traditional web apps redirect them to the login page. But what about APIs that don\u2019t have a user interface? And what about more complex scenarios, where a user is logged in but doesn\u2019t have the necessary claims to execute an action? In section we\u2019ll look at how the ASP.NET Core authentication services handle all this for you.<br \/>\n\u5982\u679c\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u5c1d\u8bd5\u6267\u884c\u53d7 [Authorize] \u5c5e\u6027\u4fdd\u62a4\u7684\u4f5c\uff0c\u5219\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4f1a\u5c06\u5176\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u3002\u4f46\u662f\u6ca1\u6709\u7528\u6237\u754c\u9762\u7684 API \u5462\uff1f\u5bf9\u4e8e\u66f4\u590d\u6742\u7684\u60c5\u51b5\uff0c\u5373\u7528\u6237\u5df2\u767b\u5f55\u4f46\u6ca1\u6709\u6267\u884c\u4f5c\u6240\u9700\u7684\u58f0\u660e\uff0c\u8be5\u600e\u4e48\u529e\uff1f\u5728\u90e8\u5206\u6211\u4eec\u5c06\u4e86\u89e3 ASP.NET Core \u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u5982\u4f55\u4e3a\u60a8\u5904\u7406\u6240\u6709\u8fd9\u4e9b\u3002<\/p>\n<h3>24.2.2 Handling unauthorized requests\u200c<\/h3>\n<p>24.2.2 \u5904\u7406\u672a\u7ecf\u6388\u6743\u7684\u8bf7\u6c42<\/p>\n<p>In the previous section you saw how to apply the [Authorize] attribute to an action to ensure that only authenticated users can execute it. In section 24.3 we\u2019ll look at more complex examples that require you to also have a speci\ufb01c claim. In both cases, you must meet one or more authorization requirements (for example, you must be authenticated) to execute the action.\u200c<br \/>\n\u5728\u4e0a\u4e00\u8282\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u5982\u4f55\u5c06 [Authorize] \u5c5e\u6027\u5e94\u7528\u4e8e\u4f5c\uff0c\u4ee5\u786e\u4fdd\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u6267\u884c\u8be5\u4f5c\u3002\u5728 Section 24.3 \u4e2d\uff0c\u6211\u4eec\u5c06\u67e5\u770b\u66f4\u590d\u6742\u7684\u793a\u4f8b\uff0c\u8fd9\u4e9b\u793a\u4f8b\u8981\u6c42\u60a8\u4e5f\u6709\u4e00\u4e2a\u7279\u5b9a\u7684\u58f0\u660e\u3002\u5728\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u90fd\u5fc5\u987b\u6ee1\u8db3\u4e00\u4e2a\u6216\u591a\u4e2a\u6388\u6743\u8981\u6c42\uff08\u4f8b\u5982\uff0c\u60a8\u5fc5\u987b\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff09\u624d\u80fd\u6267\u884c\u4f5c\u3002<\/p>\n<p>If the user meets the authorization requirements, the request passes unimpeded through the AuthorizationMiddleware, and the endpoint is executed in the EndpointMiddleware. If they don\u2019t meet the requirements for the selected endpoint, the AuthorizationMiddleware will short-circuit the request. Depending on why the request failed authorization, the AuthorizationMiddleware generates one of two di\ufb00erent types of responses, as shown in \ufb01gure 24.3:<br \/>\n\u5982\u679c\u7528\u6237\u6ee1\u8db3\u6388\u6743\u8981\u6c42\uff0c\u5219\u8bf7\u6c42\u901a\u8fc7 AuthorizationMiddleware \u7545\u901a\u65e0\u963b\uff0c\u7aef\u70b9\u5728 EndpointMiddleware \u4e2d\u6267\u884c\u3002\u5982\u679c\u5b83\u4eec\u4e0d\u6ee1\u8db3\u6240\u9009\u7ec8\u7aef\u8282\u70b9\u7684\u8981\u6c42\uff0c\u5219 AuthorizationMiddleware \u5c06\u4f7f\u8bf7\u6c42\u77ed\u8def\u3002\u6839\u636e\u8bf7\u6c42\u6388\u6743\u5931\u8d25\u7684\u539f\u56e0\uff0c AuthorizationMiddleware \u751f\u6210\u4e24\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u54cd\u5e94\u4e4b\u4e00\uff0c\u5982\u56fe 24.3 \u6240\u793a\uff1a<\/p>\n<p>\u2022  Challenge\u2014This response indicates that the user was not authorized to execute the action because they weren\u2019t yet logged in.<br \/>\n\u2022 \u8d28\u8be2 - \u6b64\u54cd\u5e94\u8868\u793a\u7528\u6237\u7531\u4e8e\u5c1a\u672a\u767b\u5f55\u800c\u65e0\u6743\u6267\u884c\u4f5c\u3002<\/p>\n<p>\u2022  Forbid\u2014This response indicates that the user was logged in but didn\u2019t meet the requirements to execute the action. They didn\u2019t have a required claim, for example.<br \/>\n\u2022 \u7981\u6b62 - \u6b64\u54cd\u5e94\u8868\u793a\u7528\u6237\u5df2\u767b\u5f55\uff0c\u4f46\u4e0d\u7b26\u5408\u6267\u884c\u4f5c\u7684\u8981\u6c42\u3002\u4f8b\u5982\uff0c\u4ed6\u4eec\u6ca1\u6709\u5fc5\u9700\u7684\u7d22\u8d54\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2403.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.3 The three types of response to an authorization attempt. In the left example, the request contains an authentication cookie, so the user is authenticated in the AuthenticationMiddleware. The AuthorizationMiddleware con\ufb01rms that the authenticated user can access the selected endpoint, so the endpoint is executed. In the center example, the request is not authenticated, so the Authorization- Middleware generates a challenge response. In the right example, the request is authenticated, but the user does not have permission to execute the endpoint, so a forbid response is generated.<br \/>\n\u56fe 24.3 \u5bf9\u6388\u6743\u5c1d\u8bd5\u7684\u4e09\u79cd\u54cd\u5e94\u7c7b\u578b\u3002\u5728\u5de6\u4fa7\u793a\u4f8b\u4e2d\uff0c\u8bf7\u6c42\u5305\u542b\u4e00\u4e2a\u8eab\u4efd\u9a8c\u8bc1 cookie\uff0c\u56e0\u6b64\u5728 AuthenticationMiddleware \u4e2d\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002AuthorizationMiddleware \u786e\u8ba4\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u53ef\u4ee5\u8bbf\u95ee\u9009\u5b9a\u7684\u7ec8\u7aef\u8282\u70b9\uff0c\u56e0\u6b64\u5c06\u6267\u884c\u7ec8\u7aef\u8282\u70b9\u3002\u5728\u4e2d\u95f4\u7684\u793a\u4f8b\u4e2d\uff0c\u8bf7\u6c42\u672a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u56e0\u6b64 Authorization- Middleware \u751f\u6210\u8d28\u8be2\u54cd\u5e94\u3002\u5728\u6b63\u786e\u7684\u793a\u4f8b\u4e2d\uff0c\u8bf7\u6c42\u5df2\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4f46\u7528\u6237\u6ca1\u6709\u6267\u884c\u7ec8\u7aef\u8282\u70b9\u7684\u6743\u9650\uff0c\u56e0\u6b64\u4f1a\u751f\u6210 forbid \u54cd\u5e94\u3002<\/p>\n<p><b>NOTE<\/b>  If you apply the [Authorize] attribute in basic form, as you did in section 24.2.1, you will generate only challenge responses. In this case, a challenge response will be generated for unauthenticated users, but authenticated users will always be authorized.<br \/>\n\u6ce8\u610f\uff1a\u5982\u679c\u4ee5\u57fa\u672c\u5f62\u5f0f\u5e94\u7528 [Authorize] \u5c5e\u6027\uff0c\u5c31\u50cf\u5728\u7b2c 24.2.1 \u8282\u4e2d\u6240\u505a\u7684\u90a3\u6837\uff0c\u60a8\u5c06\u4ec5\u751f\u6210\u8d28\u8be2\u54cd\u5e94\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5c06\u4e3a\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u751f\u6210\u8d28\u8be2\u54cd\u5e94\uff0c\u4f46\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u5c06\u59cb\u7ec8\u83b7\u5f97\u6388\u6743\u3002<\/p>\n<p>The exact HTTP response generated by a challenge or forbid response typically depends on the type of application you\u2019re building and so the type of authentication your application uses: a traditional web application with Razor Pages, or an API application.<br \/>\n\u8d28\u8be2\u6216\u7981\u6b62\u54cd\u5e94\u751f\u6210\u7684\u786e\u5207 HTTP \u54cd\u5e94\u901a\u5e38\u53d6\u51b3\u4e8e\u8981\u6784\u5efa\u7684\u5e94\u7528\u7a0b\u5e8f\u7c7b\u578b\uff0c\u56e0\u6b64\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684\u8eab\u4efd\u9a8c\u8bc1\u7c7b\u578b\uff1a\u5177\u6709 Razor Pages \u7684\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u6216 API \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>For traditional web apps using cookie authentication, such as when you use ASP.NET Core Identity, as in chapter 23, the challenge and forbid responses generate an HTTP redirect to a page in your application. A challenge response indicates the user isn\u2019t yet authenticated, so they\u2019re redirected to the login page for the app. After logging in, they can attempt to execute the protected resource again. A forbid response means the request was from a user that already logged in, but they\u2019re still not allowed to execute the action.<br \/>\n\u5bf9\u4e8e\u4f7f\u7528 Cookie \u8eab\u4efd\u9a8c\u8bc1\u7684\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u4f8b\u5982\u5f53\u60a8\u4f7f\u7528 ASP.NET Core Identity \u65f6\uff08\u5982\u7b2c 23 \u7ae0\u6240\u793a\uff09\uff0cchallenge \u548c forbid \u54cd\u5e94\u4f1a\u751f\u6210\u6307\u5411\u5e94\u7528\u7a0b\u5e8f\u4e2d\u9875\u9762\u7684 HTTP \u91cd\u5b9a\u5411\u3002\u8d28\u8be2\u54cd\u5e94\u6307\u793a\u7528\u6237\u5c1a\u672a\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u56e0\u6b64\u4ed6\u4eec\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u5e94\u7528\u7a0b\u5e8f\u7684\u767b\u5f55\u9875\u9762\u3002\u767b\u5f55\u540e\uff0c\u4ed6\u4eec\u53ef\u4ee5\u5c1d\u8bd5\u518d\u6b21\u6267\u884c\u53d7\u4fdd\u62a4\u7684\u8d44\u6e90\u3002\u7981\u6b62\u54cd\u5e94\u8868\u793a\u8bf7\u6c42\u6765\u81ea\u5df2\u767b\u5f55\u7684\u7528\u6237\uff0c\u4f46\u4ecd\u4e0d\u5141\u8bb8\u4ed6\u4eec\u6267\u884c\u8be5\u4f5c\u3002<\/p>\n<p>Consequently, the user is redirected to a \u201cforbidden\u201d or \u201caccess denied\u201d web page, as shown in \ufb01gure 24.4, which informs them they can\u2019t execute the action or Razor Page.<br \/>\n\u56e0\u6b64\uff0c\u7528\u6237\u5c06\u88ab\u91cd\u5b9a\u5411\u5230 \u201cforbidden\u201d \u6216 \u201caccess denied\u201d \u7f51\u9875\uff0c\u5982\u56fe 24.4 \u6240\u793a\uff0c\u8be5\u7f51\u9875\u901a\u77e5\u4ed6\u4eec\u65e0\u6cd5\u6267\u884c\u4f5c\u6216 Razor Page\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2404.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.4 A forbid response in traditional web apps using cookie authentication. If you don\u2019t have permission to execute a Razor Page and you\u2019re already logged in, you\u2019ll be redirected to an \u201caccess denied\u201d page.<br \/>\n\u56fe 24.4 \u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u4f7f\u7528 cookie \u8eab\u4efd\u9a8c\u8bc1\u7684 forbid \u54cd\u5e94\u3002\u5982\u679c\u60a8\u6ca1\u6709\u6267\u884c Razor \u9875\u9762\u7684\u6743\u9650\uff0c\u5e76\u4e14\u60a8\u5df2\u7ecf\u767b\u5f55\uff0c\u60a8\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u201c\u62d2\u7edd\u8bbf\u95ee\u201d\u9875\u9762\u3002<\/p>\n<p>The preceding behavior is standard for traditional web apps, but API apps typically use a di\ufb00erent approach to authentication, as you\u2019ll see in chapter 25. Instead of logging in and using the API directly, you\u2019d typically log in to a third- party application that provides a token to the client-sidesingle-page application (SPA) or mobile app. The client-side app sends this token when it makes a request to your API.<br \/>\n\u4e0a\u8ff0\u884c\u4e3a\u662f\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u7684\u6807\u51c6\u884c\u4e3a\uff0c\u4f46 API \u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4f7f\u7528\u4e0d\u540c\u7684\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6cd5\uff0c\u5982\u7b2c 25 \u7ae0\u6240\u793a\u3002\u60a8\u901a\u5e38\u4e0d\u4f1a\u76f4\u63a5\u767b\u5f55\u5e76\u4f7f\u7528 API\uff0c\u800c\u662f\u767b\u5f55\u5230\u5411\u5ba2\u6237\u7aef\u63d0\u4f9b\u4ee4\u724c\u7684\u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u5355\u9875\u5e94\u7528\u7a0b\u5e8f \uff08SPA\uff09 \u6216\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u3002\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u5728\u5411 API \u53d1\u51fa\u8bf7\u6c42\u65f6\u53d1\u9001\u6b64\u4ee4\u724c\u3002<\/p>\n<p>Authenticating a request for an API app is essentially identical to a traditional web app that uses cookies, as you\u2019ll see in chapter 25; AuthenticationMiddleware deserializes the credentials to create the ClaimsPrincipal. The di\ufb00erence is in how an API handles authorization failures.<br \/>\n\u5bf9 API \u5e94\u7528\u7a0b\u5e8f\u7684\u8bf7\u6c42\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u4e0e\u4f7f\u7528 cookie \u7684\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u57fa\u672c\u76f8\u540c\uff0c\u5982\u7b2c 25 \u7ae0\u6240\u793a;AuthenticationMiddleware \u53cd\u5e8f\u5217\u5316\u51ed\u636e\u4ee5\u521b\u5efa ClaimsPrincipal\u3002\u533a\u522b\u5728\u4e8e API \u5904\u7406\u6388\u6743\u5931\u8d25\u7684\u65b9\u5f0f\u3002<\/p>\n<p>When an API app generates a challenge response, it returns a 401 Unauthorized error response to the caller. Similarly, when the app generates a forbid response, it returns a 403 Forbidden response. The traditional web app essentially handled these errors by automatically redirecting unauthorized users to the login or \u201caccess denied\u201d page, but the API app doesn\u2019t do this. It\u2019s up to the client-side SPA or mobile app to detect these errors and handle them as appropriate.<br \/>\n\u5f53 API \u5e94\u7528\u751f\u6210\u8d28\u8be2\u54cd\u5e94\u65f6\uff0c\u5b83\u4f1a\u5411\u8c03\u7528\u65b9\u8fd4\u56de 401 Unauthorized \u9519\u8bef\u54cd\u5e94\u3002\u540c\u6837\uff0c\u5f53\u5e94\u7528\u7a0b\u5e8f\u751f\u6210 forbid \u54cd\u5e94\u65f6\uff0c\u5b83\u4f1a\u8fd4\u56de 403 Forbidden \u54cd\u5e94\u3002\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u57fa\u672c\u4e0a\u662f\u901a\u8fc7\u81ea\u52a8\u5c06\u672a\u7ecf\u6388\u6743\u7684\u7528\u6237\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u6216 \u201caccess denied\u201d \u9875\u9762\u6765\u5904\u7406\u8fd9\u4e9b\u9519\u8bef\uff0c\u4f46 API \u5e94\u7528\u7a0b\u5e8f\u4e0d\u4f1a\u8fd9\u6837\u505a\u3002\u5ba2\u6237\u7aef SPA \u6216\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u8d1f\u8d23\u68c0\u6d4b\u8fd9\u4e9b\u9519\u8bef\u5e76\u6839\u636e\u9700\u8981\u5904\u7406\u5b83\u4eec\u3002<\/p>\n<p><b>TIP<\/b>  This di\ufb00erence in authorization behavior is one of the reasons I generally recommend creating separate apps for your APIs and Razor pages apps; it\u2019s possible to have both in the same app, but the con\ufb01guration is often more complex.<br \/>\n\u63d0\u793a\uff1a\u6388\u6743\u884c\u4e3a\u7684\u8fd9\u79cd\u5dee\u5f02\u662f\u6211\u901a\u5e38\u5efa\u8bae\u4e3a\u60a8\u7684 API \u548c Razor \u9875\u9762\u5e94\u7528\u7a0b\u5e8f\u521b\u5efa\u5355\u72ec\u5e94\u7528\u7a0b\u5e8f\u7684\u539f\u56e0\u4e4b\u4e00;\u53ef\u4ee5\u5728\u540c\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u540c\u65f6\u62e5\u6709\u4e24\u8005\uff0c\u4f46\u914d\u7f6e\u901a\u5e38\u66f4\u590d\u6742\u3002<\/p>\n<p>The di\ufb00erent behavior between traditional web apps and SPAs can be confusing initially, but you generally don\u2019t need to worry about that too much in practice. Whether you\u2019re building an API app or a traditional MVC web app, the authorization code in your app looks the same in both cases.<br \/>\n\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u548c SPA \u4e4b\u95f4\u7684\u4e0d\u540c\u884c\u4e3a\u6700\u521d\u53ef\u80fd\u4f1a\u4ee4\u4eba\u56f0\u60d1\uff0c\u4f46\u5728\u5b9e\u8df5\u4e2d\uff0c\u60a8\u901a\u5e38\u4e0d\u9700\u8981\u592a\u62c5\u5fc3\u8fd9\u4e00\u70b9\u3002\u65e0\u8bba\u60a8\u662f\u6784\u5efa API \u5e94\u7528\u7a0b\u5e8f\u8fd8\u662f\u4f20\u7edf\u7684 MVC Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6388\u6743\u4ee3\u7801\u5728\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\u770b\u8d77\u6765\u90fd\u76f8\u540c\u3002<\/p>\n<p>Apply [Authorize] attributes to your endpoints, and let the framework take care of the di\ufb00erences for you.<br \/>\n\u5c06 [Authorize] \u5c5e\u6027\u5e94\u7528\u4e8e\u60a8\u7684\u7ec8\u7aef\u8282\u70b9\uff0c\u8ba9\u6846\u67b6\u4e3a\u60a8\u5904\u7406\u5dee\u5f02\u3002<\/p>\n<p><b>NOTE<\/b>  In chapter 23 you saw how to con\ufb01gure ASP.NET Core Identity in a Razor Pages app. This chapter assumes that you\u2019re building a Razor Pages app too, but the chapter is equally applicable if you\u2019re building an API, as you\u2019ll see in chapter 25. Authorization policies are applied in the same way, whichever style of app you\u2019re building. Only the \ufb01nal response of unauthorized requests di\ufb00ers.<br \/>\n\u6ce8\u610f\uff1a\u5728\u7b2c 23 \u7ae0\u4e2d\uff0c\u4f60\u4e86\u89e3\u4e86\u5982\u4f55\u5728 Razor Pages \u5e94\u7528\u4e2d\u914d\u7f6e ASP.NET \u6838\u5fc3\u6807\u8bc6\u3002\u672c\u7ae0\u5047\u5b9a\u4f60\u4e5f\u5728\u6784\u5efa Razor Pages \u5e94\u7528\uff0c\u4f46\u5982\u679c\u4f60\u6b63\u5728\u6784\u5efa API\uff0c\u5219\u672c\u7ae0\u540c\u6837\u9002\u7528\uff0c\u5982\u7b2c 25 \u7ae0\u6240\u793a\u3002\u65e0\u8bba\u60a8\u6b63\u5728\u6784\u5efa\u54ea\u79cd\u98ce\u683c\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u6388\u6743\u7b56\u7565\u90fd\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u5e94\u7528\u3002\u53ea\u6709\u672a\u6388\u6743\u8bf7\u6c42\u7684\u6700\u7ec8\u54cd\u5e94\u4e0d\u540c\u3002<\/p>\n<p>You\u2019ve seen how to apply the most basic authorization requirement\u2014restricting an endpoint to authenticated users \u2014but most apps need something more subtle than this all-or- nothing approach. Consider the airport scenario from section 24.1. Being authenticated (having a passport) isn\u2019t enough to get you through security. Instead, you also need a speci\ufb01c claim: BoardingPassNumber. In the next section we\u2019ll look at how you can implement a similar requirement in ASP.NET Core.\u200c<br \/>\n\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u5982\u4f55\u5e94\u7528\u6700\u57fa\u672c\u7684\u6388\u6743\u8981\u6c42\uff0c\u5373\u5c06\u7ec8\u7aef\u8282\u70b9\u9650\u5236\u4e3a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\uff0c\u4f46\u5927\u591a\u6570\u5e94\u7528\u7a0b\u5e8f\u9700\u8981\u6bd4\u8fd9\u79cd\u5168\u6709\u6216\u5168\u65e0\u65b9\u6cd5\u66f4\u5fae\u5999\u7684\u4e1c\u897f\u3002\u8003\u8651 24.1 \u8282\u4e2d\u7684\u673a\u573a\u573a\u666f\u3002\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff08\u62e5\u6709\u62a4\u7167\uff09\u4e0d\u8db3\u4ee5\u8ba9\u60a8\u901a\u8fc7\u5b89\u68c0\u3002\u76f8\u53cd\uff0c\u60a8\u8fd8\u9700\u8981\u4e00\u4e2a\u7279\u5b9a\u7684\u58f0\u660e\uff1aBoardingPassNumber\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5982\u4f55\u5728 ASP.NET Core \u4e2d\u5b9e\u73b0\u7c7b\u4f3c\u7684\u8981\u6c42\u3002<\/p>\n<h2>24.3 Using policies for claims- based authorization\u200c<\/h2>\n<p>24.3 \u4f7f\u7528\u7b56\u7565\u8fdb\u884c\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743<\/p>\n<p>In the previous section, you saw how to require that users be logged in to access an endpoint. In this section you\u2019ll see how to apply additional requirements. You\u2019ll learn to use authorization policies to perform claims-based authorization to require that a logged-in user have the required claims to execute a given endpoint.<br \/>\n\u5728\u4e0a\u4e00\u8282\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u5982\u4f55\u8981\u6c42\u7528\u6237\u767b\u5f55\u624d\u80fd\u8bbf\u95ee\u7ec8\u7aef\u8282\u70b9\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5e94\u7528\u5176\u4ed6\u8981\u6c42\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528\u6388\u6743\u7b56\u7565\u6765\u6267\u884c\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\uff0c\u4ee5\u8981\u6c42\u767b\u5f55\u7528\u6237\u5177\u6709\u6267\u884c\u7ed9\u5b9a\u7ec8\u7aef\u8282\u70b9\u6240\u9700\u7684\u58f0\u660e\u3002<\/p>\n<p>In chapter 23 you saw that authentication in ASP.NET Core centers on a ClaimsPrincipal object, which represents the user. This object has a collection of claims that contain pieces of information about the user, such as their name, email, and date of birth.<br \/>\n\u5728\u7b2c 23 \u7ae0\u4e2d\uff0c\u60a8\u770b\u5230 ASP.NET Core \u4e2d\u7684\u8eab\u4efd\u9a8c\u8bc1\u4ee5\u8868\u793a\u7528\u6237\u7684 ClaimsPrincipal \u5bf9\u8c61\u4e3a\u4e2d\u5fc3\u3002\u6b64\u5bf9\u8c61\u5177\u6709\u4e00\u7ec4\u58f0\u660e\uff0c\u5176\u4e2d\u5305\u542b\u6709\u5173\u7528\u6237\u7684\u4fe1\u606f\u7247\u6bb5\uff0c\u4f8b\u5982\u5176\u59d3\u540d\u3001\u7535\u5b50\u90ae\u4ef6\u548c\u51fa\u751f\u65e5\u671f\u3002<\/p>\n<p>You can use this information to customize the app for each user, by displaying a welcome message addressing the user by name, for example, but you can also use claims for authorization. For example, you might authorize a user only if they have a speci\ufb01c claim (such as BoardingPassNumber) or if a claim has a speci\ufb01c value (FrequentFlyerClass claim with the value Gold).<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u6b64\u4fe1\u606f\u4e3a\u6bcf\u4e2a\u7528\u6237\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\uff0c\u4f8b\u5982\uff0c\u901a\u8fc7\u663e\u793a\u6309\u540d\u79f0\u79f0\u547c\u7528\u6237\u7684\u6b22\u8fce\u6d88\u606f\uff0c\u4f46\u60a8\u4e5f\u53ef\u4ee5\u4f7f\u7528\u58f0\u660e\u8fdb\u884c\u6388\u6743\u3002\u4f8b\u5982\uff0c\u4ec5\u5f53\u7528\u6237\u5177\u6709\u7279\u5b9a\u58f0\u660e\uff08\u5982 BoardingPassNumber\uff09\u6216\u58f0\u660e\u5177\u6709\u7279\u5b9a\u503c\uff08\u503c\u4e3a Gold \u7684 FrequentFlyerClass \u58f0\u660e\uff09\u65f6\uff0c\u4f60\u624d\u53ef\u4ee5\u6388\u6743\u7528\u6237\u3002<\/p>\n<p>In ASP.NET Core the rules that de\ufb01ne whether a user is authorized are encapsulated in a policy.<br \/>\n\u5728 ASP.NET Core \u4e2d\uff0c\u5b9a\u4e49\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\u7684\u89c4\u5219\u5c01\u88c5\u5728\u7b56\u7565\u4e2d\u3002<\/p>\n<p><b>DEFINITION<\/b> A policy de\ufb01nes the requirements you must meet for a request to be authorized.<br \/>\n\u5b9a\u4e49\uff1a\u7b56\u7565\u5b9a\u4e49\u8981\u6388\u6743\u8bf7\u6c42\u5fc5\u987b\u6ee1\u8db3\u7684\u8981\u6c42\u3002<\/p>\n<p>Policies can be applied to an endpoint using the [Authorize] attribute, similar to the way you saw in section 24.2.1. This listing shows a Razor Page PageModel that represents the \ufb01rst authorization step in the airport scenario. The AirportSecurity.cshtml Razor Page is protected by an [Authorize] attribute, but you\u2019ve also provided a policy name, &quot;CanEnterSecurity&quot;, as shown in the following listing.<br \/>\n\u53ef\u4ee5\u4f7f\u7528 [Authorize] \u5c5e\u6027\u5c06\u7b56\u7565\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\uff0c\u7c7b\u4f3c\u4e8e\u60a8\u5728\u7b2c 24.2.1 \u8282\u4e2d\u770b\u5230\u7684\u65b9\u5f0f\u3002\u6b64\u5217\u8868\u663e\u793a\u4e86\u4e00\u4e2a Razor Page PageModel\uff0c\u5b83\u8868\u793a airport \u573a\u666f\u4e2d\u7684\u7b2c\u4e00\u4e2a\u6388\u6743\u6b65\u9aa4\u3002AirportSecurity.cshtml Razor \u9875\u9762\u53d7 [Authorize] \u5c5e\u6027\u4fdd\u62a4\uff0c\u4f46\u4f60\u8fd8\u63d0\u4f9b\u4e86\u7b56\u7565\u540d\u79f0\u201cCanEnterSecurity\u201d\uff0c\u5982\u4ee5\u4e0b\u5217\u8868\u6240\u793a\u3002<\/p>\n<p>Listing 24.3 Applying an authorization policy to a Razor Page<br \/>\n\u6e05\u5355 24.3 \u5c06\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e Razor \u9875\u9762<\/p>\n<pre><code>[Authorize(&quot;CanEnterSecurity&quot;)] \u2776\npublic class AirportSecurityModel : PageModel\n{\npublic void OnGet() \u2777\n{\n}\n}<\/code><\/pre>\n<p>\u2776 Applying the \u201cCanEnterSecurity\u201d policy using [Authorize]<br \/>\n\u4f7f\u7528 [Authorize]\u5e94\u7528\u201cCanEnterSecurity\u201d\u7b56\u7565 <\/p>\n<p>\u2777 Only users that satisfy the \u201cCanEnterSecurity\u201d policy can execute the Razor Page.<br \/>\n\u53ea\u6709\u6ee1\u8db3\u201cCanEnterSecurity\u201d\u7b56\u7565\u7684\u7528\u6237\u624d\u80fd\u6267\u884c Razor \u9875\u9762\u3002<\/p>\n<p>If a user attempts to execute the AirportSecurity.cshtml Razor Page, the authorization middleware veri\ufb01es whether the user satis\ufb01es the policy\u2019s requirements (we\u2019ll look at the policy itself shortly). This gives one of three possible outcomes:<br \/>\n\u5982\u679c\u7528\u6237\u5c1d\u8bd5\u6267\u884c AirportSecurity.cshtml Razor \u9875\u9762\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u4f1a\u9a8c\u8bc1\u7528\u6237\u662f\u5426\u6ee1\u8db3\u7b56\u7565\u7684\u8981\u6c42\uff08\u6211\u4eec\u7a0d\u540e\u5c06\u4ecb\u7ecd\u7b56\u7565\u672c\u8eab\uff09\u3002\u8fd9\u5c06\u7ed9\u51fa\u4ee5\u4e0b\u4e09\u79cd\u53ef\u80fd\u7684\u7ed3\u679c\u4e4b\u4e00\uff1a<\/p>\n<p>\u2022  The user satis\ufb01es the policy\u2014The middleware pipeline continues, and the EndpointMiddleware executes the Razor Page as normal.<br \/>\n\u7528\u6237\u6ee1\u8db3\u7b56\u7565 - \u4e2d\u95f4\u4ef6\u7ba1\u9053\u7ee7\u7eed\uff0c\u5e76\u4e14 EndpointMiddleware \u7167\u5e38\u6267\u884c Razor Page\u3002<\/p>\n<p>\u2022  The user is unauthenticated\u2014The user is redirected to the login page.<br \/>\n\u7528\u6237\u672a\u901a\u8fc7 IF - \u7528\u6237\u88ab\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u3002<\/p>\n<p>\u2022  The user is authenticated but doesn\u2019t satisfy the policy\u2014The user is redirected to a \u201cforbidden\u201d or \u201caccess denied\u201d page.<br \/>\n\u7528\u6237\u5df2\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4f46\u4e0d\u6ee1\u8db3\u7b56\u7565 - \u7528\u6237\u88ab\u91cd\u5b9a\u5411\u5230\u201c\u7981\u6b62\u201d\u6216\u201c\u62d2\u7edd\u8bbf\u95ee\u201d\u9875\u9762\u3002<\/p>\n<p>These three outcomes correlate with real-life outcomes you might expect when trying to pass through security at the airport:<br \/>\n\u8fd9\u4e09\u79cd\u7ed3\u679c\u4e0e\u60a8\u5728\u5c1d\u8bd5\u901a\u8fc7\u673a\u573a\u5b89\u68c0\u65f6\u53ef\u80fd\u9884\u671f\u7684\u73b0\u5b9e\u7ed3\u679c\u76f8\u5173\uff1a<\/p>\n<p>\u2022  You have a valid boarding pass\u2014You can enter security as normal.<br \/>\n\u60a8\u6301\u6709\u6709\u6548\u7684\u767b\u673a\u724c - \u60a8\u53ef\u4ee5\u6b63\u5e38\u8fdb\u5165\u5b89\u68c0\u3002<\/p>\n<p>\u2022  You don\u2019t have a boarding pass\u2014You\u2019re redirected to purchase a ticket.<br \/>\n\u60a8\u6ca1\u6709\u767b\u673a\u724c - \u60a8\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u8d2d\u4e70\u673a\u7968\u3002<\/p>\n<p>\u2022  Your boarding pass is invalid (you turned up a day late, for example)\u2014You\u2019re blocked from entering.<br \/>\n\u60a8\u7684\u767b\u673a\u724c\u65e0\u6548\uff08\u4f8b\u5982\uff0c\u60a8\u8fdf\u5230\u4e00\u5929\uff09- \u60a8\u88ab\u963b\u6b62\u8fdb\u5165\u3002<\/p>\n<p>Listing 24.3 shows how you can apply a policy to a Razor Page using the [Authorize] attribute, but you still need to de\ufb01ne the CanEnterSecurity policy.<br \/>\n\u6e05\u5355 24.3 \u663e\u793a\u4e86\u5982\u4f55\u4f7f\u7528 [Authorize] \u5c5e\u6027\u5c06\u7b56\u7565\u5e94\u7528\u4e8e Razor \u9875\u9762\uff0c\u4f46\u60a8\u4ecd\u7136\u9700\u8981\u5b9a\u4e49 CanEnterSecurity \u7b56\u7565\u3002<\/p>\n<p>You add policies to an ASP.NET Core application in Program.cs, as shown in listing 24.4. First, you add the authorization services and return an AuthorizationBuilder object using AddAuthorizationBuilder(). You can then add policies to the builder by calling AddPolicy(). You de\ufb01ne the policy itself by calling methods in a lambda method on a AuthorizationPolicyBuilder (called policyBuilder here).<br \/>\n\u60a8\u53ef\u4ee5\u5728 Program.cs \u4e2d\u5c06\u7b56\u7565\u6dfb\u52a0\u5230 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\uff0c\u5982\u6e05\u5355 24.4 \u6240\u793a\u3002\u9996\u5148\uff0c\u6dfb\u52a0\u6388\u6743\u670d\u52a1\u5e76\u4f7f\u7528 AddAuthorizationBuilder\uff08\uff09 \u8fd4\u56de AuthorizationBuilder \u5bf9\u8c61\u3002\u7136\u540e\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528 AddPolicy\uff08\uff09 \u5c06\u7b56\u7565\u6dfb\u52a0\u5230\u751f\u6210\u5668\u4e2d\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u5728 AuthorizationPolicyBuilder\uff08\u6b64\u5904\u79f0\u4e3a policyBuilder\uff09\u4e0a\u8c03\u7528 lambda \u65b9\u6cd5\u4e2d\u7684\u65b9\u6cd5\u6765\u5b9a\u4e49\u7b56\u7565\u672c\u8eab\u3002<\/p>\n<p>Listing 24.4 Adding an authorization policy using AuthorizationPolicyBuilder<br \/>\n\u6e05\u5355 24.4 \u4f7f\u7528 AuthorizationPolicyBuilder \u6dfb\u52a0\u6388\u6743\u7b56\u7565<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddAuthorizationBuilder() \u2776\n.AddPolicy( \u2777\n&quot;CanEnterSecurity&quot;, \u2778\npolicyBuilder =&gt; policyBuilder \u2779\n.RequireClaim(&quot;BoardingPassNumber&quot;)); \u2779\n});\n\/\/ Additional configuration<\/code><\/pre>\n<p>\u2776 Calls AddAuthorizationBuilder to add the required authorization services<br \/>\n\u8c03\u7528 AddAuthorizationBuilder \u4ee5\u6dfb\u52a0\u6240\u9700\u7684\u6388\u6743\u670d\u52a1<br \/>\n\u2777 Adds a new policy<br \/>\n\u6dfb\u52a0\u65b0\u7b56\u7565<br \/>\n\u2778 Provides a name for the policy<br \/>\n\u4e3a\u7b56\u7565\u63d0\u4f9b\u540d\u79f0<br \/>\n\u2779 Defines the policy requirements using AuthorizationPolicyBuilder<br \/>\n\u4f7f\u7528 AuthorizationPolicyBuilder \u5b9a\u4e49\u7b56\u7565\u8981\u6c42<\/p>\n<p>When you call AddPolicy you provide a name for the policy, which should match the value you use in your [Authorize] attributes, and you de\ufb01ne the requirements of the policy. In this example, you have a single simple requirement: the user must have a claim of type BoardingPassNumber. If a user has this claim, whatever its value, the policy is satis\ufb01ed, and the user will be authorized.<br \/>\n\u8c03\u7528 AddPolicy \u65f6\uff0c\u60a8\u9700\u8981\u4e3a\u7b56\u7565\u63d0\u4f9b\u4e00\u4e2a\u540d\u79f0\uff0c\u8be5\u540d\u79f0\u5e94\u4e0e\u60a8\u5728 [Authorize] \u5c5e\u6027\u4e2d\u4f7f\u7528\u7684\u503c\u5339\u914d\uff0c\u5e76\u5b9a\u4e49\u7b56\u7565\u7684\u8981\u6c42\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u60a8\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u8981\u6c42\uff1a\u7528\u6237\u5fc5\u987b\u5177\u6709 BoardingPassNumber \u7c7b\u578b\u7684\u58f0\u660e\u3002\u5982\u679c\u7528\u6237\u5177\u6709\u6b64\u58f0\u660e\uff0c\u5219\u65e0\u8bba\u5176\u503c\u5982\u4f55\uff0c\u90fd\u6ee1\u8db3\u7b56\u7565\uff0c\u5e76\u4e14\u7528\u6237\u5c06\u83b7\u5f97\u6388\u6743\u3002<\/p>\n<p><b>NOTE<\/b>  A claim is information about the user, as a key-value pair. A policy de\ufb01nes the requirements for successful authorization. A policy may require that a user have a given claim, or it may specify more complex requirements, as you\u2019ll see shortly.<br \/>\n\u6ce8\u610f\uff1a\u58f0\u660e\u662f\u6709\u5173\u7528\u6237\u7684\u4fe1\u606f\uff0c\u4ee5\u952e\u503c\u5bf9\u7684\u5f62\u5f0f\u3002\u7b56\u7565\u5b9a\u4e49\u6210\u529f\u6388\u6743\u7684\u8981\u6c42\u3002\u7b56\u7565\u53ef\u80fd\u8981\u6c42\u7528\u6237\u5177\u6709\u7ed9\u5b9a\u7684\u58f0\u660e\uff0c\u6216\u8005\u5b83\u53ef\u80fd\u6307\u5b9a\u66f4\u590d\u6742\u7684\u8981\u6c42\uff0c\u60a8\u5f88\u5feb\u5c31\u4f1a\u770b\u5230\u3002<\/p>\n<p>AuthorizationPolicyBuilder contains several methods for creating simple policies like this, as shown in table 24.1. For example, an overload of the RequireClaim() method lets you specify a speci\ufb01c value that a claim must have. The following would let you create a policy where the &quot;BoardingPassNumber&quot; claim must have a value of &quot;A1234&quot;:<br \/>\nAuthorizationPolicyBuilder\u5305\u542b\u51e0\u79cd\u7528\u4e8e\u521b\u5efa\u6b64\u7c7b\u7b80\u5355\u7b56\u7565\u7684\u65b9\u6cd5\uff0c\u5982\u8868 24.1 \u6240\u793a\u3002\u4f8b\u5982\uff0cRequireClaim\uff08\uff09 \u65b9\u6cd5\u7684\u91cd\u8f7d\u5141\u8bb8\u60a8\u6307\u5b9a\u58f0\u660e\u5fc5\u987b\u5177\u6709\u7684\u7279\u5b9a\u503c\u3002\u4e0b\u9762\u5c06\u5141\u8bb8\u4f60\u521b\u5efa\u4e00\u4e2a\u7b56\u7565\uff0c\u5176\u4e2d \u201cBoardingPassNumber\u201d \u58f0\u660e\u7684\u503c\u5fc5\u987b\u4e3a\u201cA1234\u201d\uff1a<\/p>\n<pre><code>policyBuilder =&gt; policyBuilder.RequireClaim(&quot;BoardingPassNumber&quot;, &quot;A1234&quot;);<\/code><\/pre>\n<p>Table 24.1 Simple policy builder methods on AuthorizationPolicyBuilder<br \/>\n\u8868 24.1 AuthorizationPolicyBuilder \u4e0a\u7684\u7b80\u5355\u7b56\u7565\u751f\u6210\u5668\u65b9\u6cd5<\/p>\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Policy behavior<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>RequireAuthenticatedUser()<\/td>\n<td>The required user must be authenticated. Creates a policy similar to the default [Authorize] attribute, where you don\u2019t set a policy.<\/td>\n<\/tr>\n<tr>\n<td>RequireClaim(claim, values)<\/td>\n<td>The user must have the speci\ufb01ed claim. If provided, the claim must be one of the speci\ufb01ed values.<\/td>\n<\/tr>\n<tr>\n<td>RequireUsername(username)<\/td>\n<td>The user must have the speci\ufb01ed username.<\/td>\n<\/tr>\n<tr>\n<td>RequireAssertion(function)<\/td>\n<td>Executes the provided lambda function, which returns a bool, indicating whether the policy was satis\ufb01ed.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<blockquote>\n<p>Role-based authorization vs. claims-based authorization<br \/>\n\u57fa\u4e8e\u89d2\u8272\u7684\u6388\u6743\u4e0e\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743<\/p>\n<p>If you look at all of the methods available on the AuthorizationPolicyBuilder type using IntelliSense, you might notice that there\u2019s a method I didn\u2019t mention in table 24.1: RequireRole(). This is a remnant of the role-based approach to authorization used in previous versions of ASP.NET, and I don\u2019t recommend using it.<br \/>\n\u5982\u679c\u60a8\u4f7f\u7528 IntelliSense \u67e5\u770b AuthorizationPolicyBuilder \u7c7b\u578b\u4e0a\u7684\u6240\u6709\u53ef\u7528\u65b9\u6cd5\uff0c\u60a8\u53ef\u80fd\u4f1a\u6ce8\u610f\u5230\u6211\u5728\u8868 24.1 \u4e2d\u6ca1\u6709\u63d0\u5230\u7684\u65b9\u6cd5\uff1aRequireRole\uff08\uff09\u3002\u8fd9\u662f ASP.NET \u65e9\u671f\u7248\u672c\u4e2d\u4f7f\u7528\u7684\u57fa\u4e8e\u89d2\u8272\u7684\u6388\u6743\u65b9\u6cd5\u7684\u6b8b\u4f59\u90e8\u5206\uff0c\u6211\u4e0d\u5efa\u8bae\u4f7f\u7528\u5b83\u3002<\/p>\n<p>Before Microsoft adopted the claims-based authorization used by ASP.NET, role-based authorization was the norm. Users were assigned to one or more roles, such as Administrator or Manager, and authorization involved checking whether the current user was in the required role.\u200c<br \/>\n\u5728 Microsoft \u91c7\u7528 ASP.NET \u4f7f\u7528\u7684\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u4e4b\u524d\uff0c\u57fa\u4e8e\u89d2\u8272\u7684\u6388\u6743\u662f\u5e38\u6001\u3002\u5c06\u7528\u6237\u5206\u914d\u7ed9\u4e00\u4e2a\u6216\u591a\u4e2a\u89d2\u8272\uff0c\u4f8b\u5982 Administrator \u6216 Manager\uff0c\u6388\u6743\u6d89\u53ca\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u4f4d\u4e8e\u6240\u9700\u7684\u89d2\u8272\u4e2d\u3002<\/p>\n<p>This role-based approach to authorization is possible in ASP.NET Core, but it\u2019s used primarily for legacy compatibility reasons. Claims-based authorization is the suggested approach. Unless you\u2019re porting a legacy app that uses roles, I suggest that you embrace claims-based authorization and leave those roles behind.<br \/>\n\u8fd9\u79cd\u57fa\u4e8e\u89d2\u8272\u7684\u6388\u6743\u65b9\u6cd5\u5728 ASP.NET Core \u4e2d\u662f\u53ef\u80fd\u7684\uff0c\u4f46\u5b83\u4e3b\u8981\u7528\u4e8e\u65e7\u7248\u517c\u5bb9\u6027\u539f\u56e0\u3002\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u662f\u5efa\u8bae\u7684\u65b9\u6cd5\u3002\u9664\u975e\u60a8\u8981\u79fb\u690d\u4f7f\u7528\u89d2\u8272\u7684\u65e7\u5e94\u7528\u7a0b\u5e8f\uff0c\u5426\u5219\u6211\u5efa\u8bae\u60a8\u91c7\u7528\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\uff0c\u5e76\u5c06\u8fd9\u4e9b\u89d2\u8272\u629b\u5728\u8111\u540e\u3002<\/p>\n<p>Note that the fact that you\u2019re using claims-based permissions doesn\u2019t mean you need to get rid of roles entirely, but you should use roles as a basis for assigning claims to a user rather than authorize that a user belongs to one or more roles.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u4f7f\u7528\u57fa\u4e8e\u58f0\u660e\u7684\u6743\u9650\u8fd9\u4e00\u4e8b\u5b9e\u5e76\u4e0d\u610f\u5473\u7740\u9700\u8981\u5b8c\u5168\u5220\u9664\u89d2\u8272\uff0c\u4f46\u5e94\u4f7f\u7528\u89d2\u8272\u4f5c\u4e3a\u5c06\u58f0\u660e\u5206\u914d\u7ed9\u7528\u6237\u7684\u57fa\u7840\uff0c\u800c\u4e0d\u662f\u6388\u6743\u7528\u6237\u5c5e\u4e8e\u4e00\u4e2a\u6216\u591a\u4e2a\u89d2\u8272\u3002<\/p>\n<\/blockquote>\n<p>You can use these methods to build simple policies that can handle basic situations, but often you\u2019ll need something more complicated. What if you want to create a policy that enforces that only users over the age of 18 can execute an endpoint?<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e9b\u65b9\u6cd5\u6765\u6784\u5efa\u53ef\u4ee5\u5904\u7406\u57fa\u672c\u60c5\u51b5\u7684\u7b80\u5355\u7b56\u7565\uff0c\u4f46\u901a\u5e38\u9700\u8981\u66f4\u590d\u6742\u7684\u7b56\u7565\u3002\u5982\u679c\u8981\u521b\u5efa\u4e00\u4e2a\u7b56\u7565\uff0c\u5f3a\u5236\u8981\u6c42\u53ea\u6709 18 \u5c81\u4ee5\u4e0a\u7684\u7528\u6237\u624d\u80fd\u6267\u884c\u7ec8\u7aef\u8282\u70b9\uff0c\u8be5\u600e\u4e48\u529e\uff1f<\/p>\n<p>The DateOfBirth claim provides the information you need, but there\u2019s no single correct value, so you couldn\u2019t use the RequireClaim() method. You could use the RequireAssertion() method and provide a function that calculates the age from the DateOfBirth claim, but that could get messy pretty quickly.<br \/>\nDateOfBirth \u58f0\u660e\u63d0\u4f9b\u6240\u9700\u7684\u4fe1\u606f\uff0c\u4f46\u6ca1\u6709\u5355\u4e2a\u6b63\u786e\u7684\u503c\uff0c\u56e0\u6b64\u65e0\u6cd5\u4f7f\u7528 RequireClaim\uff08\uff09 \u65b9\u6cd5\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 RequireAssertion\uff08\uff09 \u65b9\u6cd5\u5e76\u63d0\u4f9b\u4e00\u4e2a\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u6839\u636e DateOfBirth \u58f0\u660e\u8ba1\u7b97\u5e74\u9f84\uff0c\u4f46\u8fd9\u5f88\u5feb\u5c31\u4f1a\u53d8\u5f97\u6df7\u4e71\u3002<\/p>\n<p>For more complex policies that can\u2019t be easily de\ufb01ned using the RequireClaim() method, I recommend that you take a di\ufb00erent approach and create a custom policy, as you\u2019ll see in the following section.\u200c<br \/>\n\u5bf9\u4e8e\u65e0\u6cd5\u4f7f\u7528 RequireClaim\uff08\uff09 \u65b9\u6cd5\u8f7b\u677e\u5b9a\u4e49\u7684\u66f4\u590d\u6742\u7684\u7b56\u7565\uff0c\u6211\u5efa\u8bae\u60a8\u91c7\u7528\u4e0d\u540c\u7684\u65b9\u6cd5\u5e76\u521b\u5efa\u81ea\u5b9a\u4e49\u7b56\u7565\uff0c\u5982\u4e0b\u4e00\u8282\u6240\u793a\u3002<\/p>\n<h2>27.4 Creating custom policies for authorization\u200c<\/h2>\n<p>27.4 \u521b\u5efa\u81ea\u5b9a\u4e49\u6388\u6743\u7b56\u7565<\/p>\n<p>You\u2019ve already seen how to create a policy by requiring a speci\ufb01c claim or requiring a speci\ufb01c claim with a speci\ufb01c value, but often the requirements will be more complex than that. In this section you\u2019ll learn how to create custom authorization requirements and handlers. You\u2019ll also see how to con\ufb01gure authorization requirements where there are multiple ways to satisfy a policy, any of which are valid.<br \/>\n\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u5982\u4f55\u901a\u8fc7\u8981\u6c42\u7279\u5b9a\u58f0\u660e\u6216\u8981\u6c42\u5177\u6709\u7279\u5b9a\u503c\u7684\u7279\u5b9a\u58f0\u660e\u6765\u521b\u5efa\u7b56\u7565\uff0c\u4f46\u8981\u6c42\u901a\u5e38\u6bd4\u8fd9\u66f4\u590d\u6742\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u521b\u5efa\u81ea\u5b9a\u4e49\u6388\u6743\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u3002\u60a8\u8fd8\u5c06\u4e86\u89e3\u5982\u4f55\u914d\u7f6e\u6388\u6743\u8981\u6c42\uff0c\u5176\u4e2d\u6709\u591a\u79cd\u65b9\u6cd5\u53ef\u4ee5\u6ee1\u8db3\u7b56\u7565\uff0c\u5176\u4e2d\u4efb\u4f55\u4e00\u79cd\u90fd\u662f\u6709\u6548\u7684\u3002<\/p>\n<p>Let\u2019s return to the airport example. You\u2019ve already con\ufb01gured the policy for passing through security, and now you\u2019re going to con\ufb01gure the policy that controls whether you\u2019re authorized to enter the airline lounge.<br \/>\n\u8ba9\u6211\u4eec\u56de\u5230\u673a\u573a\u7684\u4f8b\u5b50\u3002\u60a8\u5df2\u7ecf\u914d\u7f6e\u4e86\u901a\u8fc7\u5b89\u68c0\u7684\u7b56\u7565\uff0c\u73b0\u5728\u60a8\u5c06\u914d\u7f6e\u63a7\u5236\u60a8\u662f\u5426\u6709\u6743\u8fdb\u5165\u822a\u7a7a\u516c\u53f8\u4f11\u606f\u5ba4\u7684\u7b56\u7565\u3002<\/p>\n<p>As you saw in \ufb01gure 24.1, you\u2019re allowed to enter the lounge if you have a FrequentFlyerClass claim with a value of Gold. If this was the only requirement, you could use AuthorizationPolicyBuilder to create a policy like this:<br \/>\n\u5982\u56fe 24.1 \u6240\u793a\uff0c\u5982\u679c\u60a8\u6709\u4ef7\u503c\u4e3a Gold \u7684 FrequentFlyerClass \u7d22\u8d54\uff0c\u5219\u53ef\u4ee5\u8fdb\u5165\u4f11\u606f\u5ba4\u3002\u5982\u679c\u8fd9\u662f\u552f\u4e00\u7684\u8981\u6c42\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 AuthorizationPolicyBuilder \u521b\u5efa\u5982\u4e0b\u6240\u793a\u7684\u7b56\u7565\uff1a<\/p>\n<pre><code>options.AddPolicy(&quot;CanAccessLounge&quot;, policyBuilder =&gt; policyBuilder.RequireClaim(&quot;FrequentFlyerClass&quot;, &quot;Gold&quot;));<\/code><\/pre>\n<p>But what if the requirements are more complicated? For example, suppose you can enter the lounge if you\u2019re at least 18 years old (as calculated from the DateOfBirth claim) and you\u2019re one of the following:<br \/>\n\u4f46\u662f\uff0c\u5982\u679c\u8981\u6c42\u66f4\u590d\u6742\u5462\uff1f\u4f8b\u5982\uff0c\u5047\u8bbe\u60a8\u81f3\u5c11\u5e74\u6ee1 18 \u5c81\uff08\u6839\u636e DateOfBirth \u58f0\u660e\u8ba1\u7b97\uff09\u5e76\u4e14\u60a8\u662f\u4ee5\u4e0b\u4e4b\u4e00\uff0c\u5219\u53ef\u4ee5\u8fdb\u5165\u4f11\u606f\u5ba4\uff1a<\/p>\n<p>\u2022  You\u2019re a Gold-class frequent \ufb02yer (have a FrequentFlyerClass claim with value &quot;Gold&quot;)<br \/>\n\u60a8\u662f\u91d1\u5361\u7ea7\u5e38\u65c5\u5ba2\uff08\u6709\u4ef7\u503c\u4e3a\u201c\u91d1\u5361\u201d\u7684 FrequentFlyerClass \u7d22\u8d54\uff09<br \/>\n\u2022  You\u2019re an employee of the airline (have an EmployeeNumber claim).<br \/>\n\u60a8\u662f\u822a\u7a7a\u516c\u53f8\u7684\u5458\u5de5\uff08\u6709 EmployeeNumber \u7d22\u8d54\uff09\u3002<\/p>\n<p>If you\u2019ve ever been banned from the lounge (you have an IsBannedFromLounge claim), you won\u2019t be allowed in, even if you satisfy the other requirements.<br \/>\n\u5982\u679c\u60a8\u66fe\u7ecf\u88ab\u7981\u6b62\u8fdb\u5165\u4f11\u606f\u5ba4\uff08\u60a8\u6709 IsBannedFromLounge \u7d22\u8d54\uff09\uff0c\u5373\u4f7f\u60a8\u6ee1\u8db3\u5176\u4ed6\u8981\u6c42\uff0c\u4e5f\u4e0d\u4f1a\u88ab\u5141\u8bb8\u8fdb\u5165\u3002<\/p>\n<p>There\u2019s no way of achieving this complex set of requirements with the basic use of AuthorizationPolicyBuilder you\u2019ve seen so far. Luckily, these methods are a wrapper around a set of building blocks that you can combine to achieve the desired policy.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u60a8\u6240\u770b\u5230\u7684 AuthorizationPolicyBuilder \u7684\u57fa\u672c\u7528\u6cd5\u65e0\u6cd5\u5b9e\u73b0\u8fd9\u7ec4\u590d\u6742\u7684\u8981\u6c42\u3002\u5e78\u8fd0\u7684\u662f\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u662f\u4e00\u7ec4\u6784\u5efa\u5757\u7684\u5305\u88c5\u5668\uff0c\u60a8\u53ef\u4ee5\u7ec4\u5408\u8fd9\u4e9b\u6784\u5efa\u5757\u6765\u5b9e\u73b0\u6240\u9700\u7684\u7b56\u7565\u3002<\/p>\n<h3>24.4.1 Requirements and handlers: The building blocks of a policy\u200c<\/h3>\n<p>24.4.1 \u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\uff1a\u7b56\u7565\u7684\u6784\u5efa\u5757<\/p>\n<p>Every policy in ASP.NET Core consists of one or more requirements, and every requirement can have one or more handlers. For the airport lounge example, you have a single policy (&quot;CanAccessLounge&quot;), two requirements (MinimumAgeRequirement and AllowedInLoungeRequirement), and several handlers, as shown in \ufb01gure 24.5.<br \/>\nASP.NET Core \u4e2d\u7684\u6bcf\u4e2a\u7b56\u7565\u90fd\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u8981\u6c42\uff0c\u6bcf\u4e2a\u8981\u6c42\u53ef\u4ee5\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002\u5bf9\u4e8e\u673a\u573a\u4f11\u606f\u5ba4\u793a\u4f8b\uff0c\u60a8\u6709\u4e00\u4e2a\u7b56\u7565\uff08\u201cCanAccessLounge\u201d\uff09\u3001\u4e24\u4e2a\u8981\u6c42\uff08MinimumAgeRequirement \u548c AllowedInLoungeRequirement\uff09\u548c\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\uff0c\u5982\u56fe 24.5 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2405.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.5 A policy can have many requirements, and every requirement can have many handlers. By combining multiple requirements in a policy and providing multiple handler implementations, you can create complex authorization policies that meet any of your business requirements.<br \/>\n\u56fe 24.5 \u4e00\u4e2a\u7b56\u7565\u53ef\u4ee5\u6709\u5f88\u591a\u9700\u6c42\uff0c\u6bcf\u4e2a\u9700\u6c42\u53ef\u4ee5\u6709\u5f88\u591a\u5904\u7406\u7a0b\u5e8f\u3002\u901a\u8fc7\u5728\u7b56\u7565\u4e2d\u7ec4\u5408\u591a\u4e2a\u8981\u6c42\u5e76\u63d0\u4f9b\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u5b9e\u65bd\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u6ee1\u8db3\u4efb\u4f55\u4e1a\u52a1\u9700\u6c42\u7684\u590d\u6742\u6388\u6743\u7b56\u7565\u3002<\/p>\n<p>For a policy to be satis\ufb01ed, a user must ful\ufb01ll all the requirements. If the user fails any of the requirements, the authorize middleware won\u2019t allow the protected endpoint to be executed. In this example, a user must be allowed to access the lounge and must be over 18 years old.<br \/>\n\u8981\u6ee1\u8db3\u7b56\u7565\uff0c\u7528\u6237\u5fc5\u987b\u6ee1\u8db3\u6240\u6709\u8981\u6c42\u3002\u5982\u679c\u7528\u6237\u4e0d\u7b26\u5408\u4efb\u4f55\u8981\u6c42\uff0c\u5219 authorize \u4e2d\u95f4\u4ef6\u5c06\u4e0d\u5141\u8bb8\u6267\u884c\u53d7\u4fdd\u62a4\u7684\u7ec8\u7aef\u8282\u70b9\u3002\u5728\u6b64\u793a\u4f8b\u4e2d\uff0c\u5fc5\u987b\u5141\u8bb8\u7528\u6237\u8bbf\u95ee\u4f11\u606f\u5ba4\uff0c\u5e76\u4e14\u5fc5\u987b\u5e74\u6ee1 18 \u5c81\u3002<\/p>\n<p>Each requirement can have one or more handlers, which will con\ufb01rm that the requirement has been satis\ufb01ed. For example, as shown in \ufb01gure 24.5, AllowedInLoungeRequirement has two handlers that can satisfy the requirement:<br \/>\n\u6bcf\u4e2a\u8981\u6c42\u90fd\u53ef\u4ee5\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\uff0c\u8fd9\u4e9b\u5904\u7406\u7a0b\u5e8f\u5c06\u786e\u8ba4\u5df2\u6ee1\u8db3\u8981\u6c42\u3002\u4f8b\u5982\uff0c\u5982\u56fe 24.5 \u6240\u793a\uff0cAllowedInLoungeRequirement \u6709\u4e24\u4e2a\u53ef\u4ee5\u6ee1\u8db3\u8981\u6c42\u7684\u5904\u7406\u7a0b\u5e8f\uff1a<\/p>\n<p>\u2022  FrequentFlyerHandler<br \/>\n\u2022  IsAirlineEmployeeHandler<\/p>\n<p>If the user satis\ufb01es either of these handlers, AllowedInLoungeRequirement is satis\ufb01ed. You don\u2019t need all handlers for a requirement to be satis\ufb01ed; you need only one.<br \/>\n\u5982\u679c\u7528\u6237\u6ee1\u8db3\u5176\u4e2d\u4efb\u4e00\u5904\u7406\u7a0b\u5e8f\uff0c\u5219\u6ee1\u8db3 AllowedInLoungeRequirement\u3002\u60a8\u4e0d\u9700\u8981\u6ee1\u8db3\u6240\u6709\u5904\u7406\u7a0b\u5e8f\u5373\u53ef\u6ee1\u8db3\u9700\u6c42;\u4f60\u53ea\u9700\u8981\u4e00\u4e2a\u3002<\/p>\n<p><b>NOTE<\/b>  Figure 24.5 shows a third handler,BannedFromLoungeHandler, which I\u2019ll cover in section 24.4.2. It\u2019s slightly di\ufb00erent in that it can fail a requirement but not satisfy it.<br \/>\n\u6ce8\u610f:\u56fe 24.5 \u663e\u793a\u4e86\u7b2c\u4e09\u4e2a\u5904\u7406\u7a0b\u5e8f BannedFromLoungeHandler\uff0c\u6211\u5c06\u5728 24.4.2 \u8282\u4e2d\u4ecb\u7ecd\u3002\u5b83\u7565\u6709\u4e0d\u540c\uff0c\u56e0\u4e3a\u5b83\u53ef\u80fd\u4e0d\u7b26\u5408\u8981\u6c42\uff0c\u4f46\u4e0d\u80fd\u6ee1\u8db3\u5b83\u3002<\/p>\n<p>You can use requirements and handlers to achieve most any combination of behavior you need for a policy. By combining handlers for a requirement, you can validate conditions using a logical OR: if any of the handlers is satis\ufb01ed, the requirement is satis\ufb01ed. By combining requirements, you create a logical AND: all the requirements must be satis\ufb01ed for the policy to be satis\ufb01ed, as shown in \ufb01gure 24.6.\u200c<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u6765\u5b9e\u73b0\u7b56\u7565\u6240\u9700\u7684\u5927\u591a\u6570\u884c\u4e3a\u7ec4\u5408\u3002\u901a\u8fc7\u7ec4\u5408\u9700\u6c42\u7684\u5904\u7406\u7a0b\u5e8f\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u903b\u8f91 OR \u9a8c\u8bc1\u6761\u4ef6\uff1a\u5982\u679c\u6ee1\u8db3\u4efb\u4f55\u5904\u7406\u7a0b\u5e8f\uff0c\u5219\u6ee1\u8db3\u9700\u6c42\u3002\u901a\u8fc7\u7ec4\u5408\u9700\u6c42\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u903b\u8f91 AND\uff1a\u5fc5\u987b\u6ee1\u8db3\u6240\u6709\u8981\u6c42\u624d\u80fd\u6ee1\u8db3\u7b56\u7565\uff0c\u5982\u56fe 24.6 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2406.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.6 For a policy to be satis\ufb01ed, every requirement must be satis\ufb01ed. A requirement is satis\ufb01ed if any of the handlers is satis\ufb01ed.<br \/>\n\u56fe 24.6 \u8981\u6ee1\u8db3\u7b56\u7565\uff0c\u5fc5\u987b\u6ee1\u8db3\u6240\u6709\u8981\u6c42\u3002\u5982\u679c\u6ee1\u8db3\u4efb\u4f55\u5904\u7406\u7a0b\u5e8f\uff0c\u5219\u6ee1\u8db3\u8981\u6c42\u3002<\/p>\n<p><b>TIP<\/b>  You can add multiple policies to a Razor Page or action method by applying the [Authorize] attribute multiple times, as in [Authorize (&quot;Policy1&quot;), Authorize(&quot;Policy2&quot;)]. All policies must be satis\ufb01ed for the request to be authorized.<br \/>\n\u63d0\u793a:\u53ef\u4ee5\u901a\u8fc7\u591a\u6b21\u5e94\u7528 [Authorize] \u5c5e\u6027\uff0c\u5c06\u591a\u4e2a\u7b56\u7565\u6dfb\u52a0\u5230 Razor \u9875\u9762\u6216\u4f5c\u65b9\u6cd5\uff0c\u5982 [Authorize \uff08\u201cPolicy1\u201d\uff09\uff0c Authorize\uff08\u201cPolicy2\u201d\uff09] \u4e2d\u6240\u793a\u3002\u5fc5\u987b\u6ee1\u8db3\u6240\u6709\u7b56\u7565\uff0c\u8bf7\u6c42\u624d\u80fd\u83b7\u5f97\u6388\u6743\u3002<\/p>\n<p>I\u2019ve highlighted requirements and handlers that will make up your &quot;CanAccessLounge&quot; policy, so in the next section you\u2019ll build each of the components and apply them to the airport sample app.<br \/>\n\u6211\u5df2\u7ecf\u91cd\u70b9\u4ecb\u7ecd\u4e86\u6784\u6210\u201cCanAccessLounge\u201d\u7b56\u7565\u7684\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\uff0c\u56e0\u6b64\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u6784\u5efa\u6bcf\u4e2a\u7ec4\u4ef6\u5e76\u5c06\u5b83\u4eec\u5e94\u7528\u4e8e airport \u793a\u4f8b\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<h3>24.4.2 Creating a policy with a custom requirement and handler\u200c<\/h3>\n<p>24.4.2 \u521b\u5efa\u5177\u6709\u81ea\u5b9a\u4e49\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u7684\u7b56\u7565<\/p>\n<p>You\u2019ve seen all the pieces that make up a custom authorization policy, so in this section we\u2019ll explore the implementation of the &quot;CanAccessLounge&quot; policy.<br \/>\n\u60a8\u5df2\u7ecf\u4e86\u89e3\u4e86\u6784\u6210\u81ea\u5b9a\u4e49\u6388\u6743\u7b56\u7565\u7684\u6240\u6709\u90e8\u5206\uff0c\u56e0\u6b64\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u63a2\u8ba8 \u201cCanAccessLounge\u201d \u7b56\u7565\u7684\u5b9e\u73b0\u3002<\/p>\n<blockquote>\n<p>CREATING AN IAUTHORIZATIONREQUIREMENT TO REPRESENT A REQUIREMENT<br \/>\n\u521b\u5efa IAUTHORIZATIONREQUIREMENT \u4ee5\u8868\u793a\u8981\u6c42<\/p>\n<\/blockquote>\n<p>As you\u2019ve seen, a custom policy can have multiple requirements, but what is a requirement in code terms? Authorization requirements in ASP.NET Core are any class that implements the IAuthorizationRequirement interface. This is a blank marker interface, which you can apply to any class to indicate that it represents a requirement.<br \/>\n\u5982\u60a8\u6240\u89c1\uff0c\u81ea\u5b9a\u4e49\u7b56\u7565\u53ef\u4ee5\u6709\u591a\u4e2a\u8981\u6c42\uff0c\u4f46\u4ee3\u7801\u672f\u8bed\u4e2d\u7684\u8981\u6c42\u662f\u4ec0\u4e48\uff1fASP.NET Core \u4e2d\u7684\u6388\u6743\u8981\u6c42\u662f\u5b9e\u73b0 IAuthorizationRequirement \u63a5\u53e3\u7684\u4efb\u4f55\u7c7b\u3002\u8fd9\u662f\u4e00\u4e2a\u7a7a\u767d\u6807\u8bb0\u63a5\u53e3\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u5e94\u7528\u4e8e\u4efb\u4f55\u7c7b\uff0c\u4ee5\u6307\u793a\u5b83\u8868\u793a\u8981\u6c42\u3002<\/p>\n<p>If the interface doesn\u2019t have any members, you might be wondering what the requirement class needs to look like. Typically, they\u2019re simple plain old CLR object (POCO) classes. The following listing shows AllowedInLoungeRequirement, which is about as simple as a requirement can get. It has no properties or methods; it implements the required IAuthorizationRequirement interface.<br \/>\n\u5982\u679c\u63a5\u53e3\u6ca1\u6709\u4efb\u4f55\u6210\u5458\uff0c\u60a8\u53ef\u80fd\u60f3\u77e5\u9053 requirement \u7c7b\u9700\u8981\u662f\u4ec0\u4e48\u6837\u5b50\u3002\u901a\u5e38\uff0c\u5b83\u4eec\u662f\u7b80\u5355\u7684\u666e\u901a\u65e7 CLR \u5bf9\u8c61 \uff08POCO\uff09 \u7c7b\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86 AllowedInLoungeRequirement\uff0c\u8fd9\u4e0e\u8981\u6c42\u6240\u80fd\u83b7\u5f97\u7684\u6700\u4f4e\u8981\u6c42\u5dee\u4e0d\u591a\u3002\u5b83\u6ca1\u6709\u5c5e\u6027\u6216\u65b9\u6cd5;\u5b83\u5b9e\u73b0\u6240\u9700\u7684 IAuthorizationRequirement \u63a5\u53e3\u3002<\/p>\n<p>Listing 24.5 AllowedInLoungeRequirement<\/p>\n<pre><code>public class AllowedInLoungeRequirement\n    : IAuthorizationRequirement { } \u2776<\/code><\/pre>\n<p>\u2776 The interface identi\ufb01es the class as an authorization requirement.<br \/>\n\u63a5\u53e3\u5c06\u7c7b\u6807\u8bc6\u4e3a\u6388\u6743\u8981\u6c42\u3002<\/p>\n<p>This is the simplest form of requirement, but it\u2019s also common to have one or two properties that make the requirement more generalized. For example, instead of creating the highly speci\ufb01c MustBe18YearsOldRequirement, you could create a parameterized MinimumAgeRequirement, as shown in the following listing. By providing the minimum age as a parameter to the requirement, you can reuse the requirement for other policies with di\ufb00erent minimum-age requirements.<br \/>\n\u8fd9\u662f\u6700\u7b80\u5355\u7684\u8981\u6c42\u5f62\u5f0f\uff0c\u4f46\u901a\u5e38\u5177\u6709\u4e00\u4e24\u4e2a\u4f7f\u8981\u6c42\u66f4\u901a\u7528\u7684\u5c5e\u6027\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u53c2\u6570\u5316\u7684 MinimumAgeRequirement\uff0c\u800c\u4e0d\u662f\u521b\u5efa\u9ad8\u5ea6\u5177\u4f53\u7684 MustBe18YearsOldRequirement\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u901a\u8fc7\u63d0\u4f9b\u6700\u4f4e\u5e74\u9f84\u4f5c\u4e3a\u8981\u6c42\u7684\u53c2\u6570\uff0c\u60a8\u53ef\u4ee5\u5c06\u8be5\u8981\u6c42\u91cd\u65b0\u7528\u4e8e\u5177\u6709\u4e0d\u540c\u6700\u4f4e\u5e74\u9f84\u8981\u6c42\u7684\u5176\u4ed6\u4fdd\u5355\u3002<\/p>\n<p>Listing 24.6 The parameterized MinimumAgeRequirement<br \/>\n\u6e05\u5355 24.6 \u53c2\u6570\u5316\u7684 MinimumAgeRequirement<\/p>\n<pre><code>public class MinimumAgeRequirement : IAuthorizationRequirement \u2776\n{\npublic MinimumAgeRequirement(int minimumAge) \u2777\n{\nMinimumAge = minimumAge;\n}\npublic int MinimumAge { get; } \u2778\n}<\/code><\/pre>\n<p>\u2776 The interface identi\ufb01es the class as an authorization requirement.<br \/>\n\u63a5\u53e3\u5c06\u7c7b\u6807\u8bc6\u4e3a\u6388\u6743\u8981\u6c42\u3002<\/p>\n<p>\u2777 The minimum age is provided when the requirement is created.<br \/>\n\u521b\u5efa\u8981\u6c42\u65f6\u63d0\u4f9b\u6700\u4f4e\u5e74\u9f84\u3002<\/p>\n<p>\u2778 Handlers can use the exposed minimum age to determine whether the requirement is satis\ufb01ed.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528\u516c\u5f00\u7684\u6700\u5c0f\u5e74\u9f84\u6765\u786e\u5b9a\u662f\u5426\u6ee1\u8db3\u8981\u6c42\u3002<\/p>\n<p>The requirements are the easy part. They represent each of the components of the policy that must be satis\ufb01ed for the policy to be satis\ufb01ed overall. Note that requirements are meant to be lightweight objects that can be created \u201cmanually.\u201d So while you can have constructor parameters, as shown in listing 24.6, you can\u2019t use dependency injection (DI) here. That\u2019s not as limiting as it sounds, because your handlers can use DI.<br \/>\n\u8981\u6c42\u662f\u6700\u7b80\u5355\u7684\u90e8\u5206\u3002\u5b83\u4eec\u8868\u793a\u7b56\u7565\u7684\u6bcf\u4e2a\u7ec4\u6210\u90e8\u5206\uff0c\u5fc5\u987b\u6ee1\u8db3\u8fd9\u4e9b\u7ec4\u6210\u90e8\u5206\u624d\u80fd\u4f7f\u7b56\u7565\u603b\u4f53\u4e0a\u5f97\u5230\u6ee1\u8db3\u3002\u8bf7\u6ce8\u610f\uff0c\u9700\u6c42\u662f\u53ef\u4ee5 \u201c\u624b\u52a8\u201d \u521b\u5efa\u7684\u8f7b\u91cf\u7ea7\u5bf9\u8c61\u3002\u56e0\u6b64\uff0c\u867d\u7136\u4f60\u53ef\u4ee5\u6709\u6784\u9020\u51fd\u6570\u53c2\u6570\uff0c\u5982\u6e05\u5355 24.6 \u6240\u793a\uff0c\u4f46\u4f60\u4e0d\u80fd\u5728\u8fd9\u91cc\u4f7f\u7528\u4f9d\u8d56\u6ce8\u5165 \uff08DI\uff09\u3002\u8fd9\u5e76\u4e0d\u50cf\u542c\u8d77\u6765\u90a3\u4e48\u9650\u5236\uff0c\u56e0\u4e3a\u4f60\u7684\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528 DI\u3002<\/p>\n<blockquote>\n<p>CREATING A POLICY WITH MULTIPLE REQUIREMENTS<br \/>\n\u521b\u5efa\u5177\u6709\u591a\u4e2a\u8981\u6c42\u7684\u7b56\u7565<\/p>\n<\/blockquote>\n<p>You\u2019ve created the two requirements, so now you can con\ufb01gure the &quot;CanAccessLounge&quot; policy to use them. You con\ufb01gure your policies as you did before, in Program.cs.<br \/>\n\u60a8\u5df2\u7ecf\u521b\u5efa\u4e86\u8fd9\u4e24\u4e2a\u8981\u6c42\uff0c\u56e0\u6b64\u73b0\u5728\u53ef\u4ee5\u914d\u7f6e \u201cCanAccessLounge\u201d \u7b56\u7565\u6765\u4f7f\u7528\u5b83\u4eec\u3002\u60a8\u53ef\u4ee5\u50cf\u4ee5\u524d\u4e00\u6837\u5728 Program.cs \u4e2d\u914d\u7f6e\u7b56\u7565\u3002<\/p>\n<p>Listing 24.7 shows how to do this by creating an instance of each requirement and passing them to AuthorizationPolicyBuilder. The authorization handlers use these requirement objects when attempting to authorize the policy.<br \/>\n\u6e05\u5355 24.7 \u5c55\u793a\u4e86\u5982\u4f55\u901a\u8fc7\u521b\u5efa\u6bcf\u4e2a\u9700\u6c42\u7684\u5b9e\u4f8b\u5e76\u5c06\u5b83\u4eec\u4f20\u9012\u7ed9AuthorizationPolicyBuilder\u6765\u505a\u5230\u8fd9\u4e00\u70b9\u3002\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u5728\u5c1d\u8bd5\u6388\u6743\u7b56\u7565\u65f6\u4f7f\u7528\u8fd9\u4e9b\u8981\u6c42\u5bf9\u8c61\u3002<\/p>\n<p>Listing 24.7 Creating an authorization policy with multiple requirements<br \/>\n\u6e05\u5355 24.7 \u521b\u5efa\u5177\u6709\u591a\u4e2a\u9700\u6c42\u7684\u6388\u6743\u7b56\u7565<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.services.AddAuthorization(options =&gt;\n{ \u2776\noptions.AddPolicy( \u2776\n&quot;CanEnterSecurity&quot;, \u2776\npolicyBuilder =&gt; policyBuilder \u2776\n.RequireClaim(Claims.BoardingPassNumber)); \u2776\noptions.AddPolicy( \u2777\n&quot;CanAccessLounge&quot;, \u2777\npolicyBuilder =&gt; policyBuilder.AddRequirements( \u2778\nnew MinimumAgeRequirement(18), \u2778\nnew AllowedInLoungeRequirement() \u2778\n));\n});\n\/\/ Additional configuration<\/code><\/pre>\n<p>\u2776 Adds the previous simple policy for passing through security<br \/>\n\u65b0\u589e\u4e4b\u524d\u7b80\u5355\u7684\u901a\u8fc7\u5b89\u68c0\u7b56\u7565<\/p>\n<p>\u2777 Adds a new policy for the airport lounge, called CanAccessLounge<br \/>\n\u4e3a\u673a\u573a\u8d35\u5bbe\u5ba4\u6dfb\u52a0\u4e00\u9879\u540d\u4e3a CanAccessLounge \u7684\u65b0\u653f\u7b56<br \/>\n\u2778 Adds an instance of each IAuthorizationRequirement object<br \/>\n\u6dfb\u52a0\u6bcf\u4e2a IAuthorizationRequirement \u5bf9\u8c61\u7684\u5b9e\u4f8b<\/p>\n<p>You now have a policy called &quot;CanAccessLounge&quot; with two requirements, so you can apply it to a Razor Page or action method using the [Authorize] attribute, in exactly the same way you did for the &quot;CanEnterSecurity&quot; policy:<br \/>\n\u73b0\u5728\uff0c\u60a8\u6709\u4e00\u4e2a\u540d\u4e3a\u201cCanAccessLounge\u201d\u7684\u7b56\u7565\uff0c\u5176\u4e2d\u5305\u542b\u4e24\u4e2a\u8981\u6c42\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u4f7f\u7528 [Authorize] \u5c5e\u6027\u5c06\u5176\u5e94\u7528\u4e8e Razor \u9875\u9762\u6216\u4f5c\u65b9\u6cd5\uff0c\u5176\u65b9\u5f0f\u4e0e\u5bf9\u201cCanEnterSecurity\u201d\u7b56\u7565\u6267\u884c\u7684\u4f5c\u5b8c\u5168\u76f8\u540c\uff1a<\/p>\n<pre><code>[Authorize(&quot;CanAccessLounge&quot;)]\npublic class AirportLoungeModel : PageModel\n{\npublic void OnGet() { }\n}<\/code><\/pre>\n<p>When a request is routed to the AirportLounge.cshtml Razor Page, the authorize middleware executes the authorization policy and each of the requirements is inspected. But you saw earlier that the requirements are purely data; they indicate what needs to be ful\ufb01lled, but they don\u2019t describe how that has to happen. For that, you need to write some handlers.<br \/>\n\u5c06\u8bf7\u6c42\u8def\u7531\u5230 AirportLounge.cshtml Razor \u9875\u9762\u65f6\uff0cauthorize \u4e2d\u95f4\u4ef6\u5c06\u6267\u884c\u6388\u6743\u7b56\u7565\u5e76\u68c0\u67e5\u6bcf\u4e2a\u8981\u6c42\u3002\u4f46\u60a8\u4e4b\u524d\u770b\u5230\uff0c\u8fd9\u4e9b\u8981\u6c42\u7eaf\u7cb9\u662f\u6570\u636e;\u5b83\u4eec\u6307\u51fa\u4e86\u9700\u8981\u6ee1\u8db3\u4ec0\u4e48\uff0c\u4f46\u6ca1\u6709\u63cf\u8ff0\u5fc5\u987b\u5982\u4f55\u5b9e\u73b0\u3002\u4e3a\u6b64\uff0c\u60a8\u9700\u8981\u7f16\u5199\u4e00\u4e9b\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<blockquote>\n<p>CREATING AUTHORIZATION HANDLERS TO SATISFY YOUR REQUIREMENTS<br \/>\n\u521b\u5efa\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u4ee5\u6ee1\u8db3\u60a8\u7684\u8981\u6c42<\/p>\n<\/blockquote>\n<p>Authorization handlers contain the logic of how a speci\ufb01c IAuthorizationRequirement can be satis\ufb01ed. When executed, a handler can do one of three things:<br \/>\n\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u5305\u542b\u5982\u4f55\u6ee1\u8db3\u7279\u5b9a IAuthorizationRequirement \u7684\u903b\u8f91\u3002\u6267\u884c\u65f6\uff0c\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u6267\u884c\u4ee5\u4e0b\u4e09\u9879\u4f5c\u4e4b\u4e00\uff1a<\/p>\n<p>\u2022  Mark the requirement handling as a success.<br \/>\n\u5c06\u9700\u6c42\u5904\u7406\u6807\u8bb0\u4e3a\u6210\u529f\u3002<\/p>\n<p>\u2022  Do nothing.<br \/>\n\u4ec0\u4e48\u90fd\u4e0d\u505a\u3002<\/p>\n<p>\u2022  Explicitly fail the requirement.<br \/>\n\u660e\u786e\u4e0d\u7b26\u5408\u8981\u6c42\u3002<\/p>\n<p>Handlers should implement AuthorizationHandler<T>, where T is the type of requirement they handle. For example, the following listing shows a handler for AllowedInLoungeRequirement that checks whether the user has a claim called FrequentFlyerClass with a value of Gold.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u5e94\u5b9e\u73b0 AuthorizationHandler\uff0c\u5176\u4e2d T \u662f\u5b83\u4eec\u5904\u7406\u7684\u9700\u6c42\u7c7b\u578b\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86 AllowedInLoungeRequirement \u7684\u5904\u7406\u7a0b\u5e8f\uff0c\u8be5\u5904\u7406\u7a0b\u5e8f\u68c0\u67e5\u7528\u6237\u662f\u5426\u5177\u6709\u540d\u4e3a FrequentFlyerClass \u4e14\u503c\u4e3a Gold \u7684\u58f0\u660e\u3002<\/p>\n<p>Listing 24.8 FrequentFlyerHandler for AllowedInLoungeRequirement<br \/>\n\u6e05\u5355 24.8 AllowedInLoungeRequirement \u7684 FrequentFlyerHandler<\/p>\n<pre><code>public class FrequentFlyerHandler :\nAuthorizationHandler&lt;AllowedInLoungeRequirement&gt; \u2776\n{\nprotected override Task HandleRequirementAsync( \u2777\nAuthorizationHandlerContext context, \u2778\nAllowedInLoungeRequirement requirement) \u2779\n{\nif(context.User.HasClaim(&quot;FrequentFlyerClass&quot;, &quot;Gold&quot;)) \u277a\n{\ncontext.Succeed(requirement); \u277b\n}\nreturn Task.CompletedTask; \u277c\n}\n}<\/code><\/pre>\n<p>\u2776 The handler implements <code>AuthorizationHandler&lt;T&gt;<\/code>.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u5b9e\u73b0 <code>AuthorizationHandler&lt;T&gt;<\/code>\u3002<\/p>\n<p>\u2777 You must override the abstract HandleRequirementAsync method.<br \/>\n\u60a8\u5fc5\u987b\u91cd\u5199\u62bd\u8c61 HandleRequirementAsync \u65b9\u6cd5\u3002<\/p>\n<p>\u2778 The context contains details such as the ClaimsPrincipal user object.<br \/>\n\u4e0a\u4e0b\u6587\u5305\u542b\u8bf8\u5982 ClaimsPrincipal \u7528\u6237\u5bf9\u8c61\u4e4b\u7c7b\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>\u2779 The requirement instance to handle<br \/>\n\u8981\u5904\u7406\u7684\u8981\u6c42\u5b9e\u4f8b<\/p>\n<p>\u277a Checks whether the user has the Frequent-FlyerClass claim with the Gold value<br \/>\n\u68c0\u67e5\u7528\u6237\u662f\u5426\u5177\u6709\u503c\u4e3a Gold \u7684Frequent-FlyerClass \u58f0\u660e<\/p>\n<p>\u277b If the user had the necessary claim, marks the requirement as satisfied by calling Succeed<br \/>\n\u5982\u679c\u7528\u6237\u5177\u6709\u5fc5\u8981\u7684\u58f0\u660e\uff0c\u5219\u901a\u8fc7\u8c03\u7528 Succeed\u5c06\u8981\u6c42\u6807\u8bb0\u4e3a\u6ee1\u8db3<\/p>\n<p>\u277c If the requirement wasn\u2019t satisfied, does nothing<br \/>\n\u5982\u679c\u672a\u6ee1\u8db3\u8981\u6c42\uff0c\u5219\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c<\/p>\n<p>This handler is functionally equivalent to the simple RequireClaim() handler you saw at the start of section 24.4, but using the requirement and handler approach instead.<br \/>\n\u8fd9\u4e2a\u5904\u7406\u7a0b\u5e8f\u5728\u529f\u80fd\u4e0a\u7b49\u540c\u4e8e\u4f60\u5728 24.4 \u8282\u5f00\u5934\u770b\u5230\u7684\u7b80\u5355RequireClaim\uff08\uff09\u5904\u7406\u7a0b\u5e8f\uff0c\u4f46\u4f7f\u7528\u7684\u662f\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u3002<\/p>\n<p>When a request is routed to the AirportLounge.cshtml Razor Page, the authorization middleware sees the [Authorize] attribute on the endpoint with the &quot;CanAccessLounge&quot; policy. It loops through all the requirements in the policy and all the handlers for each requirement, calling the HandleRequirementAsync method for each.\u200c<br \/>\n\u5f53\u8bf7\u6c42\u8def\u7531\u5230 AirportLounge.cshtml Razor \u9875\u9762\u65f6\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u4f1a\u5728\u5177\u6709\u201cCanAccessLounge\u201d\u7b56\u7565\u7684\u7ec8\u7ed3\u70b9\u4e0a\u770b\u5230 [Authorize] \u5c5e\u6027\u3002\u5b83\u5faa\u73af\u8bbf\u95ee\u7b56\u7565\u4e2d\u7684\u6240\u6709\u8981\u6c42\u548c\u6bcf\u4e2a\u8981\u6c42\u7684\u6240\u6709\u5904\u7406\u7a0b\u5e8f\uff0c\u5e76\u4e3a\u6bcf\u4e2a\u8981\u6c42\u8c03\u7528 HandleRequirementAsync \u65b9\u6cd5\u3002<\/p>\n<p>The authorization middleware passes the current AuthorizationHandlerContext and the requirement to be checked to each handler. The current ClaimsPrincipal being authorized is exposed on the context as the User property. In listing 24.8, FrequentFlyerHandler uses the context to check for a claim called FrequentFlyerClass with the Gold value, and if it exists, indicates that the user is allowed to enter the airline lounge by calling Succeed().<br \/>\n\u6388\u6743\u4e2d\u95f4\u4ef6\u5c06\u5f53\u524d AuthorizationHandlerContext \u548c\u8981\u68c0\u67e5\u7684\u8981\u6c42\u4f20\u9012\u7ed9\u6bcf\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002\u5f53\u524d\u88ab\u6388\u6743\u7684 ClaimsPrincipal \u5728\u4e0a\u4e0b\u6587\u4e2d\u4f5c\u4e3a User \u5c5e\u6027\u516c\u5f00\u3002\u5728\u5217\u8868 24.8 \u4e2d\uff0cFrequentFlyerHandler \u4f7f\u7528\u4e0a\u4e0b\u6587\u6765\u68c0\u67e5\u540d\u4e3a FrequentFlyerClass \u4e14\u503c\u4e3a Gold \u7684\u58f0\u660e\uff0c\u5982\u679c\u5b58\u5728\uff0c\u5219\u8868\u793a\u5141\u8bb8\u7528\u6237\u901a\u8fc7\u8c03\u7528 Succeed\uff08\uff09 \u8fdb\u5165\u822a\u7a7a\u516c\u53f8\u4f11\u606f\u5ba4\u3002<\/p>\n<p><b>NOTE<\/b>  Handlers mark a requirement as being satis\ufb01ed by calling context .Succeed() and passing the requirement as an argument.<br \/>\n\u6ce8\u610f\u5904\u7406\u7a0b\u5e8f\u901a\u8fc7\u8c03\u7528 context \u5c06\u9700\u6c42\u6807\u8bb0\u4e3a\u6ee1\u8db3\u3002Succeed\uff08\uff09 \u5e76\u5c06\u9700\u6c42\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u3002<\/p>\n<p>It\u2019s important to note the behavior when the user doesn\u2019t have the claim. FrequentFlyerHandler doesn\u2019t do anything in this case; it returns a completed Task to satisfy the method signature.<br \/>\n\u8bf7\u52a1\u5fc5\u6ce8\u610f\u7528\u6237\u6ca1\u6709\u58f0\u660e\u65f6\u7684\u884c\u4e3a\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0cFrequentFlyerHandler \u4e0d\u6267\u884c\u4efb\u4f55\u4f5c;\u5b83\u8fd4\u56de\u4e00\u4e2a\u5df2\u5b8c\u6210\u7684 Task \u4ee5\u6ee1\u8db3\u65b9\u6cd5\u7b7e\u540d\u3002<\/p>\n<p><b>NOTE<\/b>  Remember that if any of the handlers associated with a requirement passes, the requirement is a success. Only one of the handlers must succeed for the requirement to be satis\ufb01ed.<br \/>\n\u6ce8\u610f:\u8bf7\u8bb0\u4f4f\uff0c\u5982\u679c\u4e0e\u8981\u6c42\u5173\u8054\u7684\u4efb\u4f55\u5904\u7406\u7a0b\u5e8f\u901a\u8fc7\uff0c\u5219\u8981\u6c42\u6210\u529f\u3002\u53ea\u6709\u4e00\u4e2a\u5904\u7406\u7a0b\u5e8f\u5fc5\u987b\u6210\u529f\u624d\u80fd\u6ee1\u8db3\u8981\u6c42\u3002<\/p>\n<p>This behavior, whereby you either call context.Succeed() or do nothing, is typical for authorization handlers. The following listing shows the implementation of IsAirlineEmployeeHandler, which uses a similar claim check to determine whether the requirement is satis\ufb01ed.<br \/>\n\u6b64\u884c\u4e3a\uff0c\u5373\u8c03\u7528 context.Succeed\uff08\uff09 \u6216\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c\uff0c\u662f\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u7684\u5178\u578b\u7279\u5f81\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86 IsAirlineEmployeeHandler \u7684\u5b9e\u73b0\uff0c\u5b83\u4f7f\u7528\u7c7b\u4f3c\u7684\u58f0\u660e\u68c0\u67e5\u6765\u786e\u5b9a\u662f\u5426\u6ee1\u8db3\u8981\u6c42\u3002<\/p>\n<p>Listing 24.9 IsAirlineEmployeeHandler<\/p>\n<pre><code>public class IsAirlineEmployeeHandler :\nAuthorizationHandler&lt;AllowedInLoungeRequirement&gt; \u2776\n{\nprotected override Task HandleRequirementAsync( \u2777\nAuthorizationHandlerContext context, \u2777\nAllowedInLoungeRequirement requirement) \u2777\n{\nif(context.User.HasClaim(c =&gt; c.Type == &quot;EmployeeNumber&quot;)) \u2778\n{\ncontext.Succeed(requirement); \u2779\n}\nreturn Task.CompletedTask; \u277a\n}\n}<\/code><\/pre>\n<p>\u2776 The handler implements <code>AuthorizationHandler&lt;T&gt;<\/code>.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u5b9e\u73b0 <code>AuthorizationHandler&lt;T&gt;<\/code>\u3002<\/p>\n<p>\u2777 You must override the abstract HandleRequirementAsync method.<br \/>\n\u60a8\u5fc5\u987b\u8986\u76d6\u62bd\u8c61\u7684 HandleRequirementAsync \u65b9\u6cd5\u3002<\/p>\n<p>\u2778 Checks whether the user has the EmployeeNumber claim<br \/>\n\u68c0\u67e5\u7528\u6237\u662f\u5426\u5177\u6709 EmployeeNumber \u58f0\u660e<\/p>\n<p>\u2779 If the user has the necessary claim, marks the requirement as satisfied by calling Succeed<br \/>\n\u5982\u679c\u7528\u6237\u5177\u6709\u5fc5\u8981\u7684\u58f0\u660e\uff0c\u5219\u901a\u8fc7\u8c03\u7528 Succeed \u5c06\u9700\u6c42\u6807\u8bb0\u4e3a\u6ee1\u8db3<\/p>\n<p>\u277a If the requirement wasn\u2019t satisfied, does nothing<br \/>\n\u5982\u679c\u4e0d\u6ee1\u8db3\u8981\u6c42\uff0c\u5219\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c<\/p>\n<p>I\u2019ve left the implementation of MinimumAgeHandler for MinimumAgeRequirement as an exercise for the reader, as it\u2019s similar to the handlers you have already seen. You can \ufb01nd an example implementation in the code samples for the chapter.<br \/>\n\u6211\u5c06 MinimumAgeRequirement \u7684 MinimumAgeHandler \u7684\u5b9e\u73b0\u7559\u7ed9\u8bfb\u8005\u4f5c\u4e3a\u7ec3\u4e60\uff0c\u56e0\u4e3a\u5b83\u7c7b\u4f3c\u4e8e\u60a8\u5df2\u7ecf\u770b\u5230\u7684\u5904\u7406\u7a0b\u5e8f\u3002\u60a8\u53ef\u4ee5\u5728\u672c\u7ae0\u7684\u4ee3\u7801\u793a\u4f8b\u4e2d\u627e\u5230\u793a\u4f8b\u5b9e\u73b0\u3002<\/p>\n<p><b>TIP<\/b> It\u2019s possible to write generic handlers that can be used with multiple requirements, but I suggest sticking to handling a single requirement. If you need to extract some common functionality, move it to an external service, and call that from both handlers.<br \/>\n\u63d0\u793a:\u53ef\u4ee5\u7f16\u5199\u53ef\u7528\u4e8e\u591a\u4e2a\u9700\u6c42\u7684\u901a\u7528\u5904\u7406\u7a0b\u5e8f\uff0c\u4f46\u6211\u5efa\u8bae\u575a\u6301\u5904\u7406\u5355\u4e2a\u9700\u6c42\u3002\u5982\u679c\u9700\u8981\u63d0\u53d6\u4e00\u4e9b\u5e38\u7528\u529f\u80fd\uff0c\u8bf7\u5c06\u5176\u79fb\u52a8\u5230\u5916\u90e8\u670d\u52a1\uff0c\u7136\u540e\u4ece\u4e24\u4e2a\u5904\u7406\u7a0b\u5e8f\u4e2d\u8c03\u7528\u5b83\u3002<\/p>\n<p>This pattern of authorization handler is common, but in some cases, instead of checking for a success condition, you might want to check for a failure condition. In the airport example, you don\u2019t want to authorize someone who was previously banned from the lounge, even if they would otherwise be allowed to enter.<br \/>\n\u8fd9\u79cd\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u6a21\u5f0f\u5f88\u5e38\u89c1\uff0c\u4f46\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u80fd\u5e0c\u671b\u68c0\u67e5\u5931\u8d25\u6761\u4ef6\uff0c\u800c\u4e0d\u662f\u68c0\u67e5\u6210\u529f\u6761\u4ef6\u3002\u5728 airport \u793a\u4f8b\u4e2d\uff0c\u60a8\u4e0d\u5e0c\u671b\u6388\u6743\u4e4b\u524d\u88ab\u7981\u6b62\u8fdb\u5165\u8d35\u5bbe\u5ba4\u7684\u4eba\uff0c\u5373\u4f7f\u4ed6\u4eec\u672c\u6765\u53ef\u4ee5\u8fdb\u5165\u3002<\/p>\n<p>You can handle this scenario by using the context.Fail() method exposed on the context, as shown in the following listing. Calling Fail() in a handler always causes the requirement, and hence the whole policy, to fail. You should use it only when you want to guarantee failure, even if other handlers indicate success.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528\u4e0a\u4e0b\u6587\u5904\u7406\u6b64\u65b9\u6848\u3002Fail\uff08\uff09 \u65b9\u6cd5\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u5728\u5904\u7406\u7a0b\u5e8f\u4e2d\u8c03\u7528 Fail\uff08\uff09 \u603b\u662f\u4f1a\u5bfc\u81f4\u9700\u6c42\u5931\u8d25\uff0c\u4ece\u800c\u5bfc\u81f4\u6574\u4e2a\u7b56\u7565\u5931\u8d25\u3002\u4ec5\u5f53\u60a8\u5e0c\u671b\u4fdd\u8bc1\u5931\u8d25\u65f6\uff0c\u624d\u5e94\u4f7f\u7528\u5b83\uff0c\u5373\u4f7f\u5176\u4ed6\u5904\u7406\u7a0b\u5e8f\u6307\u793a\u6210\u529f\u3002<\/p>\n<p>Listing 24.10 Calling context.Fail() in a handler to fail the requirement<br \/>\n\u6e05\u5355 24.10 \u8c03\u7528context.Fail()\u4f7f\u9700\u6c42\u5931\u8d25<\/p>\n<pre><code>public class BannedFromLoungeHandler :\nAuthorizationHandler&lt;AllowedInLoungeRequirement&gt; \u2776\n{\nprotected override Task HandleRequirementAsync( \u2777\nAuthorizationHandlerContext context, \u2777\nAllowedInLoungeRequirement requirement) \u2777\n{\nif(context.User.HasClaim(c =&gt; c.Type == &quot;IsBannedFromLounge&quot;)) \u2778\n{\ncontext.Fail(); \u2779\n}\nreturn Task.CompletedTask; \u277a\n}\n}<\/code><\/pre>\n<p>\u2776 The handler implements <code>AuthorizationHandler&lt;T&gt;<\/code>.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u5b9e\u73b0 <code>AuthorizationHandler&lt;T&gt;<\/code>\u3002<\/p>\n<p>\u2777 You must override the abstract HandleRequirementAsync method.<br \/>\n\u60a8\u5fc5\u987b\u91cd\u5199\u62bd\u8c61\u7684 HandleRequirementAsync \u65b9\u6cd5\u3002<\/p>\n<p>\u2778 Checks whether the user has the IsBannedFromLounge claim<br \/>\n\u68c0\u67e5\u7528\u6237\u662f\u5426\u5177\u6709 IsBannedFromLounge \u58f0\u660e<\/p>\n<p>\u2779 If the user has the claim, fails the requirement by calling Fail. The whole policy fails.<br \/>\n\u5982\u679c\u7528\u6237\u5177\u6709\u58f0\u660e\uff0c\u5219\u901a\u8fc7\u8c03\u7528 Fail \u6765\u6ee1\u8db3\u8981\u6c42\u3002\u6574\u4e2a\u7b56\u7565\u5931\u8d25\u4e86\u3002<\/p>\n<p>\u277a If the claim wasn\u2019t found, does nothing<br \/>\n\u5982\u679c\u672a\u627e\u5230\u7d22\u8d54\uff0c\u5219\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c<\/p>\n<p>In most cases, your handlers will either call Succeed() or will do nothing, but the Fail() method is useful when you need a kill switch to guarantee that a requirement won\u2019t be satis\ufb01ed.<br \/>\n\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u5904\u7406\u7a0b\u5e8f\u5c06\u8c03\u7528 Succeed\uff08\uff09 \u6216\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c\uff0c\u4f46\u5f53\u4f60\u9700\u8981\u4e00\u4e2a\u7ec8\u6b62\u5f00\u5173\u6765\u4fdd\u8bc1\u4e0d\u4f1a\u6ee1\u8db3\u8981\u6c42\u65f6\uff0cFail\uff08\uff09 \u65b9\u6cd5\u975e\u5e38\u6709\u7528\u3002<\/p>\n<p><b>NOTE<\/b>  Whether a handler calls Succeed(), Fail(), or neither, the authorization system always executes all the handlers for a requirement and all the requirements for a policy, so you can be sure your handlers will always be called.<br \/>\n\u6ce8\u610f:\u65e0\u8bba\u5904\u7406\u7a0b\u5e8f\u662f\u8c03\u7528 Succeed\uff08\uff09\u3001Fail\uff08\uff09\uff0c\u8fd8\u662f\u4e24\u8005\u90fd\u4e0d\u8c03\u7528\uff0c\u6388\u6743\u7cfb\u7edf\u59cb\u7ec8\u6267\u884c\u8981\u6c42\u7684\u6240\u6709\u5904\u7406\u7a0b\u5e8f\u548c\u7b56\u7565\u7684\u6240\u6709\u8981\u6c42\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u786e\u4fdd\u59cb\u7ec8\u8c03\u7528\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>The \ufb01nal step to complete your authorization implementation for the app is to register the authorization handlers with the DI container, as shown in the following listing.<br \/>\n\u5b8c\u6210\u5e94\u7528\u7a0b\u5e8f\u7684\u6388\u6743\u5b9e\u73b0\u7684\u6700\u540e\u4e00\u6b65\u662f\u5411 DI \u5bb9\u5668\u6ce8\u518c\u6388\u6743\u5904\u7406\u7a0b\u5e8f\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 24.11 Registering the authorization handlers with the DI container<br \/>\nListing 24.11 \u5411 DI \u5bb9\u5668\u6ce8\u518c\u6388\u6743\u5904\u7406\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddAuthorization(options =&gt;\noptions.AddPolicy(\n&quot;CanEnterSecurity&quot;,\npolicyBuilder =&gt; policyBuilder\n.RequireClaim(Claims.BoardingPassNumber));\noptions.AddPolicy(\n&quot;CanAccessLounge&quot;,\npolicyBuilder =&gt; policyBuilder.AddRequirements(\nnew MinimumAgeRequirement(18),\nnew AllowedInLoungeRequirement()\n));\n});\nservices.AddSingleton&lt;IAuthorizationHandler, MinimumAgeHandler&gt;();\nservices.AddSingleton&lt;IAuthorizationHandler, FrequentFlyerHandler&gt;();\nservices.AddSingleton&lt;IAuthorizationHandler, BannedFromLoungeHandler&gt;();\nservices.AddSingleton&lt;IAuthorizationHandler, IsAirlineEmployeeHandler&gt;();\n\/\/ Additional configuration<\/code><\/pre>\n<p>For this app, the handlers don\u2019t have any constructor dependencies, so I\u2019ve registered them as singletons with the container. If your handlers have scoped or transient dependencies (the EF Core DbContext, for example), you might want to register them as scoped instead, as appropriate.<br \/>\n\u5bf9\u4e8e\u6b64\u5e94\u7528\u7a0b\u5e8f\uff0c\u5904\u7406\u7a0b\u5e8f\u6ca1\u6709\u4efb\u4f55\u6784\u9020\u51fd\u6570\u4f9d\u8d56\u9879\uff0c\u56e0\u6b64\u6211\u5df2\u5c06\u5b83\u4eec\u6ce8\u518c\u4e3a\u5bb9\u5668\u4e2d\u7684\u5355\u4f8b\u3002\u5982\u679c\u5904\u7406\u7a0b\u5e8f\u5177\u6709\u8303\u56f4\u6216\u6682\u65f6\u6027\u4f9d\u8d56\u9879\uff08\u4f8b\u5982 EF Core DbContext\uff09\uff0c\u5219\u53ef\u80fd\u9700\u8981\u6839\u636e\u9700\u8981\u5c06\u5b83\u4eec\u6ce8\u518c\u4e3a\u8303\u56f4\u4f9d\u8d56\u9879\u3002<\/p>\n<p><b>NOTE<\/b>  Services are registered with a lifetime of transient, scoped, or singleton, as discussed in chapter 9.<br \/>\n\u6ce8\u610f:\u670d\u52a1\u6ce8\u518c\u7684\u751f\u547d\u5468\u671f\u4e3a transient\u3001scoped \u6216 singleton\uff0c\u5982\u7b2c 9 \u7ae0\u6240\u8ff0\u3002<\/p>\n<p>You can combine the concepts of policies, requirements, and handlers in many ways to achieve your goals for authorization in your application. The example in this section, although contrived, demonstrates the components you need to apply authorization declaratively at the action method or Razor Page level by creating policies and applying the [Authorize] attribute as appropriate.<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u7ec4\u5408\u7b56\u7565\u3001\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u7684\u6982\u5ff5\uff0c\u4ee5\u5b9e\u73b0\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6388\u6743\u76ee\u6807\u3002\u672c\u90e8\u5206\u4e2d\u7684\u793a\u4f8b\u867d\u7136\u662f\u4eba\u4e3a\u7684\uff0c\u4f46\u6f14\u793a\u4e86\u901a\u8fc7\u521b\u5efa\u7b56\u7565\u5e76\u6839\u636e\u9700\u8981\u5e94\u7528 [Authorize] \u5c5e\u6027\uff0c\u5728\u4f5c\u65b9\u6cd5\u6216 Razor \u9875\u9762\u7ea7\u522b\u4ee5\u58f0\u660e\u65b9\u5f0f\u5e94\u7528\u6388\u6743\u6240\u9700\u7684\u7ec4\u4ef6\u3002<\/p>\n<p>As well as applying the [Authorize] attribute explicitly to actions and Razor Pages, you can con\ufb01gure it globally, so that a policy is applied to every endpoint in your application. Additionally, for Razor Pages you can apply di\ufb00erent authorization policies to di\ufb00erent folders. You can read more about applying authorization policies using conventions in Microsoft\u2019s \u201cRazor Pages authorization conventions in ASP.NET Core\u201d documentation: <a href=\"http:\/\/mng.bz\/nMm2\">http:\/\/mng.bz\/nMm2<\/a>.<br \/>\n\u9664\u4e86\u5c06 [Authorize] \u5c5e\u6027\u663e\u5f0f\u5e94\u7528\u4e8e\u4f5c\u548c Razor Pages \u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u5168\u5c40\u914d\u7f6e\u5b83\uff0c\u4ee5\u4fbf\u5c06\u7b56\u7565\u5e94\u7528\u4e8e\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u6bcf\u4e2a\u7ec8\u7ed3\u70b9\u3002\u6b64\u5916\uff0c\u5bf9\u4e8e Razor Pages\uff0c\u53ef\u4ee5\u5c06\u4e0d\u540c\u7684\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e\u4e0d\u540c\u7684\u6587\u4ef6\u5939\u3002\u60a8\u53ef\u4ee5\u5728 Microsoft \u7684\u201cASP.NET Core \u4e2d\u7684 Razor Pages \u6388\u6743\u7ea6\u5b9a\u201d\u6587\u6863\u4e2d\u9605\u8bfb\u6709\u5173\u4f7f\u7528\u7ea6\u5b9a\u5e94\u7528\u6388\u6743\u7b56\u7565\u7684\u66f4\u591a\u4fe1\u606f\uff1a<a href=\"http:\/\/mng.bz\/nMm2\">http:\/\/mng.bz\/nMm2<\/a>\u3002<\/p>\n<p>There\u2019s one area, however, where the [Authorize] attribute falls short: resource-based authorization. The [Authorize] attribute attaches metadata to an endpoint, so the authorization middleware can authorize the user before an endpoint is executed. But what if you need to authorize the action from within the endpoint?<br \/>\n\u4f46\u662f\uff0c[Authorize] \u5c5e\u6027\u5728\u4e00\u4e2a\u65b9\u9762\u5b58\u5728\u4e0d\u8db3\uff1a\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u3002[Authorize] \u5c5e\u6027\u5c06\u5143\u6570\u636e\u9644\u52a0\u5230\u7ec8\u7ed3\u70b9\uff0c\u4ee5\u4fbf\u6388\u6743\u4e2d\u95f4\u4ef6\u53ef\u4ee5\u5728\u6267\u884c\u7ec8\u7ed3\u70b9\u4e4b\u524d\u5bf9\u7528\u6237\u8fdb\u884c\u6388\u6743\u3002\u4f46\u662f\uff0c\u5982\u679c\u60a8\u9700\u8981\u4ece\u7ec8\u7aef\u8282\u70b9\u5185\u90e8\u6388\u6743\u4f5c\uff0c\u8be5\u600e\u4e48\u529e\uff1f<\/p>\n<p>This is common when you\u2019re applying authorization at the document or resource level. If users are allowed to edit only documents they created, you need to load the document before you can tell whether they\u2019re allowed to edit it! This isn\u2019t easy with the declarative [Authorize] attribute approach, so you must often use an alternative, imperative approach. In the next section you\u2019ll see how to apply this resource-based authorization in a Razor Page handler.\u200c<br \/>\n\u5f53\u60a8\u5728\u6587\u6863\u6216\u8d44\u6e90\u7ea7\u522b\u5e94\u7528\u6388\u6743\u65f6\uff0c\u8fd9\u79cd\u60c5\u51b5\u5f88\u5e38\u89c1\u3002\u5982\u679c\u4ec5\u5141\u8bb8\u7528\u6237\u7f16\u8f91\u4ed6\u4eec\u521b\u5efa\u7684\u6587\u6863\uff0c\u5219\u9700\u8981\u5148\u52a0\u8f7d\u6587\u6863\uff0c\u7136\u540e\u624d\u80fd\u5224\u65ad\u662f\u5426\u5141\u8bb8\u4ed6\u4eec\u7f16\u8f91\u8be5\u6587\u6863\uff01\u4f7f\u7528\u58f0\u660e\u6027 [Authorize] \u5c5e\u6027\u65b9\u6cd5\uff0c\u8fd9\u5e76\u4e0d\u5bb9\u6613\uff0c\u56e0\u6b64\u60a8\u5fc5\u987b\u7ecf\u5e38\u4f7f\u7528\u66ff\u4ee3\u7684\u547d\u4ee4\u5f0f\u65b9\u6cd5\u3002\u5728\u4e0b\u4e00\u90e8\u5206\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u5728 Razor Page \u5904\u7406\u7a0b\u5e8f\u4e2d\u5e94\u7528\u6b64\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u3002<\/p>\n<h2>24.5 Controlling access with resource-based authorization\u200c<\/h2>\n<p>24.5 \u4f7f\u7528\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u63a7\u5236\u8bbf\u95ee<\/p>\n<p>In this section you\u2019ll learn about resource-based authorization. This is used when you need to know details about the resource being protected to determine whether a user is authorized. You\u2019ll learn how to apply authorization policies manually using the IAuthorizationService and how to create resource-based AuthorizationHandlers.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u3002\u5f53\u60a8\u9700\u8981\u4e86\u89e3\u6709\u5173\u53d7\u4fdd\u62a4\u8d44\u6e90\u7684\u8be6\u7ec6\u4fe1\u606f\u4ee5\u786e\u5b9a\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u6b64\u65b9\u6cd5\u3002\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u4f7f\u7528 IAuthorizationService \u624b\u52a8\u5e94\u7528\u6388\u6743\u7b56\u7565\uff0c\u4ee5\u53ca\u5982\u4f55\u521b\u5efa\u57fa\u4e8e\u8d44\u6e90\u7684 AuthorizationHandlers\u3002<\/p>\n<p>Resource-based authorization is a common problem for applications, especially when you have users who can create or edit some sort of document. Consider the recipe application you worked on in chapter 23. This app lets users create, view, and edit recipes.<br \/>\n\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u662f\u5e94\u7528\u7a0b\u5e8f\u7684\u5e38\u89c1\u95ee\u9898\uff0c\u5c24\u5176\u662f\u5f53\u60a8\u62e5\u6709\u53ef\u4ee5\u521b\u5efa\u6216\u7f16\u8f91\u67d0\u79cd\u6587\u6863\u7684\u7528\u6237\u65f6\u3002\u8003\u8651\u60a8\u5728\u7b2c 23 \u7ae0\u4e2d\u5904\u7406\u7684\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u3002\u6b64\u5e94\u7528\u7a0b\u5e8f\u5141\u8bb8\u7528\u6237\u521b\u5efa\u3001\u67e5\u770b\u548c\u7f16\u8f91\u914d\u65b9\u3002<\/p>\n<p>Up to this point, everyone can create new recipes, and anyone can edit any recipe, even if they haven\u2019t logged in. Now you want to add some additional behavior:<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6bcf\u4e2a\u4eba\u90fd\u53ef\u4ee5\u521b\u5efa\u65b0\u914d\u65b9\uff0c\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u7f16\u8f91\u4efb\u4f55\u914d\u65b9\uff0c\u5373\u4f7f\u4ed6\u4eec\u5c1a\u672a\u767b\u5f55\u3002\u73b0\u5728\uff0c\u60a8\u9700\u8981\u6dfb\u52a0\u4e00\u4e9b\u5176\u4ed6\u884c\u4e3a\uff1a<\/p>\n<p>\u2022  Only authenticated users should be able to create new recipes.<br \/>\n\u53ea\u6709\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u624d\u80fd\u521b\u5efa\u65b0\u914d\u65b9\u3002<\/p>\n<p>\u2022  You can edit only the recipes you created.<br \/>\n\u60a8\u53ea\u80fd\u7f16\u8f91\u60a8\u521b\u5efa\u7684\u914d\u65b9\u3002<\/p>\n<p>You\u2019ve already seen how to achieve the \ufb01rst of these requirements: decorate the Create .cshtml Razor Page with an [Authorize] attribute and don\u2019t specify a policy, as shown in the following listing. This will force the user to authenticate before they can create a new recipe.<br \/>\n\u4f60\u5df2\u4e86\u89e3\u5982\u4f55\u5b9e\u73b0\u8fd9\u4e9b\u8981\u6c42\u4e2d\u7684\u7b2c\u4e00\u4e2a\uff1a\u4f7f\u7528 [Authorize] \u5c5e\u6027\u88c5\u9970 Create .cshtml Razor \u9875\u9762\uff0c\u5e76\u4e14\u4e0d\u6307\u5b9a\u7b56\u7565\uff0c\u5982\u4e0b\u9762\u7684\u5217\u8868\u6240\u793a\u3002\u8fd9\u5c06\u5f3a\u5236\u7528\u6237\u5728\u521b\u5efa\u65b0\u914d\u65b9\u4e4b\u524d\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>Listing 24.12 Adding AuthorizeAttribute to the Create.cshtml Razor Page<br \/>\n\u5217\u8868 24.12 \u5c06 AuthorizeAttribute \u6dfb\u52a0\u5230 Create.cshtml Razor \u9875\u9762<\/p>\n<pre><code>[Authorize] \u2776\npublic class CreateModel : PageModel\n{[BindProperty]\npublic CreateRecipeCommand Input { get; set; }\npublic void OnGet() \u2777\n{ \u2777\nInput = new CreateRecipeCommand(); \u2777\n} \u2777\npublic async Task&lt;IActionResult&gt; OnPost() \u2777\n{ \u2777\n\/\/ Method body not shown for brevity \u2777\n} \u2777\n}<\/code><\/pre>\n<p>\u2776 Users must be authenticated to execute the Create.cshtml Razor Page.<br \/>\n\u7528\u6237\u5fc5\u987b\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u624d\u80fd\u6267\u884c Create.cshtml Razor \u9875\u9762\u3002<br \/>\n\u2777 All page handlers are protected. You can apply [Authorize] only to the PageModel, not handlers.<br \/>\n\u6240\u6709\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u90fd\u53d7\u5230\u4fdd\u62a4\u3002\u53ea\u80fd\u5c06 [Authorize] \u5e94\u7528\u4e8e PageModel\uff0c\u800c\u4e0d\u80fd\u5e94\u7528\u4e8e\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p><b>TIP<\/b>  As with all \ufb01lters, you can apply the [Authorize] attribute only to the Razor Page, not to individual page handlers. The attribute applies to all page handlers in the Razor Page.<br \/>\n\u63d0\u793a:\u4e0e\u6240\u6709\u7b5b\u9009\u5668\u4e00\u6837\uff0c\u53ea\u80fd\u5c06 [Authorize] \u5c5e\u6027\u5e94\u7528\u4e8e Razor \u9875\u9762\uff0c\u800c\u4e0d\u80fd\u5e94\u7528\u4e8e\u5355\u4e2a\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002\u8be5\u5c5e\u6027\u9002\u7528\u4e8e Razor \u9875\u9762\u4e2d\u7684\u6240\u6709\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>Adding the [Authorize] attribute ful\ufb01lls your \ufb01rst requirement, but unfortunately, with the techniques you\u2019ve seen so far, you have no way to ful\ufb01ll the second. You could apply a policy that either permits or denies a user the ability to edit all recipes, but there\u2019s currently no easy way to restrict this so that a user can only edit their own recipes.<br \/>\n\u6dfb\u52a0 [Authorize] \u5c5e\u6027\u53ef\u4ee5\u6ee1\u8db3\u7b2c\u4e00\u4e2a\u8981\u6c42\uff0c\u4f46\u9057\u61be\u7684\u662f\uff0c\u4f7f\u7528\u4f60\u76ee\u524d\u770b\u5230\u7684\u6280\u672f\uff0c\u65e0\u6cd5\u6ee1\u8db3\u7b2c\u4e8c\u4e2a\u8981\u6c42\u3002\u60a8\u53ef\u4ee5\u5e94\u7528\u4e00\u4e2a\u7b56\u7565\u6765\u5141\u8bb8\u6216\u62d2\u7edd\u7528\u6237\u7f16\u8f91\u6240\u6709\u914d\u65b9\uff0c\u4f46\u76ee\u524d\u6ca1\u6709\u7b80\u5355\u7684\u65b9\u6cd5\u6765\u9650\u5236\u8fd9\u4e00\u70b9\uff0c\u4ee5\u4fbf\u7528\u6237\u53ea\u80fd\u7f16\u8f91\u81ea\u5df1\u7684\u914d\u65b9\u3002<\/p>\n<p>To \ufb01nd out who created the Recipe, you must \ufb01rst load it from the database. Only then can you attempt to authorize the user, taking the speci\ufb01c recipe (resource) into account. The following listing shows a partially implemented page handler for how this might look, where authorization occurs partway through the method, after the Recipe object has been loaded.<br \/>\n\u8981\u627e\u51fa Recipe \u7684\u521b\u5efa\u8005\uff0c\u60a8\u5fc5\u987b\u5148\u4ece\u6570\u636e\u5e93\u4e2d\u52a0\u8f7d\u5b83\u3002\u53ea\u6709\u8fd9\u6837\uff0c\u60a8\u624d\u80fd\u5c1d\u8bd5\u6388\u6743\u7528\u6237\uff0c\u540c\u65f6\u8003\u8651\u7279\u5b9a\u7684\u914d\u65b9\uff08\u8d44\u6e90\uff09\u3002\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u4e00\u4e2a\u90e8\u5206\u5b9e\u73b0\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u5176\u4e2d\u6388\u6743\u53d1\u751f\u5728\u65b9\u6cd5\u7684\u4e2d\u9014\uff0c\u5728 Recipe \u5bf9\u8c61\u52a0\u8f7d\u4e4b\u540e\u3002<\/p>\n<p>Listing 24.13 The Edit.cshtml page must load the Recipe<br \/>\n\u6e05\u5355 24.13 Edit.cshtml \u9875\u9762\u5fc5\u987b\u52a0\u8f7d Recipe<\/p>\n<pre><code>public IActionResult OnGet(int id) \u2776\n{\nvar recipe = _service.GetRecipe(id); \u2777\nvar createdById = recipe.CreatedById; \u2777\n\/\/ Authorize user based on createdById \u2778\nif(isAuthorized) \u2779\n{ \u2779\nreturn View(recipe); \u2779\n} \u2779\n}<\/code><\/pre>\n<p>\u2776 The id of the recipe to edit is provided by model binding.<br \/>\n\u8981\u7f16\u8f91\u7684\u914d\u65b9\u7684 id \u7531\u6a21\u578b\u7ed1\u5b9a\u63d0\u4f9b\u3002<br \/>\n\u2777 You must load the Recipe from the database before you know who created it.<br \/>\n\u60a8\u5fc5\u987b\u5148\u4ece\u6570\u636e\u5e93\u4e2d\u52a0\u8f7d Recipe\uff0c\u7136\u540e\u624d\u80fd\u77e5\u9053\u8c01\u521b\u5efa\u4e86\u5b83\u3002<br \/>\n\u2778 You must authorize the current user to verify that they\u2019re allowed to edit this specific Recipe.<br \/>\n\u60a8\u5fc5\u987b\u6388\u6743\u5f53\u524d\u7528\u6237\u9a8c\u8bc1\u662f\u5426\u5141\u8bb8\u4ed6\u4eec\u7f16\u8f91\u6b64\u7279\u5b9a\u914d\u65b9\u3002<br \/>\n\u2779 The action method can continue only if the user was authorized.<br \/>\n\u53ea\u6709\u5728\u7528\u6237\u83b7\u5f97\u6388\u6743\u7684\u60c5\u51b5\u4e0b\uff0c\u4f5c\u65b9\u6cd5\u624d\u80fd\u7ee7\u7eed\u3002<\/p>\n<p>You need access to the resource (in this case, the Recipe entity) to perform the authorization, so the declarative [Authorize] attribute can\u2019t help you. In section 24.5.1 you\u2019ll see the approach you need to take to handle these situations and to apply authorization inside your endpoints.<br \/>\n\u60a8\u9700\u8981\u8bbf\u95ee\u8d44\u6e90\uff08\u5728\u672c\u4f8b\u4e2d\u4e3a Recipe \u5b9e\u4f53\uff09\u624d\u80fd\u6267\u884c\u6388\u6743\uff0c\u56e0\u6b64\u58f0\u660e\u6027 [Authorize] \u5c5e\u6027\u65e0\u6cd5\u4e3a\u60a8\u63d0\u4f9b\u5e2e\u52a9\u3002\u5728 Section 24.5.1 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5904\u7406\u8fd9\u4e9b\u60c5\u51b5\u5e76\u5728 endpoints \u5185\u5e94\u7528\u6388\u6743\u6240\u9700\u91c7\u7528\u7684\u65b9\u6cd5\u3002<\/p>\n<p><b>WARNING<\/b> Be careful when exposing the integer ID of your entities in the URL, as in listing 24.13. Users will be able to edit every entity by modifying the ID in the URL to access a di\ufb00erent entity. Be sure to apply authorization checks, or you could expose a security vulnerability called insecure direct object reference (IDOR). You can read more about IDOR at <a href=\"http:\/\/mng.bz\/QPnG\">http:\/\/mng.bz\/QPnG<\/a>.<br \/>\n\u8b66\u544a:\u5728 URL \u4e2d\u516c\u5f00\u5b9e\u4f53\u7684\u6574\u6570 ID \u65f6\u8981\u5c0f\u5fc3\uff0c\u5982\u6e05\u5355 24.13 \u6240\u793a\u3002\u7528\u6237\u5c06\u80fd\u591f\u901a\u8fc7\u4fee\u6539 URL \u4e2d\u7684 ID \u6765\u7f16\u8f91\u6bcf\u4e2a\u5b9e\u4f53\uff0c\u4ee5\u8bbf\u95ee\u4e0d\u540c\u7684\u5b9e\u4f53\u3002\u8bf7\u52a1\u5fc5\u5e94\u7528\u6388\u6743\u68c0\u67e5\uff0c\u5426\u5219\u53ef\u80fd\u4f1a\u66b4\u9732\u79f0\u4e3a\u4e0d\u5b89\u5168\u76f4\u63a5\u5bf9\u8c61\u5f15\u7528 \uff08IDOR\uff09 \u7684\u5b89\u5168\u6f0f\u6d1e\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"http:\/\/mng.bz\/QPnG\">http:\/\/mng.bz\/QPnG<\/a> \u4e0a\u9605\u8bfb\u6709\u5173 IDOR \u7684\u66f4\u591a\u4fe1\u606f\u3002<\/p>\n<h3>24.5.1 Manually authorizing requests with IAuthorizationService\u200c<\/h3>\n<p>24.5.1 \u4f7f\u7528 IAuthorizationService \u624b\u52a8\u6388\u6743\u8bf7\u6c42<\/p>\n<p>All of the approaches to authorization so far have been declarative. You apply the [Authorize] attribute, with or without a policy name, and you let the framework take care of performing the authorization itself.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6240\u6709\u6388\u6743\u65b9\u6cd5\u90fd\u662f\u58f0\u660e\u6027\u7684\u3002\u60a8\u53ef\u4ee5\u5e94\u7528 [Authorize] \u5c5e\u6027\uff08\u65e0\u8bba\u662f\u5426\u5177\u6709\u7b56\u7565\u540d\u79f0\uff09\uff0c\u5e76\u8ba9\u6846\u67b6\u81ea\u884c\u6267\u884c\u6388\u6743\u3002<\/p>\n<p>For this recipe-editing example, you need to use imperative authorization, so you can authorize the user after you\u2019ve loaded the Recipe from the database. Instead of applying a marker saying \u201cAuthorize this method,\u201d you need to write some of the authorization code yourself.<br \/>\n\u5bf9\u4e8e\u6b64\u914d\u65b9\u7f16\u8f91\u793a\u4f8b\uff0c\u60a8\u9700\u8981\u4f7f\u7528\u547d\u4ee4\u5f0f\u6388\u6743\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u5728\u4ece\u6570\u636e\u5e93\u52a0\u8f7d\u914d\u65b9\u540e\u6388\u6743\u7528\u6237\u3002\u60a8\u9700\u8981\u81ea\u5df1\u7f16\u5199\u4e00\u4e9b\u6388\u6743\u4ee3\u7801\uff0c\u800c\u4e0d\u662f\u5e94\u7528\u201cAuthorize this method\u201d\u6807\u8bb0\u3002<\/p>\n<p><b>DEFINITION<\/b> Declarative and imperative are two di\ufb00erent styles of programming. Declarative programming describes what you\u2019re trying to achieve and lets the framework \ufb01gure out how to achieve it. Imperative programming describes how to achieve something by providing each of the steps needed.\u200c<br \/>\n\u5b9a\u4e49:\u58f0\u660e\u5f0f\u548c\u547d\u4ee4\u5f0f\u662f\u4e24\u79cd\u4e0d\u540c\u7684\u7f16\u7a0b\u98ce\u683c\u3002\u58f0\u660e\u5f0f\u7f16\u7a0b\u63cf\u8ff0\u4e86\u60a8\u8981\u5b9e\u73b0\u7684\u76ee\u6807\uff0c\u5e76\u8ba9\u6846\u67b6\u5f04\u6e05\u695a\u5982\u4f55\u5b9e\u73b0\u5b83\u3002\u547d\u4ee4\u5f0f\u7f16\u7a0b\u63cf\u8ff0\u4e86\u5982\u4f55\u901a\u8fc7\u63d0\u4f9b\u6240\u9700\u7684\u6bcf\u4e2a\u6b65\u9aa4\u6765\u5b9e\u73b0\u67d0\u4e9b\u76ee\u6807\u3002<\/p>\n<p>ASP.NET Core exposes IAuthorizationService, which you can inject into any of your services or endpoints for imperative authorization. The following listing shows how you could update the Edit.cshtml Razor Page (shown partially in listing 24.13) to use the IAuthorizationService to verify whether the action is allowed to continue execution.<br \/>\nASP.NET Core \u516c\u5f00\u4e86 IAuthorizationService\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u6ce8\u5165\u5230\u4efb\u4f55\u670d\u52a1\u6216\u7ec8\u7aef\u8282\u70b9\u4e2d\uff0c\u4ee5\u5b9e\u73b0\u547d\u4ee4\u5f0f\u6388\u6743\u3002\u4ee5\u4e0b\u5217\u8868\u663e\u793a\u4e86\u5982\u4f55\u66f4\u65b0 Edit.cshtml Razor \u9875\u9762\uff08\u90e8\u5206\u663e\u793a\u5728\u5217\u8868 24.13 \u4e2d\uff09\uff0c\u4ee5\u4f7f\u7528 IAuthorizationService \u6765\u9a8c\u8bc1\u662f\u5426\u5141\u8bb8\u4f5c\u7ee7\u7eed\u6267\u884c\u3002<\/p>\n<p>Listing 24.14 Using IAuthorizationService for resource-based authorization<br \/>\n\u6e05\u5355 24.14 \u4f7f\u7528 IAuthorizationService \u8fdb\u884c\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743<\/p>\n<pre><code>[Authorize] \u2776\npublic class EditModel : PageModel\n{\n[BindProperty]\npublic Recipe Recipe { get; set; }\nprivate readonly RecipeService _service;\nprivate readonly IAuthorizationService _authService; \u2777\npublic EditModel(\nRecipeService service,\nIAuthorizationService authService) \u2777\n{\n_service = service;\n_authService = authService; \u2777\n}\npublic async Task&lt;IActionResult&gt; OnGet(int id)\n{\nRecipe = _service.GetRecipe(id); \u2778\nAuthorizationResult authResult = await _authService \u2779\n.AuthorizeAsync(User, Recipe, &quot;CanManageRecipe&quot;); \u2779\nif (!authResult.Succeeded) \u277a\n{ \u277a\nreturn new ForbidResult(); \u277a\n} \u277a\nreturn Page(); \u277b\n}\n}<\/code><\/pre>\n<p>\u2776 Only authenticated users should be allowed to edit recipes.<br \/>\n\u53ea\u5141\u8bb8\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u7f16\u8f91\u914d\u65b9\u3002<br \/>\n\u2777 IAuthorizationService is injected into the class constructor using DI.<br \/>\n\u4f7f\u7528 DI \u5c06 IAuthorizationService \u6ce8\u5165\u5230\u7c7b\u6784\u9020\u51fd\u6570\u4e2d\u3002<br \/>\n\u2778 Loads the Recipe from the database<br \/>\n\u4ece\u6570\u636e\u5e93\u52a0\u8f7d\u914d\u65b9<br \/>\n\u2779 Calls IAuthorizationService, providing ClaimsPrinicipal, resource, and the policy name<br \/>\n\u8c03\u7528 IAuthorizationService\uff0c\u63d0\u4f9b ClaimsPrinicipal\u3001\u8d44\u6e90\u548c\u7b56\u7565\u540d\u79f0<br \/>\n\u277a If authorization failed, returns a Forbidden result<br \/>\n\u5982\u679c\u6388\u6743\u5931\u8d25\uff0c\u5219\u8fd4\u56de Forbidden \u7ed3\u679c<br \/>\n\u277b If authorization was successful, continues displaying the Razor Page<br \/>\n\u5982\u679c\u6388\u6743\u6210\u529f\uff0c\u5219\u7ee7\u7eed\u663e\u793a Razor \u9875\u9762<\/p>\n<p>IAuthorizationService exposes an AuthorizeAsync method, which requires three things to authorize the request:<br \/>\nIAuthorizationService \u516c\u5f00\u4e86\u4e00\u4e2a AuthorizeAsync \u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u9700\u8981\u4e09\u9879\u5185\u5bb9\u6765\u6388\u6743\u8bf7\u6c42\uff1a<\/p>\n<p>\u2022  The ClaimsPrincipal user object, exposed on the PageModel as User<br \/>\nClaimsPrincipal \u7528\u6237\u5bf9\u8c61\uff0c\u5728 PageModel \u4e0a\u4f5c\u4e3a User \u516c\u5f00<\/p>\n<p>\u2022  The resource being authorized: Recipe<br \/>\n\u6b63\u5728\u6388\u6743\u7684\u8d44\u6e90\uff1aRecipe<\/p>\n<p>\u2022  The policy to evaluate: &quot;CanManageRecipe&quot;<br \/>\n\u8981\u8bc4\u4f30\u7684\u7b56\u7565\uff1a\u201cCanManageRecipe\u201d<\/p>\n<p>The authorization attempt returns an AuthorizationResult object, which indicates whether the attempt was successful via the Succeeded property. If the attempt wasn\u2019t successful, you should return a new ForbidResult, which is converted to an HTTP 403 Forbidden response or redirects the user to the \u201caccess denied\u201d page, depending on whether you\u2019re building a traditional web app or an API app.\u200c\u200c\u200c<br \/>\n\u6388\u6743\u5c1d\u8bd5\u8fd4\u56de\u4e00\u4e2a AuthorizationResult \u5bf9\u8c61\uff0c\u8be5\u5bf9\u8c61\u901a\u8fc7 Succeeded \u5c5e\u6027\u6307\u793a\u5c1d\u8bd5\u662f\u5426\u6210\u529f\u3002\u5982\u679c\u5c1d\u8bd5\u4e0d\u6210\u529f\uff0c\u60a8\u5e94\u8be5\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684 ForbidResult\uff0c\u8be5\u7ed3\u679c\u5c06\u8f6c\u6362\u4e3a HTTP 403 Forbidden \u54cd\u5e94\u6216\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230\u201caccess denied\u201d\u9875\u9762\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u60a8\u662f\u6784\u5efa\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u8fd8\u662f API \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p><b>NOTE<\/b>  As mentioned in section 24.2.2, which type of response is generated depends on which authentication services are con\ufb01gured. The default Identity con\ufb01guration, used by Razor Pages, generates redirects. API apps typically generate HTTP 401 and 403 responses instead.<br \/>\n\u6ce8\u610f:\u5982\u7b2c 24.2.2 \u8282\u6240\u8ff0\uff0c\u751f\u6210\u7684\u54cd\u5e94\u7c7b\u578b\u53d6\u51b3\u4e8e\u914d\u7f6e\u7684\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u3002Razor Pages \u4f7f\u7528\u7684\u9ed8\u8ba4\u6807\u8bc6\u914d\u7f6e\u4f1a\u751f\u6210\u91cd\u5b9a\u5411\u3002API \u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4f1a\u751f\u6210 HTTP 401 \u548c 403 \u54cd\u5e94\u3002<\/p>\n<p>You\u2019ve con\ufb01gured the imperative authorization in the Edit.cshtml Razor Page itself, but you still need to de\ufb01ne the &quot;CanManageRecipe&quot; policy that you use to authorize the user. This is the same process as for declarative authorization, so you have to do the following:<br \/>\n\u4f60\u5df2\u5728 Edit.cshtml Razor \u9875\u9762\u672c\u8eab\u4e2d\u914d\u7f6e\u4e86\u547d\u4ee4\u6027\u6388\u6743\uff0c\u4f46\u4ecd\u9700\u8981\u5b9a\u4e49\u7528\u4e8e\u6388\u6743\u7528\u6237\u7684\u201cCanManageRecipe\u201d\u7b56\u7565\u3002\u6b64\u8fc7\u7a0b\u4e0e\u58f0\u660e\u5f0f\u6388\u6743\u7684\u8fc7\u7a0b\u76f8\u540c\uff0c\u56e0\u6b64\u60a8\u5fc5\u987b\u6267\u884c\u4ee5\u4e0b\u4f5c\uff1a<\/p>\n<p>\u2022  Create a policy in Program.cs by calling AddAuthorization().<br \/>\n\u901a\u8fc7\u8c03\u7528 AddAuthorization\uff08\uff09 \u5728 Program.cs \u4e2d\u521b\u5efa\u7b56\u7565\u3002<br \/>\n\u2022  De\ufb01ne one or more requirements for the policy.<br \/>\n\u5b9a\u4e49\u7b56\u7565\u7684\u4e00\u4e2a\u6216\u591a\u4e2a\u8981\u6c42\u3002<br \/>\n\u2022  De\ufb01ne one or more handlers for each requirement.<br \/>\n\u4e3a\u6bcf\u4e2a\u8981\u6c42\u5b9a\u4e49\u4e00\u4e2a\u6216\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002<br \/>\n\u2022  Register the handlers in the DI container.<br \/>\n\u5728 DI \u5bb9\u5668\u4e2d\u6ce8\u518c\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>With the exception of the handler, these steps are identical to the declarative authorization approach with the [Authorize] attribute, so I run through them only brie\ufb02y here.<br \/>\n\u9664\u4e86\u5904\u7406\u7a0b\u5e8f\u4e4b\u5916\uff0c\u8fd9\u4e9b\u6b65\u9aa4\u4e0e\u5177\u6709 [Authorize] \u5c5e\u6027\u7684\u58f0\u660e\u6027\u6388\u6743\u65b9\u6cd5\u76f8\u540c\uff0c\u56e0\u6b64\u6211\u5728\u8fd9\u91cc\u53ea\u7b80\u8981\u4ecb\u7ecd\u4e00\u4e0b\u5b83\u4eec\u3002<\/p>\n<p>First, you can create a simple IAuthorizationRequirement. As with many requirements, this contains no data and simply implements the marker interface:<br \/>\n\u9996\u5148\uff0c\u60a8\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 IAuthorizationRequirement\u3002\u4e0e\u8bb8\u591a\u8981\u6c42\u4e00\u6837\uff0c\u8fd9\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u636e\uff0c\u53ea\u5b9e\u73b0 marker \u63a5\u53e3\uff1a<\/p>\n<pre><code>public class IsRecipeOwnerRequirement : IAuthorizationRequirement { }<\/code><\/pre>\n<p>De\ufb01ning the policy in Program.cs is similarly simple, as you have only a single requirement. Note that there\u2019s nothing resource-speci\ufb01c in any of this code so far:<br \/>\n\u5728 Program.cs \u4e2d\u5b9a\u4e49\u7b56\u7565\u540c\u6837\u7b80\u5355\uff0c\u56e0\u4e3a\u60a8\u53ea\u6709\u4e00\u4e2a\u9700\u6c42\u3002\u8bf7\u6ce8\u610f\uff0c\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6b64\u4ee3\u7801\u4e2d\u6ca1\u6709\u4efb\u4f55\u7279\u5b9a\u4e8e\u8d44\u6e90\u7684\u5185\u5bb9\uff1a<\/p>\n<pre><code>builder.Services.AddAuthorization(options =&gt; { options.AddPolicy(&quot;CanManageRecipe&quot;, policyBuilder =&gt;\npolicyBuilder.AddRequirements(new IsRecipeOwnerRequirement()));\n});\n<\/code><\/pre>\n<p>You\u2019re halfway there. All you need to do now is create an authorization handler for IsRecipeOwnerRequirement and register it with the DI container.<br \/>\n\u4f60\u5df2\u7ecf\u6210\u529f\u4e86\u4e00\u534a\u3002\u73b0\u5728\uff0c\u60a8\u9700\u8981\u505a\u7684\u5c31\u662f\u4e3a IsRecipeOwnerRequirement \u521b\u5efa\u4e00\u4e2a\u6388\u6743\u5904\u7406\u7a0b\u5e8f\uff0c\u5e76\u5c06\u5176\u6ce8\u518c\u5230 DI \u5bb9\u5668\u4e2d\u3002<\/p>\n<h3>24.5.2 Creating a resource-based AuthorizationHandler\u200c<\/h3>\n<p>24.5.2 \u521b\u5efa\u57fa\u4e8e\u8d44\u6e90\u7684 AuthorizationHandler<\/p>\n<p>Resource-based authorization handlers are essentially the same as the authorization handler implementations you saw in section 24.4.2. The only di\ufb00erence is that the handler also has access to the resource being authorized.<br \/>\n\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u672c\u8d28\u4e0a\u4e0e\u60a8\u5728 Section 24.4.2 \u4e2d\u770b\u5230\u7684\u6388\u6743\u5904\u7406\u7a0b\u5e8f\u5b9e\u73b0\u76f8\u540c\u3002\u552f\u4e00\u7684\u533a\u522b\u662f\u5904\u7406\u7a0b\u5e8f\u8fd8\u53ef\u4ee5\u8bbf\u95ee\u88ab\u6388\u6743\u7684\u8d44\u6e90\u3002<\/p>\n<p>To create a resource-based handler, you should derive from the <code>AuthorizationHandler&lt;TRequirement, TResource&gt;<\/code> base class, where TRequirement is the type of requirement to handle and TResource is the type of resource that you provide when calling IAuthorizationService. Compare this with the <code>AuthorizationHandler&lt;T&gt;<\/code> class you implemented previously, where you speci\ufb01ed only the requirement.<br \/>\n\u82e5\u8981\u521b\u5efa\u57fa\u4e8e\u8d44\u6e90\u7684\u5904\u7406\u7a0b\u5e8f\uff0c\u5e94\u4ece<code>AuthorizationHandler&lt;TRequirement, TResource&gt;<\/code> \u57fa\u7c7b\u6d3e\u751f\uff0c\u5176\u4e2d TRequirement \u662f\u8981\u5904\u7406\u7684\u8981\u6c42\u7c7b\u578b\uff0cTResource \u662f\u8c03\u7528 IAuthorizationService \u65f6\u63d0\u4f9b\u7684\u8d44\u6e90\u7c7b\u578b\u3002\u5c06\u6b64\u7c7b\u4e0e\u60a8\u4e4b\u524d\u5b9e\u73b0\u7684\u7c7b\u8fdb\u884c\u6bd4\u8f83\uff0c\u5728<code>AuthorizationHandler&lt;T&gt;<\/code> \u8be5\u7c7b\u4e2d\uff0c\u60a8\u53ea\u6307\u5b9a\u4e86\u8981\u6c42\u3002<\/p>\n<p>The next listing shows the handler implementation for your recipe application. You can see that you\u2019ve speci\ufb01ed the requirement as IsRecipeOwnerRequirement and the resource as Recipe, and you have implemented the HandleRequirementAsync method.<br \/>\n\u4e0b\u4e00\u4e2a\u6e05\u5355\u663e\u793a\u4e86\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u7684\u5904\u7406\u7a0b\u5e8f\u5b9e\u73b0\u3002\u60a8\u53ef\u4ee5\u770b\u5230\uff0c\u60a8\u5df2\u5c06\u8981\u6c42\u6307\u5b9a\u4e3a IsRecipeOwnerRequirement\uff0c\u5c06\u8d44\u6e90\u6307\u5b9a\u4e3a Recipe\uff0c\u5e76\u4e14\u5df2\u5b9e\u73b0 HandleRequirementAsync \u65b9\u6cd5\u3002<\/p>\n<p>Listing 24.15 IsRecipeOwnerHandler for resource-based authorization<br \/>\n\u5217\u8868 24.15 IsRecipeOwnerHandler \u7528\u4e8e\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743<\/p>\n<pre><code>public class IsRecipeOwnerHandler :\nAuthorizationHandler&lt;IsRecipeOwnerRequirement, Recipe&gt; \u2776\n{\nprivate readonly UserManager&lt;ApplicationUser&gt; _userManager; \u2777\npublic IsRecipeOwnerHandler( \u2777\nUserManager&lt;ApplicationUser&gt; userManager) \u2777\n{ \u2777\n_userManager = userManager; \u2777\n} \u2777\nprotected override async Task HandleRequirementAsync(\nAuthorizationHandlerContext context,\nIsRecipeOwnerRequirement requirement,\nRecipe resource) \u2778\n{\nvar appUser = await _userManager.GetUserAsync(context.User);\nif(appUser == null) \u2779\n{\nreturn;\n}\nif(resource.CreatedById == appUser.Id) \u277a\n{\ncontext.Succeed(requirement); \u277b\n}\n}\n}<\/code><\/pre>\n<p>\u2776 Implements the necessary base class, specifying the requirement and resource type<br \/>\n\u5b9e\u73b0\u5fc5\u8981\u7684\u57fa\u7c7b\uff0c\u6307\u5b9a\u9700\u6c42\u548c\u8d44\u6e90\u7c7b\u578b<br \/>\n\u2777 Injects an instance of the <code>UserManager&lt;T&gt;<\/code> class using DI<br \/>\n\u4f7f\u7528 DI \u6ce8\u5165  <code>UserManager&lt;T&gt;<\/code> \u7c7b\u7684\u5b9e\u4f8b<br \/>\n\u2778 As well as the context and requirement, you\u2019re provided the resource instance.<br \/>\n\u9664\u4e86\u4e0a\u4e0b\u6587\u548c\u9700\u6c42\u5916\uff0c\u8fd8\u4e3a\u60a8\u63d0\u4f9b\u8d44\u6e90\u5b9e\u4f8b\u3002<br \/>\n\u2779 If you aren\u2019t authenticated, appUser will be null.<br \/>\n\u5982\u679c\u60a8\u672a\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\uff0cappUser \u5c06\u4e3a null\u3002<br \/>\n\u277a Checks whether the current user created the Recipe by checking the CreatedById property<br \/>\n\u901a\u8fc7\u68c0\u67e5CreatedById \u5c5e\u6027\u6765\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u521b\u5efa\u4e86\u914d\u65b9<br \/>\n\u277b If the user created the document, Succeeds the requirement; otherwise, does nothing<br \/>\n\u5982\u679c\u7528\u6237\u521b\u5efa\u4e86\u6587\u6863\uff0c\u5219 Succeeds the requirement;\u5426\u5219\uff0c\u4e0d\u6267\u884c\u4efb\u4f55\u4f5c<\/p>\n<p>This handler is slightly more complicated than the examples you\u2019ve seen previously, primarily because you\u2019re using an additional service, <code>UserManager&lt;&gt;<\/code>, to load the ApplicationUser entity based on ClaimsPrincipal from the request.<br \/>\n\u6b64\u5904\u7406\u7a0b\u5e8f\u6bd4\u60a8\u4e4b\u524d\u770b\u5230\u7684\u793a\u4f8b\u7a0d\u5fae\u590d\u6742\u4e00\u4e9b\uff0c\u4e3b\u8981\u662f\u56e0\u4e3a\u60a8\u6b63\u5728\u4f7f\u7528\u9644\u52a0\u670d\u52a1<code>UserManager&lt;&gt;<\/code> \u6765\u6839\u636e\u8bf7\u6c42\u4e2d\u7684 ClaimsPrincipal \u52a0\u8f7d ApplicationUser \u5b9e\u4f53\u3002<\/p>\n<p><b>NOTE<\/b>  In practice, the ClaimsPrincipal will likely already have the Id added as a claim, making the extra step unnecessary in this case. This example shows the general pattern if you need to use dependency-injected services.<br \/>\n\u6ce8\u610f:\u5b9e\u9645\u4e0a\uff0cClaimsPrincipal \u53ef\u80fd\u5df2\u5c06 Id \u6dfb\u52a0\u4e3a\u58f0\u660e\uff0c\u56e0\u6b64\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u4e0d\u9700\u8981\u989d\u5916\u7684\u6b65\u9aa4\u3002\u6b64\u793a\u4f8b\u663e\u793a\u4e86\u9700\u8981\u4f7f\u7528 dependency-injected \u670d\u52a1\u65f6\u7684\u4e00\u822c\u6a21\u5f0f\u3002<\/p>\n<p>The other signi\ufb01cant di\ufb00erence is that the HandleRequirementAsync method has provided the Recipe resource as a method argument. This is the same object you provided when calling AuthorizeAsync on IAuthorizationService. You can use this resource to verify whether the current user created it. If so, you Succeed() the requirement; otherwise, you do nothing.<br \/>\n\u53e6\u4e00\u4e2a\u663e\u8457\u533a\u522b\u662f HandleRequirementAsync \u65b9\u6cd5\u5df2\u5c06 Recipe \u8d44\u6e90\u4f5c\u4e3a\u65b9\u6cd5\u53c2\u6570\u63d0\u4f9b\u3002\u8fd9\u4e0e\u60a8\u5728 IAuthorizationService \u4e0a\u8c03\u7528 AuthorizeAsync \u65f6\u63d0\u4f9b\u7684\u5bf9\u8c61\u76f8\u540c\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528\u6b64\u8d44\u6e90\u6765\u9a8c\u8bc1\u5b83\u662f\u5426\u4e3a\u5f53\u524d\u7528\u6237\u521b\u5efa\u3002\u5982\u679c\u662f\u8fd9\u6837\uff0c\u5219 Succeed\uff08\uff09 \u8981\u6c42;\u5426\u5219\uff0c\u60a8\u4ec0\u4e48\u90fd\u4e0d\u505a\u3002<\/p>\n<p>The \ufb01nal task is adding IsRecipeOwnerHandler to the DI container. Your handler uses an additional dependency, <code>UserManager&lt;&gt;<\/code>, that uses EF Core, so you should register the handler as a scoped service:<br \/>\n\u6700\u540e\u4e00\u9879\u4efb\u52a1\u662f\u5c06 IsRecipeOwnerHandler \u6dfb\u52a0\u5230 DI \u5bb9\u5668\u4e2d\u3002\u5904\u7406\u7a0b\u5e8f\u4f7f\u7528\u4f7f\u7528 EF Core \u7684\u9644\u52a0\u4f9d\u8d56\u9879 <code>UserManager&lt;&gt;<\/code>\uff0c\u56e0\u6b64\u5e94\u5c06\u5904\u7406\u7a0b\u5e8f\u6ce8\u518c\u4e3a\u8303\u56f4\u670d\u52a1\uff1a<\/p>\n<pre><code>services.AddScoped&lt;IAuthorizationHandler, IsRecipeOwnerHandler&gt;();<\/code><\/pre>\n<p><b>TIP<\/b>  If you\u2019re wondering how to know whether you register a handler as scoped or a singleton, think back to chapter 9.<br \/>\n\u63d0\u793a:\u5982\u679c\u60a8\u60f3\u77e5\u9053\u5982\u4f55\u77e5\u9053\u5c06\u5904\u7406\u7a0b\u5e8f\u6ce8\u518c\u4e3a scoped \u8fd8\u662f singleton\uff0c\u8bf7\u56de\u60f3\u7b2c 9 \u7ae0\u3002<\/p>\n<p>Essentially, if you have scoped dependencies, you must register the handler as scoped; otherwise, singleton is \ufb01ne.<br \/>\n\u672c\u8d28\u4e0a\uff0c\u5982\u679c\u4f60\u6709 scoped \u4f9d\u8d56\u9879\uff0c\u5219\u5fc5\u987b\u5c06\u5904\u7406\u7a0b\u5e8f\u6ce8\u518c\u4e3a scoped;\u5426\u5219\uff0cSingleton \u5c31\u53ef\u4ee5\u4e86\u3002<\/p>\n<p>With everything hooked up, you can take the application for a spin. If you try to edit a recipe you didn\u2019t create by clicking the Edit button on the recipe, you\u2019ll either be redirected to the login page (if you hadn\u2019t yet authenticated) or see an \u201caccess denied\u201d page, as shown in \ufb01gure 24.7.<br \/>\n\u8fde\u63a5\u597d\u6240\u6709\u5185\u5bb9\u540e\uff0c\u60a8\u53ef\u4ee5\u8bd5\u7528\u8be5\u5e94\u7528\u7a0b\u5e8f\u3002\u5982\u679c\u60a8\u5c1d\u8bd5\u901a\u8fc7\u5355\u51fb\u914d\u65b9\u4e0a\u7684 Edit \u6309\u94ae\u6765\u7f16\u8f91\u4e0d\u662f\u521b\u5efa\u7684\u914d\u65b9\uff0c\u60a8\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\uff08\u5982\u679c\u60a8\u5c1a\u672a\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff09\u6216\u770b\u5230 \u201caccess denied\u201d \u9875\u9762\uff0c\u5982\u56fe 24.7 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2407.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.7 If you\u2019re logged in but not authorized to edit a recipe, you\u2019ll be redirected to an \u201cAccess Denied\u201d page. If you\u2019re not logged in, you\u2019ll be redirected to the Login page.<br \/>\n\u56fe 24.7 \u5982\u679c\u60a8\u5df2\u767b\u5f55\u4f46\u65e0\u6743\u7f16\u8f91\u914d\u65b9\uff0c\u60a8\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u201cAccess Denied\u201d\u9875\u9762\u3002\u5982\u679c\u60a8\u5c1a\u672a\u767b\u5f55\uff0c\u60a8\u5c06\u88ab\u91cd\u5b9a\u5411\u5230 Login \uff08\u767b\u5f55\u9875\u9762\uff09\u3002<\/p>\n<p>By using resource-based authorization, you\u2019re able to enact more \ufb01ne-grained authorization requirements that you can apply at the level of an individual document or resource.<br \/>\n\u901a\u8fc7\u4f7f\u7528\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\uff0c\u60a8\u53ef\u4ee5\u5236\u5b9a\u66f4\u7cbe\u7ec6\u7684\u6388\u6743\u8981\u6c42\uff0c\u8fd9\u4e9b\u8981\u6c42\u53ef\u4ee5\u5e94\u7528\u4e8e\u5355\u4e2a\u6587\u6863\u6216\u8d44\u6e90\u7ea7\u522b\u3002<\/p>\n<p>Instead of being able to authorize only that a user can edit any recipe, you can authorize whether a user can edit this recipe.<br \/>\n\u60a8\u53ef\u4ee5\u6388\u6743\u7528\u6237\u662f\u5426\u53ef\u4ee5\u7f16\u8f91\u6b64\u914d\u65b9\uff0c\u800c\u4e0d\u662f\u4ec5\u6388\u6743\u7528\u6237\u53ef\u4ee5\u7f16\u8f91\u4efb\u4f55\u914d\u65b9\u3002<\/p>\n<p>All the authorization techniques you\u2019ve seen so far have focused on server-side checks. Both the [Authorize] attribute and resource-based authorization approaches focus on stopping users from executing a protected endpoint on the server. This is important from a security point of view, but there\u2019s another aspect you should consider: the user experience when they don\u2019t have permission.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u60a8\u770b\u5230\u7684\u6240\u6709\u6388\u6743\u6280\u672f\u90fd\u96c6\u4e2d\u5728\u670d\u52a1\u5668\u7aef\u68c0\u67e5\u4e0a\u3002[Authorize] \u5c5e\u6027\u548c\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u65b9\u6cd5\u90fd\u4fa7\u91cd\u4e8e\u963b\u6b62\u7528\u6237\u5728\u670d\u52a1\u5668\u4e0a\u6267\u884c\u53d7\u4fdd\u62a4\u7684\u7ec8\u7ed3\u70b9\u3002\u4ece\u5b89\u5168\u89d2\u5ea6\u6765\u770b\uff0c\u8fd9\u5f88\u91cd\u8981\uff0c\u4f46\u60a8\u5e94\u8be5\u8003\u8651\u53e6\u4e00\u4e2a\u65b9\u9762\uff1a\u7528\u6237\u6ca1\u6709\u6743\u9650\u65f6\u7684\u4f53\u9a8c\u3002<\/p>\n<p>You\u2019ve protected the code executing on the server, but arguably the Edit button should never have been visible to the user if they weren\u2019t going to be allowed to edit the recipe! In the next section we\u2019ll look at how you can conditionally hide the Edit button by using resource-based authorization in your view models.\u200c<br \/>\n\u60a8\u5df2\u7ecf\u4fdd\u62a4\u4e86\u5728\u670d\u52a1\u5668\u4e0a\u6267\u884c\u7684\u4ee3\u7801\uff0c\u4f46\u53ef\u4ee5\u8bf4\uff0c\u5982\u679c\u4e0d\u5141\u8bb8\u7528\u6237\u7f16\u8f91\u914d\u65b9\uff0c\u5219 Edit \uff08\u7f16\u8f91\uff09 \u6309\u94ae\u6c38\u8fdc\u4e0d\u5e94\u8be5\u5bf9\u7528\u6237\u53ef\u89c1\uff01\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5982\u4f55\u5728\u89c6\u56fe\u6a21\u578b\u4e2d\u4f7f\u7528\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u6765\u6709\u6761\u4ef6\u5730\u9690\u85cf Edit \u6309\u94ae\u3002<\/p>\n<blockquote>\n<p>Resource-based authorization versus business-logic checks<br \/>\n\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u4e0e\u4e1a\u52a1\u903b\u8f91\u68c0\u67e5<\/p>\n<p>The value proposition of using the ASP.NET Core framework\u2019s resource- based authorization approach isn\u2019t always clear compared with using simple, manual, business-logic based checks (as in listing 24.13). Using IAuthorizationService and the authorization infrastructure adds an explicit dependency on the ASP.NET Core framework that you may not want to use if you\u2019re performing authorization checks in your domain model services.<br \/>\n\u4e0e\u4f7f\u7528\u7b80\u5355\u7684\u3001\u624b\u52a8\u7684\u3001\u57fa\u4e8e\u4e1a\u52a1\u903b\u8f91\u7684\u68c0\u67e5\uff08\u5982\u6e05\u5355 24.13 \u6240\u793a\uff09\u76f8\u6bd4\uff0c\u4f7f\u7528 ASP.NET Core \u6846\u67b6\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u65b9\u6cd5\u7684\u4ef7\u503c\u4e3b\u5f20\u5e76\u4e0d\u603b\u662f\u5f88\u6e05\u695a\u3002\u4f7f\u7528 IAuthorizationService \u548c\u6388\u6743\u57fa\u7840\u7ed3\u6784\u4f1a\u6dfb\u52a0\u5bf9 ASP.NET Core \u6846\u67b6\u7684\u663e\u5f0f\u4f9d\u8d56\u9879\uff0c\u5982\u679c\u60a8\u5728\u57df\u6a21\u578b\u670d\u52a1\u4e2d\u6267\u884c\u6388\u6743\u68c0\u67e5\uff0c\u5219\u53ef\u80fd\u4e0d\u60f3\u4f7f\u7528\u8be5\u6846\u67b6\u3002<\/p>\n<p>This is a valid concern without an easy answer. I tend to favor simple business-logic checks inside the domain, without relying on the framework\u2019s authorization infrastructure, to make my domain easier to test and framework-independent. But doing so loses some of the bene\ufb01ts of such a framework:<br \/>\n\u8fd9\u662f\u4e00\u4e2a\u5408\u7406\u7684\u62c5\u5fe7\uff0c\u6ca1\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u7b54\u6848\u3002\u6211\u503e\u5411\u4e8e\u5728\u57df\u5185\u8fdb\u884c\u7b80\u5355\u7684\u4e1a\u52a1\u903b\u8f91\u68c0\u67e5\uff0c\u800c\u4e0d\u4f9d\u8d56\u6846\u67b6\u7684\u6388\u6743\u57fa\u7840\u8bbe\u65bd\uff0c\u4ee5\u4f7f\u6211\u7684\u57df\u66f4\u6613\u4e8e\u6d4b\u8bd5\u4e14\u72ec\u7acb\u4e8e\u6846\u67b6\u3002\u4f46\u8fd9\u6837\u505a\u4f1a\u5931\u53bb\u8fd9\u79cd\u6846\u67b6\u7684\u4e00\u4e9b\u597d\u5904\uff1a<\/p>\n<\/blockquote>\n<p>\u2022  The IAuthorizationService uses declarative policies, even though you are calling the authorization framework imperatively.<br \/>\nIAuthorizationService \u4f7f\u7528\u58f0\u660e\u6027\u7b56\u7565\uff0c\u5373\u4f7f\u60a8\u4ee5\u547d\u4ee4\u65b9\u5f0f\u8c03\u7528\u6388\u6743\u6846\u67b6\u4e5f\u662f\u5982\u6b64\u3002<\/p>\n<p>\u2022  You can decouple the need to authorize an action from the actual requirements.<br \/>\n\u60a8\u53ef\u4ee5\u5c06\u6388\u6743\u4f5c\u7684\u9700\u8981\u4e0e\u5b9e\u9645\u8981\u6c42\u5206\u79bb\u3002<\/p>\n<p>\u2022  You can easily rely on peripheral services and properties of the request, which may be harder (or undesirable) with business logic checks.<br \/>\n\u60a8\u53ef\u4ee5\u8f7b\u677e\u4f9d\u8d56\u8bf7\u6c42\u7684\u5916\u56f4\u670d\u52a1\u548c\u5c5e\u6027\uff0c\u8fd9\u5bf9\u4e8e\u4e1a\u52a1\u903b\u8f91\u68c0\u67e5\u53ef\u80fd\u66f4\u96be\uff08\u6216\u4e0d\u53ef\u53d6\uff09\u3002<\/p>\n<blockquote>\n<p>You can achieve these bene\ufb01ts in business-logic checks, but that typically requires creating a lot of infrastructure too, so you lose a lot of the bene\ufb01ts of keeping things simple. Which approach is best will depend on the speci\ufb01cs of your application design, and there may well be cases for using both.<br \/>\n\u4f60\u53ef\u4ee5\u5728\u4e1a\u52a1\u903b\u8f91\u68c0\u67e5\u4e2d\u5b9e\u73b0\u8fd9\u4e9b\u597d\u5904\uff0c\u4f46\u8fd9\u901a\u5e38\u9700\u8981\u521b\u5efa\u5927\u91cf\u7684\u57fa\u7840\u8bbe\u65bd\uff0c\u6240\u4ee5\u4f60\u4f1a\u5931\u53bb\u5f88\u591a\u4fdd\u6301\u7b80\u5355\u7684\u597d\u5904\u3002\u54ea\u79cd\u65b9\u6cd5\u6700\u597d\uff0c\u5c06\u53d6\u51b3\u4e8e\u5e94\u7528\u7a0b\u5e8f\u8bbe\u8ba1\u7684\u5177\u4f53\u60c5\u51b5\uff0c\u5e76\u4e14\u5f88\u53ef\u80fd\u4f1a\u51fa\u73b0\u540c\u65f6\u4f7f\u7528\u8fd9\u4e24\u79cd\u65b9\u6cd5\u7684\u60c5\u51b5\u3002<\/p>\n<p>For example, one possible approach is to use the basic [Authorize] attribute as described in section 24.2.1 to prevent anonymous access to your APIs, potentially with simple, coarse policies applied to your APIs. You would then rely on \u201cmanual\u201d business-logic checks against the ClaimsPrincipal in your domain as required. This may reduce a lot of the complexity and indirection associated with the ASP.NET Core authorization system.<br \/>\n\u4f8b\u5982\uff0c\u4e00\u79cd\u53ef\u80fd\u7684\u65b9\u6cd5\u662f\u4f7f\u7528\u7b2c 24.2.1 \u8282\u4e2d\u6240\u8ff0\u7684\u57fa\u672c [Authorize] \u5c5e\u6027\u6765\u9632\u6b62\u533f\u540d\u8bbf\u95ee\u60a8\u7684 API\uff0c\u53ef\u80fd\u4f1a\u4f7f\u7528\u7b80\u5355\u3001\u7c97\u7565\u7684\u7b56\u7565\u5e94\u7528\u4e8e\u60a8\u7684 API\u3002\u7136\u540e\uff0c\u60a8\u53ef\u4ee5\u6839\u636e\u9700\u8981\u5bf9\u57df\u4e2d\u7684 ClaimsPrincipal \u8fdb\u884c\u201c\u624b\u52a8\u201d\u4e1a\u52a1\u903b\u8f91\u68c0\u67e5\u3002\u8fd9\u53ef\u80fd\u4f1a\u964d\u4f4e\u4e0e ASP.NET Core \u6388\u6743\u7cfb\u7edf\u76f8\u5173\u7684\u8bb8\u591a\u590d\u6742\u6027\u548c\u95f4\u63a5\u6027\u3002<\/p>\n<\/blockquote>\n<h2>24.6 Hiding HTML elements from unauthorized users\u200c<\/h2>\n<p>24.6 \u5bf9\u672a\u7ecf\u6388\u6743\u7684\u7528\u6237\u9690\u85cf HTML \u5143\u7d20<\/p>\n<p>All the authorization code you\u2019ve seen so far has revolved around protecting endpoints on the server side, rather than modifying the UI for users. This is important and should be the starting point whenever you add authorization to an app.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u60a8\u770b\u5230\u7684\u6240\u6709\u6388\u6743\u4ee3\u7801\u90fd\u56f4\u7ed5\u7740\u4fdd\u62a4\u670d\u52a1\u5668\u7aef\u7684\u7aef\u70b9\uff0c\u800c\u4e0d\u662f\u4e3a\u7528\u6237\u4fee\u6539 UI\u3002\u8fd9\u5f88\u91cd\u8981\uff0c\u6bcf\u5f53\u60a8\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u6388\u6743\u65f6\uff0c\u90fd\u5e94\u8be5\u4ece\u6b64\u4f5c\u4e3a\u8d77\u70b9\u3002<\/p>\n<p><b>WARNING<\/b> Malicious users can easily circumvent your UI, so it\u2019s important to always authorize your endpoints on the server, never on the client alone.<br \/>\n\u8b66\u544a:\u6076\u610f\u7528\u6237\u53ef\u4ee5\u8f7b\u677e\u7ed5\u8fc7\u60a8\u7684 UI\uff0c\u56e0\u6b64\u8bf7\u52a1\u5fc5\u59cb\u7ec8\u5728\u670d\u52a1\u5668\u4e0a\u6388\u6743\u60a8\u7684\u7ec8\u7aef\u8282\u70b9\uff0c\u800c\u4e0d\u662f\u4ec5\u5728\u5ba2\u6237\u7aef\u4e0a\u6388\u6743\u3002<\/p>\n<p>From a user-experience point of view, however, it\u2019s not friendly to have buttons or links that look like they\u2019re available but present an \u201caccess denied\u201d page when they\u2019re clicked. A better experience would be for the links to be disabled or not visible at all.<br \/>\n\u7136\u800c\uff0c\u4ece\u7528\u6237\u4f53\u9a8c\u7684\u89d2\u5ea6\u6765\u770b\uff0c\u8ba9\u6309\u94ae\u6216\u94fe\u63a5\u770b\u8d77\u6765\u53ef\u7528\u4f46\u5728\u70b9\u51fb\u65f6\u663e\u793a \u201c\u62d2\u7edd\u8bbf\u95ee\u201d \u9875\u9762\u5e76\u4e0d\u53cb\u597d\u3002\u66f4\u597d\u7684\u4f53\u9a8c\u662f\u7981\u7528\u94fe\u63a5\u6216\u6839\u672c\u4e0d\u663e\u793a\u94fe\u63a5\u3002<\/p>\n<p>You can achieve this in several ways in your own Razor templates. In this section I\u2019m going to show you how to add an additional property to the PageModel, called CanEditRecipe, which the Razor view template will use to change the rendered HTML.<br \/>\n\u60a8\u53ef\u4ee5\u5728\u81ea\u5df1\u7684 Razor \u6a21\u677f\u4e2d\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u5b9e\u73b0\u6b64\u76ee\u7684\u3002\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u5411\u60a8\u5c55\u793a\u5982\u4f55\u5411 PageModel \u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a CanEditRecipe \u7684\u9644\u52a0\u5c5e\u6027\uff0cRazor \u89c6\u56fe\u6a21\u677f\u5c06\u4f7f\u7528\u8be5\u5c5e\u6027\u6765\u66f4\u6539\u5448\u73b0\u7684 HTML\u3002<\/p>\n<p><b>TIP<\/b>  An alternative approach would be to inject IAuthorizationService directly into the view template using the @inject directive, as you saw in chapter 9, but you should generally prefer to keep logic like this in the page handler.<br \/>\n\u63d0\u793a:\u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 @inject \u6307\u4ee4\u5c06 IAuthorizationService \u76f4\u63a5\u6ce8\u5165\u89c6\u56fe\u6a21\u677f\u4e2d\uff0c\u5982\u7b2c 9 \u7ae0\u6240\u793a\uff0c\u4f46\u60a8\u901a\u5e38\u66f4\u613f\u610f\u5728\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e2d\u4fdd\u7559\u8fd9\u6837\u7684\u903b\u8f91\u3002<\/p>\n<p>When you\u2019re \ufb01nished, the rendered HTML looks unchanged for recipes you created, but the Edit button will be hidden when viewing a recipe someone else created, as shown in \ufb01gure 24.8.<br \/>\n\u5b8c\u6210\u540e\uff0c\u60a8\u521b\u5efa\u7684\u914d\u65b9\u7684\u6e32\u67d3 HTML \u770b\u8d77\u6765\u6ca1\u6709\u53d8\u5316\uff0c\u4f46\u662f\u5728\u67e5\u770b\u5176\u4ed6\u4eba\u521b\u5efa\u7684\u914d\u65b9\u65f6\uff0cEdit \uff08\u7f16\u8f91\uff09 \u6309\u94ae\u5c06\u88ab\u9690\u85cf\uff0c\u5982\u56fe 24.8 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2408.jpg\" alt=\"alt text\" \/><\/p>\n<p>Figure 24.8 Although the HTML will appear unchanged for recipes you created, the Edit button is hidden when you view recipes created by a di\ufb00erent user.<br \/>\n\u56fe 24.8 \u867d\u7136\u60a8\u521b\u5efa\u7684\u914d\u65b9\u7684 HTML \u770b\u8d77\u6765\u4e0d\u53d8\uff0c\u4f46\u5f53\u60a8\u67e5\u770b\u5176\u4ed6\u7528\u6237\u521b\u5efa\u7684\u914d\u65b9\u65f6\uff0cEdit\uff08\u7f16\u8f91\uff09\u6309\u94ae\u4f1a\u9690\u85cf\u3002<\/p>\n<p>Listing 24.16 shows the PageModel for the View.cshtml Razor Page, which is used to render the recipe page shown in \ufb01gure 24.8. As you\u2019ve already seen for resource-based authorization, you can use the IAuthorizationService to determine whether the current user has permission to edit the Recipe by calling AuthorizeAsync.<br \/>\n\u5217\u8868 24.16 \u663e\u793a\u4e86 View.cshtml Razor \u9875\u9762\u7684 PageModel\uff0c\u5b83\u7528\u4e8e\u5448\u73b0\u56fe 24.8 \u4e2d\u6240\u793a\u7684\u914d\u65b9\u9875\u9762\u3002\u6b63\u5982\u60a8\u5df2\u7ecf\u770b\u5230\u7684\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 IAuthorizationService \u901a\u8fc7\u8c03\u7528 AuthorizeAsync \u6765\u786e\u5b9a\u5f53\u524d\u7528\u6237\u662f\u5426\u6709\u6743\u7f16\u8f91\u914d\u65b9\u3002<\/p>\n<p>You can then set this value as an additional property on the PageModel, called CanEditRecipe.<br \/>\n\u7136\u540e\uff0c\u60a8\u53ef\u4ee5\u5c06\u6b64\u503c\u8bbe\u7f6e\u4e3a PageModel \u4e0a\u7684\u9644\u52a0\u5c5e\u6027\uff0c\u79f0\u4e3a CanEditRecipe\u3002<\/p>\n<p>Listing 24.16 Setting the CanEditRecipe property in the View.cshtml Razor Page<br \/>\n\u5217\u8868 24.16 \u5728 View.cshtml Razor \u9875\u9762\u4e2d\u8bbe\u7f6e CanEditRecipe \u5c5e\u6027<\/p>\n<pre><code>public class ViewModel : PageModel\n{\npublic Recipe Recipe { get; set; }\npublic bool CanEditRecipe { get; set; } \u2776\nprivate readonly RecipeService _service;\nprivate readonly IAuthorizationService _authService;\npublic ViewModel(\nRecipeService service,\nIAuthorizationService authService)\n{\n_service = service;\n_authService = authService;\n}\npublic async Task&lt;IActionResult&gt; OnGetAsync(int id)\n{\nRecipe = _service.GetRecipe(id); \u2777\nAuthorizationResult isAuthorised = await _authService \u2778\n.AuthorizeAsync(User, recipe, &quot;CanManageRecipe&quot;); \u2778\nCanEditRecipe = isAuthorised.Succeeded; \u2779\nreturn Page();\n}\n}<\/code><\/pre>\n<p>\u2776 The CanEditRecipe property will be used to control whether the Edit button is rendered.<br \/>\nCanEditRecipe \u5c5e\u6027\u5c06\u7528\u4e8e\u63a7\u5236\u662f\u5426\u5448\u73b0 Edit \u6309\u94ae\u3002<\/p>\n<p>\u2777 Loads the Recipe resource for use with IAuthorizationService<br \/>\n\u52a0\u8f7d Recipe \u8d44\u6e90\u4ee5\u7528\u4e8e IAuthorizationService<\/p>\n<p>\u2778 Verifies whether the user is authorized to edit the Recipe<br \/>\n\u9a8c\u8bc1\u7528\u6237\u662f\u5426\u6709\u6743\u7f16\u8f91Recipe<\/p>\n<p>\u2779 Sets the CanEditRecipe property on the PageModel as appropriate<br \/>\n\u6839\u636e\u9700\u8981\u5728 PageModel \u4e0a\u8bbe\u7f6e CanEditRecipe \u5c5e\u6027<\/p>\n<p>Instead of blocking execution of the Razor Page (as you did previously in the Edit.cshtml page handler), use the result of the call to AuthorizeAsync to set the CanEditRecipe value on the PageModel. You can then make a simple change to the View.chstml Razor template, adding an if clause around the rendering of the Edit link:<br \/>\n\u4e0d\u8981\u963b\u6b62 Razor \u9875\u9762\u7684\u6267\u884c\uff08\u5c31\u50cf\u4e4b\u524d\u5728 Edit.cshtml \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e2d\u6240\u505a\u7684\u90a3\u6837\uff09\uff0c\u800c\u662f\u4f7f\u7528\u5bf9 AuthorizeAsync \u7684\u8c03\u7528\u7ed3\u679c\u5728 PageModel \u4e0a\u8bbe\u7f6e CanEditRecipe \u503c\u3002\u7136\u540e\uff0c\u60a8\u53ef\u4ee5\u5bf9 View.chstml Razor \u6a21\u677f\u8fdb\u884c\u7b80\u5355\u7684\u66f4\u6539\uff0c\u5728 Edit \u94fe\u63a5\u7684\u5448\u73b0\u5468\u56f4\u6dfb\u52a0 if \u5b50\u53e5\uff1a<\/p>\n<pre><code>@if(Model.CanEditRecipe)\n{\n&lt;a asp-page=&quot;Edit&quot; asp-route-id=&quot;@Model.Id&quot; class=&quot;btn btn-primary&quot;&gt;Edit&lt;\/a&gt;\n}<\/code><\/pre>\n<p>This ensures that only users who will be able to execute the Edit.cshtml Razor Page can see the link to that page.<br \/>\n\u8fd9\u53ef\u786e\u4fdd\u53ea\u6709\u80fd\u591f\u6267\u884c Edit.cshtml Razor \u9875\u9762\u7684\u7528\u6237\u624d\u80fd\u770b\u5230\u6307\u5411\u8be5\u9875\u9762\u7684\u94fe\u63a5\u3002<\/p>\n<p><b>WARNING<\/b> The if clause means that the Edit link will not be displayed unless the current user created the recipe, but you should never rely on client-side security alone. It\u2019s important to keep the server-side authorization check in your Edit.cshtml page handler to protect against any direct access attempts. Even if a malicious user circumvents your UI, the server-side authorization ensures that your application is secure.<br \/>\n\u8b66\u544a:if \u5b50\u53e5\u8868\u793a\u9664\u975e\u5f53\u524d\u7528\u6237\u521b\u5efa\u4e86\u914d\u65b9\uff0c\u5426\u5219\u4e0d\u4f1a\u663e\u793a Edit \u94fe\u63a5\uff0c\u4f46\u60a8\u7edd\u4e0d\u5e94\u4ec5\u4f9d\u8d56\u5ba2\u6237\u7aef\u5b89\u5168\u6027\u3002\u8bf7\u52a1\u5fc5\u5728 Edit.cshtml \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e2d\u4fdd\u7559\u670d\u52a1\u5668\u7aef\u6388\u6743\u68c0\u67e5\uff0c\u4ee5\u9632\u6b62\u4efb\u4f55\u76f4\u63a5\u8bbf\u95ee\u5c1d\u8bd5\u3002\u5373\u4f7f\u6076\u610f\u7528\u6237\u7ed5\u8fc7\u4e86\u60a8\u7684 UI\uff0c\u670d\u52a1\u5668\u7aef\u6388\u6743\u4e5f\u53ef\u4ee5\u786e\u4fdd\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u662f\u5b89\u5168\u7684\u3002<\/p>\n<p>With that \ufb01nal change, you\u2019ve \ufb01nished adding authorization to the recipe application. Anonymous users can browse the recipes created by others, but they must log in to create new recipes. Additionally, authenticated users can edit only the recipes that they created, and they won\u2019t see an Edit link for other people\u2019s recipes.<br \/>\n\u5b8c\u6210\u6700\u540e\u7684\u66f4\u6539\u540e\uff0c\u60a8\u5df2\u5b8c\u6210\u5411\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u6388\u6743\u3002\u533f\u540d\u7528\u6237\u53ef\u4ee5\u6d4f\u89c8\u5176\u4ed6\u4eba\u521b\u5efa\u7684\u914d\u65b9\uff0c\u4f46\u4ed6\u4eec\u5fc5\u987b\u767b\u5f55\u624d\u80fd\u521b\u5efa\u65b0\u914d\u65b9\u3002\u6b64\u5916\uff0c\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u53ea\u80fd\u7f16\u8f91\u4ed6\u4eec\u521b\u5efa\u7684\u914d\u65b9\uff0c\u5e76\u4e14\u4e0d\u4f1a\u770b\u5230\u5176\u4ed6\u4eba\u7684\u914d\u65b9\u7684 Edit \uff08\u7f16\u8f91\uff09 \u94fe\u63a5\u3002<\/p>\n<p>Authorization is a key aspect of most apps, so it\u2019s important to bear it in mind from an early point. Although it\u2019s possible to add authorization later, as you did with the recipe app, it\u2019s normally preferable to consider authorization sooner rather than later in the app\u2019s development.<br \/>\n\u6388\u6743\u662f\u5927\u591a\u6570\u5e94\u7528\u7a0b\u5e8f\u7684\u5173\u952e\u65b9\u9762\uff0c\u56e0\u6b64\u5c3d\u65e9\u7262\u8bb0\u8fd9\u4e00\u70b9\u975e\u5e38\u91cd\u8981\u3002\u5c3d\u7ba1\u53ef\u4ee5\u7a0d\u540e\u6dfb\u52a0\u6388\u6743\uff0c\u5c31\u50cf\u60a8\u5bf9\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u6240\u505a\u7684\u90a3\u6837\uff0c\u4f46\u901a\u5e38\u6700\u597d\u5728\u5e94\u7528\u7a0b\u5e8f\u5f00\u53d1\u4e2d\u5c3d\u65e9\u8003\u8651\u6388\u6743\u3002<\/p>\n<p>In chapters 23 and 24 we focused on authentication and authorization for traditional web applications using Razor. In chapter 25 we\u2019ll look at API applications, how authentication works with tokens, and how to add authorization policies to minimal APIs.<br \/>\n\u5728\u7b2c 23 \u7ae0\u548c\u7b2c 24 \u7ae0\u4e2d\uff0c\u6211\u4eec\u91cd\u70b9\u4ecb\u7ecd\u4e86\u4f7f\u7528 Razor \u5bf9\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u3002\u5728\u7b2c 25 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd API \u5e94\u7528\u7a0b\u5e8f\u3001\u8eab\u4efd\u9a8c\u8bc1\u5982\u4f55\u4e0e\u4ee4\u724c\u914d\u5408\u4f7f\u7528\uff0c\u4ee5\u53ca\u5982\u4f55\u5c06\u6388\u6743\u7b56\u7565\u6dfb\u52a0\u5230\u6700\u5c0f\u7684 API\u3002<\/p>\n<h2>27.7 Summary<\/h2>\n<p>27.7 \u603b\u7ed3<\/p>\n<p>Authentication is the process of determining who a user is. It\u2019s distinct from authorization, the process of determining what a user can do. Authentication typically occurs before authorization.<br \/>\n\u8eab\u4efd\u9a8c\u8bc1\u662f\u786e\u5b9a\u7528\u6237\u8eab\u4efd\u7684\u8fc7\u7a0b\u3002\u5b83\u4e0e authorization \u4e0d\u540c\uff0c\u6388\u6743\u662f\u786e\u5b9a\u7528\u6237\u53ef\u4ee5\u505a\u4ec0\u4e48\u7684\u8fc7\u7a0b\u3002\u8eab\u4efd\u9a8c\u8bc1\u901a\u5e38\u5728\u6388\u6743\u4e4b\u524d\u8fdb\u884c\u3002<\/p>\n<p>You can use the authorization services in any part of your application, but it\u2019s typically applied using the AuthorizationMiddleware by calling UseAuthorization(). This should be placed after the calls to UseRouting() and UseAuthentication(), and before the call to UseEndpoints() for correct operation.<br \/>\n\u60a8\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u7684\u4efb\u4f55\u90e8\u5206\u4f7f\u7528\u6388\u6743\u670d\u52a1\uff0c\u4f46\u901a\u5e38\u901a\u8fc7\u8c03\u7528 UseAuthorization\uff08\uff09 \u4f7f\u7528 AuthorizationMiddleware \u6765\u5e94\u7528\u6388\u6743\u670d\u52a1\u3002\u8fd9\u5e94\u8be5\u653e\u5728\u8c03\u7528 UseRouting\uff08\uff09 \u548c UseAuthentication\uff08\uff09 \u4e4b\u540e\uff0c\u4ee5\u53ca\u8c03\u7528 UseEndpoints\uff08\uff09 \u4e4b\u524d\uff0c\u4ee5\u4fbf\u6b63\u786e\u4f5c\u3002<\/p>\n<p>You can protect Razor Pages and MVC actions by applying the [Authorize] attribute. The routing middleware records the presence of the attribute as metadata with the selected endpoint. The authorization middleware uses this metadata to determine how to authorize the request.<br \/>\n\u53ef\u4ee5\u901a\u8fc7\u5e94\u7528 [Authorize] \u5c5e\u6027\u6765\u4fdd\u62a4 Razor Pages \u548c MVC\u4f5c\u3002\u8def\u7531\u4e2d\u95f4\u4ef6\u5c06\u5c5e\u6027\u7684\u5b58\u5728\u8bb0\u5f55\u4e3a\u6240\u9009\u7ec8\u7aef\u8282\u70b9\u7684\u5143\u6570\u636e\u3002\u6388\u6743\u4e2d\u95f4\u4ef6\u4f7f\u7528\u6b64\u5143\u6570\u636e\u6765\u786e\u5b9a\u5982\u4f55\u6388\u6743\u8bf7\u6c42\u3002<\/p>\n<p>The simplest form of authorization requires that a user be authenticated before executing an action. You can achieve this by applying the [Authorize] attribute to a Razor Page, action, controller, or globally. You can also apply attributes conventionally to a subset of Razor Pages.<br \/>\n\u6700\u7b80\u5355\u7684\u6388\u6743\u5f62\u5f0f\u8981\u6c42\u5728\u6267\u884c\u4f5c\u4e4b\u524d\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002\u53ef\u4ee5\u901a\u8fc7\u5c06 [Authorize] \u5c5e\u6027\u5e94\u7528\u4e8e Razor \u9875\u9762\u3001\u4f5c\u3001\u63a7\u5236\u5668\u6216\u5168\u5c40\u6765\u5b9e\u73b0\u6b64\u76ee\u7684\u3002\u60a8\u8fd8\u53ef\u4ee5\u6309\u60ef\u4f8b\u5c06\u5c5e\u6027\u5e94\u7528\u4e8e Razor Pages \u7684\u5b50\u96c6\u3002<\/p>\n<p>Claims-based authorization uses the current user\u2019s claims to determine whether they\u2019re authorized to execute an action. You de\ufb01ne the claims needed to execute an action in a policy.<br \/>\n\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u4f7f\u7528\u5f53\u524d\u7528\u6237\u7684\u58f0\u660e\u6765\u786e\u5b9a\u4ed6\u4eec\u662f\u5426\u6709\u6743\u6267\u884c\u4f5c\u3002\u60a8\u53ef\u4ee5\u5b9a\u4e49\u5728\u7b56\u7565\u4e2d\u6267\u884c\u4f5c\u6240\u9700\u7684\u58f0\u660e\u3002<\/p>\n<p>Policies have a name and are con\ufb01gured in Program.cs as part of the call to AddAuthorization() in ConfigureServices. You de\ufb01ne the policy using AddPolicy(), passing in a name and a lambda that de\ufb01nes the claims needed.<br \/>\n\u7b56\u7565\u6709\u4e00\u4e2a\u540d\u79f0\uff0c\u5e76\u5728 Program.cs \u4e2d\u4f5c\u4e3a\u5bf9 ConfigureServices \u4e2d AddAuthorization\uff08\uff09 \u7684\u8c03\u7528\u7684\u4e00\u90e8\u5206\u8fdb\u884c\u914d\u7f6e\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 AddPolicy\uff08\uff09 \u5b9a\u4e49\u7b56\u7565\uff0c\u4f20\u5165\u5b9a\u4e49\u6240\u9700\u58f0\u660e\u7684\u540d\u79f0\u548c lambda\u3002<\/p>\n<p>You can apply a policy to an action or Razor Page by specifying the policy in the authorize attribute; for example, [Authorize(&quot;CanAccessLounge&quot;)]. This policy will be used by the AuthorizationMiddleware to determine whether the user is allowed to execute the selected endpoint.<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u5728 authorize \u5c5e\u6027\u4e2d\u6307\u5b9a\u7b56\u7565\uff0c\u5c06\u7b56\u7565\u5e94\u7528\u4e8e\u4f5c\u6216 Razor \u9875\u9762;\u4f8b\u5982\uff0c[Authorize\uff08\u201cCanAccessLounge\u201d\uff09]\u3002AuthorizationMiddleware \u5c06\u4f7f\u7528\u6b64\u7b56\u7565\u6765\u786e\u5b9a\u662f\u5426\u5141\u8bb8\u7528\u6237\u6267\u884c\u6240\u9009\u7aef\u70b9\u3002<\/p>\n<p>In a Razor Pages app, if an unauthenticated user attempts to execute a protected action, they\u2019ll be redirected to the login page for your app. If they\u2019re already authenticated but don\u2019t have the required claims, they\u2019ll be shown an \u201caccess denied\u201d page instead.<br \/>\n\u5728 Razor Pages \u5e94\u7528\u4e2d\uff0c\u5982\u679c\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u5c1d\u8bd5\u6267\u884c\u53d7\u4fdd\u62a4\u7684\u4f5c\uff0c\u4ed6\u4eec\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u5e94\u7528\u7684\u767b\u5f55\u9875\u9762\u3002\u5982\u679c\u4ed6\u4eec\u5df2\u7ecf\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u4f46\u6ca1\u6709\u6240\u9700\u7684\u58f0\u660e\uff0c\u5219\u4f1a\u663e\u793a\u201caccess denied\u201d\u9875\u9762\u3002<\/p>\n<p>For complex authorization policies, you can build a custom policy. A custom policy consists of one or more requirements, and a requirement can have one or more handlers. You can combine requirements and handlers to create policies of arbitrary complexity.<br \/>\n\u5bf9\u4e8e\u590d\u6742\u7684\u6388\u6743\u7b56\u7565\uff0c\u60a8\u53ef\u4ee5\u6784\u5efa\u81ea\u5b9a\u4e49\u7b56\u7565\u3002\u81ea\u5b9a\u4e49\u7b56\u7565\u7531\u4e00\u4e2a\u6216\u591a\u4e2a\u8981\u6c42\u7ec4\u6210\uff0c\u4e00\u4e2a\u8981\u6c42\u53ef\u4ee5\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u5904\u7406\u7a0b\u5e8f\u3002\u60a8\u53ef\u4ee5\u7ec4\u5408\u9700\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u6765\u521b\u5efa\u4efb\u610f\u590d\u6742\u5ea6\u7684\u7b56\u7565\u3002<\/p>\n<p>For a policy to be authorized, every requirement must be satis\ufb01ed. For a requirement to be satis\ufb01ed, one or more of the associated handlers must indicate success, and none must indicate explicit failure.<br \/>\n\u8981\u6388\u6743\u7b56\u7565\uff0c\u5fc5\u987b\u6ee1\u8db3\u6240\u6709\u8981\u6c42\u3002\u8981\u6ee1\u8db3\u8981\u6c42\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u5173\u8054\u7684\u5904\u7406\u7a0b\u5e8f\u5fc5\u987b\u6307\u793a\u6210\u529f\uff0c\u5e76\u4e14\u6ca1\u6709\u5904\u7406\u7a0b\u5e8f\u5fc5\u987b\u6307\u793a\u663e\u5f0f\u5931\u8d25\u3002<\/p>\n<p><code>AuthorizationHandler&lt;T&gt;<\/code> contains the logic that determines whether a requirement is satis\ufb01ed. For example, if a requirement requires that users be over 18, the handler could look for a DateOfBirth claim and calculate the user\u2019s age.<br \/>\n<code>AuthorizationHandler&lt;T&gt;<\/code> \u5305\u542b\u786e\u5b9a\u662f\u5426\u6ee1\u8db3\u8981\u6c42\u7684\u903b\u8f91\u3002\u4f8b\u5982\uff0c\u5982\u679c\u8981\u6c42\u8981\u6c42\u7528\u6237\u5e74\u6ee1 18 \u5c81\uff0c\u5219\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u67e5\u627e DateOfBirth \u58f0\u660e\u5e76\u8ba1\u7b97\u7528\u6237\u7684\u5e74\u9f84\u3002<\/p>\n<p>Handlers can mark a requirement as satis\ufb01ed by calling context.Succeed (requirement). If a handler can\u2019t satisfy the requirement, it shouldn\u2019t call anything on the context, as a di\ufb00erent handler could call Succeed() and satisfy the requirement.<br \/>\n\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528 context \u5c06\u9700\u6c42\u6807\u8bb0\u4e3a\u6ee1\u8db3\u3002\u6210\u529f \uff08\u8981\u6c42\uff09\u3002\u5982\u679c\u5904\u7406\u7a0b\u5e8f\u65e0\u6cd5\u6ee1\u8db3\u8981\u6c42\uff0c\u5219\u5b83\u4e0d\u5e94\u5728\u4e0a\u4e0b\u6587\u4e2d\u8c03\u7528\u4efb\u4f55\u5185\u5bb9\uff0c\u56e0\u4e3a\u5176\u4ed6\u5904\u7406\u7a0b\u5e8f\u53ef\u4ee5\u8c03\u7528 Succeed\uff08\uff09 \u5e76\u6ee1\u8db3\u8981\u6c42\u3002<\/p>\n<p>If a handler calls context.Fail(), the requirement fails, even if a di\ufb00erent handler marked it as a success using Succeed(). Use this method only if you want to override any calls to Succeed() from other handlers to ensure that the authorization policy will fail authorization.<br \/>\n\u5982\u679c\u5904\u7406\u7a0b\u5e8f\u8c03\u7528 context.Fail\uff08\uff09\uff0c\u5219\u8981\u6c42\u5931\u8d25\uff0c\u5373\u4f7f\u5176\u4ed6\u5904\u7406\u7a0b\u5e8f\u4f7f\u7528 Succeed\uff08\uff09 \u5c06\u5176\u6807\u8bb0\u4e3a\u6210\u529f\u4e5f\u662f\u5982\u6b64\u3002\u4ec5\u5f53\u60a8\u60f3\u8981\u8986\u76d6\u5176\u4ed6\u5904\u7406\u7a0b\u5e8f\u5bf9 Succeed\uff08\uff09 \u7684\u4efb\u4f55\u8c03\u7528\u4ee5\u786e\u4fdd\u6388\u6743\u7b56\u7565\u6388\u6743\u5931\u8d25\u65f6\uff0c\u624d\u4f7f\u7528\u6b64\u65b9\u6cd5\u3002<\/p>\n<p>Resource-based authorization uses details of the resource being protected to determine whether the current user is authorized. For example, if a user is allowed to edit only their own documents, you need to know the author of the document before you can determine whether they\u2019re authorized.<br \/>\n\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u4f7f\u7528\u53d7\u4fdd\u62a4\u8d44\u6e90\u7684\u8be6\u7ec6\u4fe1\u606f\u6765\u786e\u5b9a\u5f53\u524d\u7528\u6237\u662f\u5426\u83b7\u5f97\u6388\u6743\u3002\u4f8b\u5982\uff0c\u5982\u679c\u53ea\u5141\u8bb8\u7528\u6237\u7f16\u8f91\u81ea\u5df1\u7684\u6587\u6863\uff0c\u5219\u9700\u8981\u5148\u77e5\u9053\u6587\u6863\u7684\u4f5c\u8005\uff0c\u7136\u540e\u624d\u80fd\u786e\u5b9a\u4ed6\u4eec\u662f\u5426\u83b7\u5f97\u6388\u6743\u3002<\/p>\n<p>Resource-based authorization uses the same policy, requirements, and handler system as before. Instead of applying authorization with the [Authorize] attribute, you must manually call IAuthorizationService and provide the resource you\u2019re protecting.<br \/>\n\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u4f7f\u7528\u4e0e\u4ee5\u524d\u76f8\u540c\u7684\u7b56\u7565\u3001\u8981\u6c42\u548c\u5904\u7406\u7a0b\u5e8f\u7cfb\u7edf\u3002\u60a8\u5fc5\u987b\u624b\u52a8\u8c03\u7528 IAuthorizationService \u5e76\u63d0\u4f9b\u60a8\u6b63\u5728\u4fdd\u62a4\u7684\u8d44\u6e90\uff0c\u800c\u4e0d\u662f\u4f7f\u7528 [Authorize] \u5c5e\u6027\u5e94\u7528\u6388\u6743\u3002<\/p>\n<p>You can modify the user interface to account for user authorization by adding additional properties to your PageModel. If a user isn\u2019t authorized to execute an action, you can remove or disable the link to that action method in the UI. You should always authorize on the server, even if you\u2019ve removed links from the UI.<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u5411 PageModel \u6dfb\u52a0\u5176\u4ed6\u5c5e\u6027\u6765\u4fee\u6539\u7528\u6237\u754c\u9762\u4ee5\u8003\u8651\u7528\u6237\u6388\u6743\u3002\u5982\u679c\u7528\u6237\u65e0\u6743\u6267\u884c\u4f5c\uff0c\u60a8\u53ef\u4ee5\u5728 UI \u4e2d\u5220\u9664\u6216\u7981\u7528\u6307\u5411\u8be5\u4f5c\u65b9\u6cd5\u7684\u94fe\u63a5\u3002\u60a8\u5e94\u8be5\u59cb\u7ec8\u5728\u670d\u52a1\u5668\u4e0a\u6388\u6743\uff0c\u5373\u4f7f\u60a8\u5df2\u4ece UI \u4e2d\u5220\u9664\u4e86\u94fe\u63a5\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>24 Authorization: Securing your application\u200c 24 Authorization\uff1a \u4fdd\u62a4\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f This chapter covers \u672c\u7ae0\u6db5\u76d6 \u2022 Using authorization to control who can use your app \u4f7f\u7528\u6388\u6743\u6765\u63a7\u5236\u8c01\u53ef\u4ee5\u4f7f\u7528\u4f60\u7684\u5e94\u7528 \u2022 Using claims-based authorization with policies \u5c06\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u4e0e\u7b56\u7565\u7ed3\u5408\u4f7f\u7528 \u2022 Creating custom policies to handle complex requirements \u521b\u5efa\u81ea\u5b9a\u4e49\u7b56\u7565\u4ee5\u5904\u7406\u590d\u6742\u8981\u6c42 \u2022 Authorizing a request depending upon the resource being accessed \u6839\u636e\u6b63\u5728\u8bbf\u95ee\u7684\u8d44\u6e90\u6388\u6743\u8bf7\u6c42 \u2022 Hiding elements from a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-619","post","type-post","status-publish","format-standard","hentry","category-csharp"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/619","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=619"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/619\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=619"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=619"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=619"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}