{"id":621,"date":"2025-04-05T11:42:49","date_gmt":"2025-04-05T03:42:49","guid":{"rendered":"https:\/\/www.hyy.net\/?p=621"},"modified":"2025-04-05T11:42:49","modified_gmt":"2025-04-05T03:42:49","slug":"asp-net-core-in-action-25-authentication-and-authorization-for-apis","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=621","title":{"rendered":"ASP.NET Core in Action 25 Authentication and authorization for APIs"},"content":{"rendered":"<p>25 Authentication and authorization for APIs<br \/>\n25 API \u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743<\/p>\n<p>This chapter covers<br \/>\n\u672c\u7ae0\u6db5\u76d6<\/p>\n<p>\u2022  Seeing how authentication works for APIs in ASP.NET Core<br \/>\n\u4e86\u89e3 ASP.NET Core\u4e2d API \u7684\u8eab\u4efd\u9a8c\u8bc1\u5de5\u4f5c\u539f\u7406<\/p>\n<p>\u2022  Using bearer tokens for authentication<br \/>\n\u4f7f\u7528\u4e0d\u8bb0\u540d\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1<\/p>\n<p>\u2022  Testing APIs locally with JSON Web Tokens<br \/>\n\u4f7f\u7528 JSON Web \u4ee4\u724c\u5728\u672c\u5730\u6d4b\u8bd5 API<\/p>\n<p>\u2022  Applying authorization policies to minimal APIs<br \/>\n\u5c06\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e\u6700\u5c11\u7684 API<\/p>\n<p>In chapter 23 you learned how authentication works with traditional web apps, such as those you would build with Razor Pages or Model-View-Controller (MVC) controllers. Traditional web apps typically use encrypted cookies to store the identity of a user for a request, which the AuthenticationMiddleware then decodes. In this chapter you\u2019ll learn how authentication works for API applications, how it differs from traditional web apps, and what options are available.<br \/>\n\u5728\u7b2c 23 \u7ae0\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86\u8eab\u4efd\u9a8c\u8bc1\u5982\u4f55\u9002\u7528\u4e8e\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u4f8b\u5982\u4f7f\u7528 Razor Pages \u6216\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u63a7\u5236\u5668\u6784\u5efa\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4f7f\u7528\u52a0\u5bc6\u7684 cookie \u6765\u5b58\u50a8\u8bf7\u6c42\u7684\u7528\u6237\u8eab\u4efd\uff0c\u7136\u540e AuthenticationMiddleware \u5bf9\u5176\u8fdb\u884c\u89e3\u7801\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u8eab\u4efd\u9a8c\u8bc1\u5982\u4f55\u7528\u4e8e API \u5e94\u7528\u7a0b\u5e8f\u3001\u5b83\u4e0e\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u6709\u4f55\u4e0d\u540c\uff0c\u4ee5\u53ca\u6709\u54ea\u4e9b\u53ef\u7528\u9009\u9879\u3002<\/p>\n<p>We start by taking a high-level look at how authentication works for APIs, both in isolation and when they\u2019re part of a larger application or distributed system. You\u2019ll learn about some of the protocols involved, such as OAuth 2.0 and OpenID Connect; patterns you can use to protect your APIs; and the tokens used to control access, typically JSON Web Tokens, called JWTs.<br \/>\n\u6211\u4eec\u9996\u5148\u4ece\u9ad8\u5c42\u6b21\u4e0a\u4e86\u89e3\u8eab\u4efd\u9a8c\u8bc1\u5982\u4f55\u7528\u4e8e API\uff0c\u65e0\u8bba\u662f\u5728\u9694\u79bb\u72b6\u6001\u4e0b\uff0c\u8fd8\u662f\u5728\u5b83\u4eec\u5c5e\u4e8e\u5927\u578b\u5e94\u7528\u7a0b\u5e8f\u6216\u5206\u5e03\u5f0f\u7cfb\u7edf\u65f6\u3002\u60a8\u5c06\u4e86\u89e3\u4e00\u4e9b\u6d89\u53ca\u7684\u534f\u8bae\uff0c\u4f8b\u5982 OAuth 2.0 \u548c OpenID Connect;\u53ef\u7528\u4e8e\u4fdd\u62a4 API \u7684\u6a21\u5f0f;\u4ee5\u53ca\u7528\u4e8e\u63a7\u5236\u8bbf\u95ee\u7684\u4ee4\u724c\uff0c\u901a\u5e38\u662f JSON Web \u4ee4\u724c\uff0c\u79f0\u4e3a JWT\u3002<\/p>\n<p>In section 25.3 you\u2019ll learn how to put this knowledge into practice, adding authentication to a minimal API application using JWTs. In section 25.4 you\u2019ll learn how to use the .NET command-line interface (CLI) to generate JWTs for testing your API locally.<br \/>\n\u5728 Section 25.3 \u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5c06\u8fd9\u4e9b\u77e5\u8bc6\u4ed8\u8bf8\u5b9e\u8df5\uff0c\u4f7f\u7528 JWT \u5c06\u8eab\u4efd\u9a8c\u8bc1\u6dfb\u52a0\u5230\u6700\u5c0f\u7684 API \u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002\u5728\u7b2c 25.4 \u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 .NET \u547d\u4ee4\u884c\u754c\u9762 \uff08CLI\uff09 \u751f\u6210 JWT \u4ee5\u5728\u672c\u5730\u6d4b\u8bd5\u60a8\u7684 API\u3002<\/p>\n<p>The .NET CLI works well for generating tokens, but you need a way to add this token to a request. Specifically, if you\u2019re using OpenAPI definitions and Swagger UI as described in chapter 11, you need a way to tell Swagger about your authentication requirements. In section 25.5 you\u2019ll learn about some of the authentication configuration options for your OpenAPI documents and how to use Swagger UI to send authenticated requests to your API.<br \/>\n.NET CLI \u975e\u5e38\u9002\u5408\u751f\u6210\u4ee4\u724c\uff0c\u4f46\u60a8\u9700\u8981\u4e00\u79cd\u65b9\u6cd5\u6765\u5c06\u6b64\u4ee4\u724c\u6dfb\u52a0\u5230\u8bf7\u6c42\u4e2d\u3002\u5177\u4f53\u6765\u8bf4\uff0c\u5982\u679c\u4f60\u6b63\u5728\u4f7f\u7528 OpenAPI \u5b9a\u4e49\u548c Swagger UI\uff0c\u5982\u7b2c 11 \u7ae0\u6240\u8ff0\uff0c\u4f60\u9700\u8981\u4e00\u79cd\u65b9\u6cd5\u6765\u544a\u8bc9 Swagger \u4f60\u7684\u8eab\u4efd\u9a8c\u8bc1\u8981\u6c42\u3002\u5728\u7b2c 25.5 \u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 OpenAPI \u6587\u6863\u7684\u4e00\u4e9b\u8eab\u4efd\u9a8c\u8bc1\u914d\u7f6e\u9009\u9879\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528 Swagger UI \u5c06\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u8bf7\u6c42\u53d1\u9001\u5230 API\u3002<\/p>\n<p>Finally, in section 25.6 I show how to apply authorization policies to minimal API endpoints to restrict which users can call your APIs. The authorization concepts you learned about in chapter 24 for Razor Pages are the same for APIs, so you\u2019re still using claims, requirements, handlers, and polices.<br \/>\n\u6700\u540e\uff0c\u5728\u7b2c 25.6 \u8282\u4e2d\uff0c\u6211\u5c06\u5c55\u793a\u5982\u4f55\u5c06\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e\u6700\u5c0f\u7684 API \u7aef\u70b9\uff0c\u4ee5\u9650\u5236\u54ea\u4e9b\u7528\u6237\u53ef\u4ee5\u8c03\u7528\u60a8\u7684 API\u3002\u60a8\u5728\u7b2c 24 \u7ae0\u4e2d\u5b66\u5230\u7684 Razor Pages \u6388\u6743\u6982\u5ff5\u4e0e API \u76f8\u540c\uff0c\u56e0\u6b64\u60a8\u4ecd\u5728\u4f7f\u7528\u58f0\u660e\u3001\u8981\u6c42\u3001\u5904\u7406\u7a0b\u5e8f\u548c\u7b56\u7565\u3002<\/p>\n<p>We\u2019ll start off by looking at how authentication works when you have an API application. Many of the authentication concepts are similar to traditional apps, but the requirement to support multiple types of users, traditional apps, client-side apps, and mobile apps has led to subtly different solutions.<br \/>\n\u9996\u5148\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5f53\u60a8\u62e5\u6709 API \u5e94\u7528\u7a0b\u5e8f\u65f6\u8eab\u4efd\u9a8c\u8bc1\u7684\u5de5\u4f5c\u539f\u7406\u3002\u8bb8\u591a\u8eab\u4efd\u9a8c\u8bc1\u6982\u5ff5\u4e0e\u4f20\u7edf\u5e94\u7528\u7a0b\u5e8f\u7c7b\u4f3c\uff0c\u4f46\u9700\u8981\u652f\u6301\u591a\u79cd\u7c7b\u578b\u7684\u7528\u6237\u3001\u4f20\u7edf\u5e94\u7528\u7a0b\u5e8f\u3001\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u548c\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u5bfc\u81f4\u4e86\u7565\u6709\u4e0d\u540c\u7684\u89e3\u51b3\u65b9\u6848\u3002<\/p>\n<h2>25.1 Authentication for APIs and distributed applications<\/h2>\n<p>25.1 API \u548c\u5206\u5e03\u5f0f\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1<\/p>\n<p>In this section you\u2019ll learn about the authentication process for API applications, why it typically differs from authentication for traditional web apps, and some of the common patterns and protocols that are involved.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 API \u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\u8fc7\u7a0b\u3001\u4e3a\u4ec0\u4e48\u5b83\u901a\u5e38\u4e0d\u540c\u4e8e\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4ee5\u53ca\u6d89\u53ca\u7684\u4e00\u4e9b\u5e38\u89c1\u6a21\u5f0f\u548c\u534f\u8bae\u3002<\/p>\n<h3>25.1.1 Extending authentication to multiple apps<\/h3>\n<p>25.1.1 \u5c06\u8eab\u4efd\u9a8c\u8bc1\u6269\u5c55\u5230\u591a\u4e2a\u5e94\u7528\u7a0b\u5e8f<\/p>\n<p>I outlined the authentication process for traditional web apps in chapter 23. When a user signs in to your application, you set an encrypted cookie. This cookie contains a serialized version of the ClaimsPrincipal of the user, including their ID and any associated claims. When you make a second request, the browser automatically sends this cookie. The AuthenticationMiddleware then decodes the cookie, deserializes the ClaimsPrincipal, and sets the current user for the request, as shown previously in figure 23.3 and reproduced in figure 25.1.<br \/>\n\u6211\u5728\u7b2c 23 \u7ae0\u4e2d\u6982\u8ff0\u4e86\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\u8fc7\u7a0b\u3002\u5f53\u7528\u6237\u767b\u5f55\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u60a8\u9700\u8981\u8bbe\u7f6e\u4e00\u4e2a\u52a0\u5bc6\u7684 Cookie\u3002\u6b64 Cookie \u5305\u542b\u7528\u6237\u7684 ClaimsPrincipal \u7684\u5e8f\u5217\u5316\u7248\u672c\uff0c\u5305\u62ec\u5176 ID \u548c\u4efb\u4f55\u5173\u8054\u7684\u58f0\u660e\u3002\u5f53\u60a8\u53d1\u51fa\u7b2c\u4e8c\u4e2a\u8bf7\u6c42\u65f6\uff0c\u6d4f\u89c8\u5668\u4f1a\u81ea\u52a8\u53d1\u9001\u6b64 cookie\u3002\u7136\u540e\uff0cAuthenticationMiddleware \u5bf9 cookie \u8fdb\u884c\u89e3\u7801\uff0c\u53cd\u5e8f\u5217\u5316 ClaimsPrincipal\uff0c\u5e76\u4e3a\u8bf7\u6c42\u8bbe\u7f6e\u5f53\u524d\u7528\u6237\uff0c\u5982\u524d\u9762\u7684\u56fe 23.3 \u6240\u793a\uff0c\u5e76\u5728\u56fe 25.1 \u4e2d\u91cd\u73b0\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2501.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.1 When a user first signs in to an app, the app sets an encrypted cookie containing the ClaimsPrincipal. On subsequent requests, the cookie sent with the request contains the user principal, which is deserialized, validated, and used to authenticate the request.<br \/>\n\u56fe 25.1 \u5f53\u7528\u6237\u9996\u6b21\u767b\u5f55\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u5e94\u7528\u7a0b\u5e8f\u4f1a\u8bbe\u7f6e\u4e00\u4e2a\u5305\u542b ClaimsPrincipal \u7684\u52a0\u5bc6 Cookie\u3002\u5728\u540e\u7eed\u8bf7\u6c42\u4e2d\uff0c\u4e0e\u8bf7\u6c42\u4e00\u8d77\u53d1\u9001\u7684 Cookie \u5305\u542b\u7528\u6237\u4e3b\u4f53\uff0c\u8be5\u4e3b\u4f53\u7ecf\u8fc7\u53cd\u5e8f\u5217\u5316\u3001\u9a8c\u8bc1\u5e76\u7528\u4e8e\u5bf9\u8bf7\u6c42\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>This flow works particularly well when you have a single traditional web app that\u2019s doing all the work. The app is responsible for authenticating and managing users, as well as serving your app data and executing business logic, as shown in figure 25.2.<br \/>\n\u5f53\u60a8\u6709\u4e00\u4e2a\u6267\u884c\u6240\u6709\u5de5\u4f5c\u7684\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u6b64\u6d41\u7a0b\u7279\u522b\u6709\u6548\u3002\u8be5\u5e94\u7528\u7a0b\u5e8f\u8d1f\u8d23\u9a8c\u8bc1\u548c\u7ba1\u7406\u7528\u6237\uff0c\u4ee5\u53ca\u63d0\u4f9b\u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u548c\u6267\u884c\u4e1a\u52a1\u903b\u8f91\uff0c\u5982\u56fe 25.2 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2502.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.2 Traditional apps typically handle all the functionality of an app: the business logic, generating the UI, authentication, and user management.<br \/>\n\u56fe 25.2 \u4f20\u7edf\u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u5904\u7406\u5e94\u7528\u7a0b\u5e8f\u7684\u6240\u6709\u529f\u80fd\uff1a\u4e1a\u52a1\u903b\u8f91\u3001\u751f\u6210 UI\u3001\u8eab\u4efd\u9a8c\u8bc1\u548c\u7528\u6237\u7ba1\u7406\u3002<\/p>\n<p>In addition to traditional web apps, it\u2019s common to use ASP.NET Core as an API to serve data for mobile and client-side single-page applications (SPAs). Similarly, even traditional web apps using Razor Pages often need to call API applications behind the scenes, as shown in figure 25.3.<br \/>\n\u9664\u4e86\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u4e4b\u5916\uff0c\u901a\u5e38\u5c06 ASP.NET Core \u7528\u4f5c API\uff0c\u4e3a\u79fb\u52a8\u548c\u5ba2\u6237\u7aef\u5355\u9875\u5e94\u7528\u7a0b\u5e8f \uff08SPA\uff09 \u63d0\u4f9b\u6570\u636e\u3002\u540c\u6837\uff0c\u5373\u4f7f\u662f\u4f7f\u7528 Razor Pages \u7684\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4e5f\u7ecf\u5e38\u9700\u8981\u5728\u540e\u53f0\u8c03\u7528 API \u5e94\u7528\u7a0b\u5e8f\uff0c\u5982\u56fe 25.3 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2503.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.3 Modern applications typically need to expose web APIs for mobile and client-side apps, as well as potentially calling APIs on the backend. When all these services need to authenticate and manage users, this becomes logistically complicated.<br \/>\n\u56fe 25.3 \u73b0\u4ee3\u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u9700\u8981\u4e3a\u79fb\u52a8\u548c\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u516c\u5f00 Web API\uff0c\u5e76\u53ef\u80fd\u5728\u540e\u7aef\u8c03\u7528 API\u3002\u5f53\u6240\u6709\u8fd9\u4e9b\u670d\u52a1\u90fd\u9700\u8981\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u548c\u7ba1\u7406\u65f6\uff0c\u8fd9\u5728\u903b\u8f91\u4e0a\u53d8\u5f97\u590d\u6742\u3002<\/p>\n<p>In this situation you have multiple apps and APIs, all of which need to understand that the same user is logically making a request across all the apps and APIs. If you keep the same approach as before, where each app manages its own users, things can quickly become unmanageable!<br \/>\n\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u6709\u591a\u4e2a\u5e94\u7528\u7a0b\u5e8f\u548c API\uff0c\u6240\u6709\u8fd9\u4e9b\u5e94\u7528\u7a0b\u5e8f\u548c API \u90fd\u9700\u8981\u4e86\u89e3\u540c\u4e00\u7528\u6237\u5728\u903b\u8f91\u4e0a\u8de8\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u548c API \u53d1\u51fa\u8bf7\u6c42\u3002\u5982\u679c\u60a8\u4fdd\u6301\u4e0e\u4ee5\u524d\u76f8\u540c\u7684\u65b9\u6cd5\uff0c\u5373\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u7ba1\u7406\u81ea\u5df1\u7684\u7528\u6237\uff0c\u4e8b\u60c5\u5f88\u5feb\u5c31\u4f1a\u53d8\u5f97\u96be\u4ee5\u7ba1\u7406\uff01<\/p>\n<p>You\u2019d need to duplicate all the sign-in logic between the apps and APIs, as well as have some central database holding the user details. Users would likely need to sign in multiple times to access different parts of the service. On top of that, using cookies becomes problematic for some mobile clients in particular or where you\u2019re making requests to multiple domains (as cookies belong to only a single domain). So how can we improve this? By moving the authentication responsibilities to a separate service.<br \/>\n\u60a8\u9700\u8981\u5728\u5e94\u7528\u7a0b\u5e8f\u548c API \u4e4b\u95f4\u590d\u5236\u6240\u6709\u767b\u5f55\u903b\u8f91\uff0c\u5e76\u62e5\u6709\u4e00\u4e9b\u5305\u542b\u7528\u6237\u8be6\u7ec6\u4fe1\u606f\u7684\u4e2d\u592e\u6570\u636e\u5e93\u3002\u7528\u6237\u53ef\u80fd\u9700\u8981\u591a\u6b21\u767b\u5f55\u624d\u80fd\u8bbf\u95ee\u670d\u52a1\u7684\u4e0d\u540c\u90e8\u5206\u3002\u6700\u91cd\u8981\u7684\u662f\uff0c\u4f7f\u7528 cookie \u5bf9\u4e8e\u67d0\u4e9b\u79fb\u52a8\u5ba2\u6237\u7aef\u6765\u8bf4\u4f1a\u6210\u4e3a\u95ee\u9898\uff0c\u7279\u522b\u662f\u5f53\u60a8\u5411\u591a\u4e2a\u57df\u53d1\u51fa\u8bf7\u6c42\u65f6\uff08\u56e0\u4e3a cookie \u53ea\u5c5e\u4e8e\u4e00\u4e2a\u57df\uff09\u3002\u90a3\u4e48\u6211\u4eec\u5982\u4f55\u6539\u8fdb\u8fd9\u4e00\u70b9\u5462\uff1f\u901a\u8fc7\u5c06\u8eab\u4efd\u9a8c\u8bc1\u8d23\u4efb\u8f6c\u79fb\u5230\u5355\u72ec\u7684\u670d\u52a1\u3002<\/p>\n<h3>25.1.2 Centralizing authentication in an identity provider<\/h3>\n<p>25.1.2 \u5728\u8eab\u4efd\u63d0\u4f9b\u7a0b\u5e8f\u4e2d\u96c6\u4e2d\u9a8c\u8bc1<\/p>\n<p>Modern systems often have many moving parts, each of which requires some level of authentication and authorization to protect each app from unauthorized use. Instead of embedding authentication responsibilities in each application, a common approach is to extract the code that\u2019s common to all the apps and APIs and then move it to an identity provider, as shown in figure 25.4.<br \/>\n\u73b0\u4ee3\u7cfb\u7edf\u901a\u5e38\u6709\u8bb8\u591a\u79fb\u52a8\u90e8\u4ef6\uff0c\u6bcf\u4e2a\u90e8\u4ef6\u90fd\u9700\u8981\u4e00\u5b9a\u7a0b\u5ea6\u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\uff0c\u4ee5\u4fdd\u62a4\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u514d\u53d7\u672a\u7ecf\u6388\u6743\u7684\u4f7f\u7528\u3002\u4e00\u79cd\u5e38\u89c1\u7684\u65b9\u6cd5\u662f\u63d0\u53d6\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u548c API \u901a\u7528\u7684\u4ee3\u7801\uff0c\u7136\u540e\u5c06\u5176\u79fb\u52a8\u5230\u8eab\u4efd\u63d0\u4f9b\u8005\uff0c\u800c\u4e0d\u662f\u5728\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5d4c\u5165\u8eab\u4efd\u9a8c\u8bc1\u8d23\u4efb\uff0c\u5982\u56fe 25.4 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2504.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.4 An alternative architecture involves using a central identity provider to handle all the authentication and user management for the system. Tokens are passed back and forth among the identity provider, apps, and APIs.<br \/>\n\u56fe 25.4 \u53e6\u4e00\u79cd\u67b6\u6784\u6d89\u53ca\u4f7f\u7528\u4e2d\u592e\u8eab\u4efd\u63d0\u4f9b\u5546\u6765\u5904\u7406\u7cfb\u7edf\u7684\u6240\u6709\u8eab\u4efd\u9a8c\u8bc1\u548c\u7528\u6237\u7ba1\u7406\u3002\u4ee4\u724c\u5728\u8eab\u4efd\u63d0\u4f9b\u5546\u3001\u5e94\u7528\u7a0b\u5e8f\u548c API \u4e4b\u95f4\u6765\u56de\u4f20\u9012\u3002<\/p>\n<p>Instead of signing in to an app directly, the app redirects to an identity provider. The user signs in to this identity provider, which passes bearer tokens back to the client (a browser or mobile app, for example) to indicate who the user is and what they\u2019re allowed to access. The client can pass these tokens to the APIs to provide information about the logged-in user without needing to reauthenticate or manage users directly in the API.<br \/>\n\u5e94\u7528\u7a0b\u5e8f\u4e0d\u662f\u76f4\u63a5\u767b\u5f55\u5230\u5e94\u7528\u7a0b\u5e8f\uff0c\u800c\u662f\u91cd\u5b9a\u5411\u5230\u8eab\u4efd\u63d0\u4f9b\u5546\u3002\u7528\u6237\u767b\u5f55\u5230\u6b64\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u8be5\u8eab\u4efd\u63d0\u4f9b\u5546\u5c06\u4e0d\u8bb0\u540d\u4ee4\u724c\u4f20\u9012\u56de\u5ba2\u6237\u7aef\uff08\u4f8b\u5982\u6d4f\u89c8\u5668\u6216\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\uff09\uff0c\u4ee5\u6307\u793a\u7528\u6237\u662f\u8c01\u4ee5\u53ca\u5141\u8bb8\u4ed6\u4eec\u8bbf\u95ee\u7684\u5185\u5bb9\u3002\u5ba2\u6237\u7aef\u53ef\u4ee5\u5c06\u8fd9\u4e9b\u4ee4\u724c\u4f20\u9012\u7ed9 API\uff0c\u4ee5\u63d0\u4f9b\u6709\u5173\u5df2\u767b\u5f55\u7528\u6237\u7684\u4fe1\u606f\uff0c\u800c\u65e0\u9700\u76f4\u63a5\u5728 API \u4e2d\u91cd\u65b0\u9a8c\u8bc1\u6216\u7ba1\u7406\u7528\u6237\u3002<\/p>\n<p><b>DEFINITION<\/b> Bearer tokens are strings that contain authentication details about a user or app. They may or may not be encrypted but are typically signed to avoid tampering. JWTs are the most common format. We\u2019ll look more at JWTs in section 25.2.<br \/>\n\u5b9a\u4e49:\u6301\u6709\u8005\u4ee4\u724c\u662f\u5305\u542b\u6709\u5173\u7528\u6237\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\u8be6\u7ec6\u4fe1\u606f\u7684\u5b57\u7b26\u4e32\u3002\u5b83\u4eec\u53ef\u80fd\u5df2\u52a0\u5bc6\uff0c\u4e5f\u53ef\u80fd\u672a\u52a0\u5bc6\uff0c\u4f46\u901a\u5e38\u4f1a\u8fdb\u884c\u7b7e\u540d\u4ee5\u907f\u514d\u7be1\u6539\u3002JWT \u662f\u6700\u5e38\u89c1\u7684\u683c\u5f0f\u3002\u6211\u4eec\u5c06\u5728 25.2 \u8282\u4e2d\u66f4\u591a\u5730\u4e86\u89e3 JWT\u3002<\/p>\n<p>Using a separate identity provider is clearly more complicated on the face of it, as you\u2019ve thrown a whole new service into the mix, but in the long run this has several advantages:<br \/>\n\u4f7f\u7528\u5355\u72ec\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u4ece\u8868\u9762\u4e0a\u770b\u663e\u7136\u66f4\u590d\u6742\uff0c\u56e0\u4e3a\u60a8\u5df2\u7ecf\u5c06\u4e00\u4e2a\u5168\u65b0\u7684\u670d\u52a1\u6295\u5165\u5176\u4e2d\uff0c\u4f46\u4ece\u957f\u8fdc\u6765\u770b\uff0c\u8fd9\u6709\u51e0\u4e2a\u597d\u5904\uff1a<\/p>\n<p>\u2022  Users can share their identity among multiple services. As you\u2019re logged in to the central identity provider, you\u2019re essentially logged in to all apps that use that service. This gives you the single-sign-on experience, where you don\u2019t have to keep logging in to multiple services.<br \/>\n\u7528\u6237\u53ef\u4ee5\u5728\u591a\u4e2a\u670d\u52a1\u4e4b\u95f4\u5171\u4eab\u5176\u8eab\u4efd\u3002\u5f53\u60a8\u767b\u5f55\u5230\u4e2d\u592e\u8eab\u4efd\u63d0\u4f9b\u5546\u65f6\uff0c\u60a8\u5b9e\u9645\u4e0a\u5df2\u7ecf\u767b\u5f55\u5230\u4f7f\u7528\u8be5\u670d\u52a1\u7684\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u3002\u8fd9\u4e3a\u60a8\u63d0\u4f9b\u4e86\u5355\u70b9\u767b\u5f55\u4f53\u9a8c\uff0c\u60a8\u4e0d\u5fc5\u4e00\u76f4\u767b\u5f55\u5230\u591a\u4e2a\u670d\u52a1\u3002<\/p>\n<p>\u2022  You don\u2019t need to duplicate sign-in logic between multiple services. All the sign-in logic is encapsulated in the identity provider, so you don\u2019t need to add sign-in screens to all your apps.<br \/>\n\u60a8\u65e0\u9700\u5728\u591a\u4e2a\u670d\u52a1\u4e4b\u95f4\u590d\u5236\u767b\u5f55\u903b\u8f91\u3002\u6240\u6709\u767b\u5f55\u903b\u8f91\u90fd\u5c01\u88c5\u5728\u8eab\u4efd\u63d0\u4f9b\u5546\u4e2d\uff0c\u56e0\u6b64\u60a8\u65e0\u9700\u5411\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u767b\u5f55\u5c4f\u5e55\u3002<\/p>\n<p>\u2022  The identity provider has a single responsibility. The identity provider is responsible only for authentication and managing users. In many cases, this is generic enough that you can (and should!) use a third-party identity service, such as Auth0 or Azure Active Directory, instead of building your own.<br \/>\n\u8eab\u4efd\u63d0\u4f9b\u5546\u6709\u5355\u4e00\u804c\u8d23\u3002\u8eab\u4efd\u63d0\u4f9b\u5546\u4ec5\u8d1f\u8d23\u8eab\u4efd\u9a8c\u8bc1\u548c\u7ba1\u7406\u7528\u6237\u3002\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\uff0c\u8fd9\u8db3\u591f\u901a\u7528\uff0c\u60a8\u53ef\u4ee5\uff08\u5e76\u4e14\u5e94\u8be5\uff09\u4f7f\u7528\u7b2c\u4e09\u65b9\u8eab\u4efd\u670d\u52a1\uff0c\u4f8b\u5982 Auth0 \u6216 Azure Active Directory\uff0c\u800c\u4e0d\u662f\u6784\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u670d\u52a1\u3002<\/p>\n<p>\u2022  You can easily add new sign-in mechanisms. Whether you use the identity provider approach or the traditional approach, it\u2019s possible to use external services to handle the authentication of users. You\u2019ll have seen this in apps that allow you to \u201clog in using Facebook\u201d or \u201clog in using Google,\u201d for example. If you use a centralized identity provider, you can add support for more providers in one place instead of having to configure every app and API explicitly.<br \/>\n\u60a8\u53ef\u4ee5\u8f7b\u677e\u6dfb\u52a0\u65b0\u7684\u767b\u5f55\u673a\u5236\u3002\u65e0\u8bba\u60a8\u4f7f\u7528\u8eab\u4efd\u63d0\u4f9b\u5546\u65b9\u6cd5\u8fd8\u662f\u4f20\u7edf\u65b9\u6cd5\uff0c\u90fd\u53ef\u4ee5\u4f7f\u7528\u5916\u90e8\u670d\u52a1\u6765\u5904\u7406\u7528\u6237\u7684\u8eab\u4efd\u9a8c\u8bc1\u3002\u4f8b\u5982\uff0c\u60a8\u4f1a\u5728\u5141\u8bb8\u60a8 \u201c\u4f7f\u7528 Facebook \u767b\u5f55\u201d \u6216 \u201c\u4f7f\u7528 Google \u767b\u5f55\u201d \u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u770b\u5230\u8fd9\u4e00\u70b9\u3002\u5982\u679c\u60a8\u4f7f\u7528\u96c6\u4e2d\u5f0f\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u5219\u53ef\u4ee5\u5728\u4e00\u4e2a\u4f4d\u7f6e\u6dfb\u52a0\u5bf9\u66f4\u591a\u63d0\u4f9b\u5546\u7684\u652f\u6301\uff0c\u800c\u4e0d\u5fc5\u663e\u5f0f\u914d\u7f6e\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u548c API\u3002<\/p>\n<p>Out of the box, ASP.NET Core supports architectures like this and for consuming bearer tokens from identity providers, but it doesn\u2019t include support for issuing those tokens in the core framework. That means you\u2019ll need to use another library or service as the identity provider.<br \/>\n\u5f00\u7bb1\u5373\u7528\u7684 ASP.NET Core \u652f\u6301\u6b64\u7c7b\u67b6\u6784\uff0c\u5e76\u652f\u6301\u4f7f\u7528\u6765\u81ea\u8eab\u4efd\u63d0\u4f9b\u5546\u7684\u4e0d\u8bb0\u540d\u4ee4\u724c\uff0c\u4f46\u5b83\u4e0d\u5305\u62ec\u5bf9\u5728\u6838\u5fc3\u6846\u67b6\u4e2d\u9881\u53d1\u8fd9\u4e9b\u4ee4\u724c\u7684\u652f\u6301\u3002\u8fd9\u610f\u5473\u7740\u60a8\u9700\u8981\u4f7f\u7528\u5176\u4ed6\u5e93\u6216\u670d\u52a1\u4f5c\u4e3a\u8eab\u4efd\u63d0\u4f9b\u5546\u3002<\/p>\n<p>As I mentioned in chapter 23, one excellent option is to use a third-party identity provider, such as Facebook, Google, Okta, Auth0, or Azure Active Directory. These providers take care of storing user passwords, authenticating using modern standards like WebAuthn (<a href=\"https:\/\/webauthn.guide\">https:\/\/webauthn.guide<\/a>), and looking for malicious attempts to impersonate users.<br \/>\n\u6b63\u5982\u6211\u5728\u7b2c 23 \u7ae0\u4e2d\u63d0\u5230\u7684\uff0c\u4e00\u4e2a\u5f88\u597d\u7684\u9009\u62e9\u662f\u4f7f\u7528\u7b2c\u4e09\u65b9\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u6bd4\u5982 Facebook\u3001Google\u3001Okta\u3001Auth0 \u6216 Azure Active Directory\u3002\u8fd9\u4e9b\u63d0\u4f9b\u5546\u8d1f\u8d23\u5b58\u50a8\u7528\u6237\u5bc6\u7801\u3001\u4f7f\u7528 WebAuthn \uff08<a href=\"https:\/\/webauthn.guide\">https:\/\/webauthn.guide<\/a>\uff09 \u7b49\u73b0\u4ee3\u6807\u51c6\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5e76\u5bfb\u627e\u5192\u5145\u7528\u6237\u7684\u6076\u610f\u5c1d\u8bd5\u3002<\/p>\n<p>By using an identity provider, you leave the tricky security details to the experts and can focus on the core purpose of your business, whichever domain that is. Not all providers are equal, though: For some providers (such as Auth0) you own the profiles, whereas for others (Facebook or Google) you don\u2019t. Make sure to choose a provider that matches your requirements.<br \/>\n\u901a\u8fc7\u4f7f\u7528\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u60a8\u53ef\u4ee5\u5c06\u68d8\u624b\u7684\u5b89\u5168\u7ec6\u8282\u7559\u7ed9\u4e13\u5bb6\uff0c\u5e76\u4e14\u53ef\u4ee5\u4e13\u6ce8\u4e8e\u4e1a\u52a1\u7684\u6838\u5fc3\u76ee\u7684\uff0c\u65e0\u8bba\u54ea\u4e2a\u57df\u3002\u4f46\u662f\uff0c\u5e76\u975e\u6240\u6709\u63d0\u4f9b\u5546\u90fd\u662f\u5e73\u7b49\u7684\uff1a\u5bf9\u4e8e\u67d0\u4e9b\u63d0\u4f9b\u5546\uff08\u4f8b\u5982 Auth0\uff09\uff0c\u60a8\u62e5\u6709\u914d\u7f6e\u6587\u4ef6\uff0c\u800c\u5bf9\u4e8e\u5176\u4ed6\u63d0\u4f9b\u5546\uff08Facebook \u6216 Google\uff09\uff0c\u60a8\u5219\u4e0d\u62e5\u6709\u3002\u786e\u4fdd\u9009\u62e9\u7b26\u5408\u60a8\u8981\u6c42\u7684\u63d0\u4f9b\u5546\u3002<\/p>\n<p><b>Tip<\/b> Wherever possible, I recommend using a third-party identity provider. Well-respected identity providers have many experts working solely on securing your customers\u2019 details, proactively preventing attacks and ensuring that the data is safe. By leaving this tricky job to the experts, you\u2019re free to focus on the core business of your app, whatever that may be.<br \/>\n\u63d0\u793a:\u6211\u5efa\u8bae\u5c3d\u53ef\u80fd\u4f7f\u7528\u7b2c\u4e09\u65b9\u8eab\u4efd\u63d0\u4f9b\u5546\u3002\u5907\u53d7\u5c0a\u656c\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u62e5\u6709\u8bb8\u591a\u4e13\u5bb6\uff0c\u4e13\u95e8\u81f4\u529b\u4e8e\u4fdd\u62a4\u5ba2\u6237\u7684\u8be6\u7ec6\u4fe1\u606f\u3001\u4e3b\u52a8\u9632\u6b62\u653b\u51fb\u5e76\u786e\u4fdd\u6570\u636e\u5b89\u5168\u3002\u901a\u8fc7\u5c06\u8fd9\u9879\u68d8\u624b\u7684\u5de5\u4f5c\u7559\u7ed9\u4e13\u5bb6\uff0c\u60a8\u53ef\u4ee5\u81ea\u7531\u5730\u4e13\u6ce8\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684\u6838\u5fc3\u4e1a\u52a1\uff0c\u65e0\u8bba\u5b83\u662f\u4ec0\u4e48\u3002<\/p>\n<p>Another common option is to build your own identity provider. This may sound like a lot of work (and it is!), but thanks to excellent libraries like OpenIddict (<a href=\"https:\/\/github.com\/openiddict\">https:\/\/github.com\/openiddict<\/a>) and Duende\u2019s IdentityServer (<a href=\"https:\/\/duendesoftware.com\">https:\/\/duendesoftware.com<\/a>), it\u2019s perfectly possible to write your own identity provider to serve bearer tokens that can be consumed by your apps and APIs.<br \/>\n\u53e6\u4e00\u4e2a\u5e38\u89c1\u7684\u9009\u9879\u662f\u6784\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u3002\u8fd9\u542c\u8d77\u6765\u50cf\u662f\u5f88\u591a\u5de5\u4f5c\uff08\u786e\u5b9e\u5982\u6b64\uff09\uff0c\u4f46\u591a\u4e8f\u4e86 OpenIddict \uff08<a href=\"https:\/\/github.com\/openiddict\">https:\/\/github.com\/openiddict<\/a>\uff09 \u548c Duende \u7684 IdentityServer \uff08<a href=\"https:\/\/duendesoftware.com\">https:\/\/duendesoftware.com<\/a>\uff09 \u7b49\u4f18\u79c0\u5e93\uff0c\u60a8\u5b8c\u5168\u53ef\u4ee5\u7f16\u5199\u81ea\u5df1\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u6765\u63d0\u4f9b\u53ef\u4f9b\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u548c API \u4f7f\u7528\u7684\u4e0d\u8bb0\u540d\u4ee4\u724c\u3002<\/p>\n<p><b>WARNING<\/b> You should consider carefully whether the effort and risks associated with creating your own identity provider are worthwhile. Bugs are a fact of life, and a bug in your identity provider could easily result in a security vulnerability. Nevertheless, if you have specific identity requirements, creating your own identity provider may be a reasonable or necessary option.<br \/>\n\u8b66\u544a:\u60a8\u5e94\u8be5\u4ed4\u7ec6\u8003\u8651\u4e0e\u521b\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u76f8\u5173\u7684\u52aa\u529b\u548c\u98ce\u9669\u662f\u5426\u503c\u5f97\u3002\u9519\u8bef\u662f\u4e8b\u5b9e\uff0c\u8eab\u4efd\u63d0\u4f9b\u5546\u4e2d\u7684\u9519\u8bef\u5f88\u5bb9\u6613\u5bfc\u81f4\u5b89\u5168\u6f0f\u6d1e\u3002\u4e0d\u8fc7\uff0c\u5982\u679c\u60a8\u6709\u7279\u5b9a\u7684\u8eab\u4efd\u8981\u6c42\uff0c\u521b\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u53ef\u80fd\u662f\u4e00\u4e2a\u5408\u7406\u6216\u5fc5\u8981\u7684\u9009\u62e9\u3002<\/p>\n<p>An aspect often overlooked by people getting started with OpenIddict and IdentityServer is that they aren\u2019t prefabricated solutions. They consist of a set of services and middleware that you add to a standard ASP.NET Core app, providing an implementation of relevant identity standards, according to the specification. You, as a developer, still need to write the profile management code that knows how to create a new user (normally in a database), load a user\u2019s details, validate their password, and manage their associated claims. On top of that, you need to provide all the UI code for the user to log in, manage their passwords, and configure two-factor authentication (2FA). It\u2019s not for the faint of heart!<br \/>\n\u5f00\u59cb\u4f7f\u7528 OpenIddict \u548c IdentityServer \u7684\u4eba\u7ecf\u5e38\u5ffd\u7565\u7684\u4e00\u4e2a\u65b9\u9762\u662f\uff0c\u5b83\u4eec\u4e0d\u662f\u9884\u5236\u7684\u89e3\u51b3\u65b9\u6848\u3002\u5b83\u4eec\u7531\u4e00\u7ec4\u670d\u52a1\u548c\u4e2d\u95f4\u4ef6\u7ec4\u6210\uff0c\u60a8\u53ef\u4ee5\u5c06\u5176\u6dfb\u52a0\u5230\u6807\u51c6 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u6839\u636e\u89c4\u8303\u63d0\u4f9b\u76f8\u5173\u8eab\u4efd\u6807\u51c6\u7684\u5b9e\u73b0\u3002\u4f5c\u4e3a\u5f00\u53d1\u4eba\u5458\uff0c\u60a8\u4ecd\u7136\u9700\u8981\u7f16\u5199 Profile Management \u4ee3\u7801\uff0c\u8be5\u4ee3\u7801\u77e5\u9053\u5982\u4f55\u521b\u5efa\u65b0\u7528\u6237\uff08\u901a\u5e38\u5728\u6570\u636e\u5e93\u4e2d\uff09\u3001\u52a0\u8f7d\u7528\u6237\u7684\u8be6\u7ec6\u4fe1\u606f\u3001\u9a8c\u8bc1\u5176\u5bc6\u7801\u4ee5\u53ca\u7ba1\u7406\u5176\u5173\u8054\u7684\u58f0\u660e\u3002\u6700\u91cd\u8981\u7684\u662f\uff0c\u60a8\u9700\u8981\u4e3a\u7528\u6237\u63d0\u4f9b\u6240\u6709 UI \u4ee3\u7801\u4ee5\u767b\u5f55\u3001\u7ba1\u7406\u4ed6\u4eec\u7684\u5bc6\u7801\u548c\u914d\u7f6e\u53cc\u56e0\u7d20\u8eab\u4efd\u9a8c\u8bc1 \uff082FA\uff09\u3002\u4e0d\u9002\u5408\u80c6\u5c0f\u7684\u4eba\uff01<\/p>\n<p>In many ways, you can think of an identity provider as a traditional web app that has only account management pages. If you want to take on building your own identity provider, ASP.NET Core Identity, described in chapter 23, provides a good basis for the user management side. Adding IdentityServer or OpenIddict gives you the ability to generate tokens for other services, using the OpenID Connect standard, for maximum interoperability with other services.<br \/>\n\u5728\u8bb8\u591a\u65b9\u9762\uff0c\u60a8\u53ef\u4ee5\u5c06\u8eab\u4efd\u63d0\u4f9b\u5546\u89c6\u4e3a\u53ea\u6709\u8d26\u6237\u7ba1\u7406\u9875\u9762\u7684\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u3002\u5982\u679c\u60a8\u60f3\u6784\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u7b2c 23 \u7ae0\u4e2d\u63cf\u8ff0\u7684 ASP.NET Core Identity \u4e3a\u7528\u6237\u7ba1\u7406\u65b9\u9762\u63d0\u4f9b\u4e86\u826f\u597d\u7684\u57fa\u7840\u3002\u6dfb\u52a0 IdentityServer \u6216 OpenIddict \u540e\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 OpenID Connect \u6807\u51c6\u4e3a\u5176\u4ed6\u670d\u52a1\u751f\u6210\u4ee4\u724c\uff0c\u4ee5\u5b9e\u73b0\u4e0e\u5176\u4ed6\u670d\u52a1\u7684\u6700\u5927\u4e92\u4f5c\u6027\u3002<\/p>\n<h3>25.1.3 OpenID Connect and OAuth 2.0<\/h3>\n<p>25.1.3 OpenID Connect \u548c OAuth 2.0<\/p>\n<p>OpenID Connect (OIDC) (<a href=\"http:\/\/openid.net\/connect\">http:\/\/openid.net\/connect<\/a>) is an authentication protocol built on top of the OAuth 2.0 (<a href=\"https:\/\/oauth.net\/2\">https:\/\/oauth.net\/2<\/a>) specification. It\u2019s designed to facilitate the kind of approaches described in section 25.1.2, where you want to leave the responsibility of storing user credentials to someone else (an identity provider). It provides an answer to the question \u201cWhich user sent this request?\u201d without your having to manage the user yourself.<br \/>\nOpenID Connect \uff08OIDC\uff09 \uff08<a href=\"http:\/\/openid.net\/connect\">http:\/\/openid.net\/connect<\/a>\uff09 \u662f\u5728 OAuth 2.0 \uff08<a href=\"https:\/\/oauth.net\/2\">https:\/\/oauth.net\/2<\/a>\uff09 \u89c4\u8303\u4e4b\u4e0a\u6784\u5efa\u7684\u8eab\u4efd\u9a8c\u8bc1\u534f\u8bae\u3002\u5b83\u65e8\u5728\u4fc3\u8fdb\u7b2c 25.1.2 \u8282\u4e2d\u63cf\u8ff0\u7684\u90a3\u79cd\u65b9\u6cd5\uff0c\u60a8\u5e0c\u671b\u5c06\u5b58\u50a8\u7528\u6237\u51ed\u636e\u7684\u8d23\u4efb\u7559\u7ed9\u5176\u4ed6\u4eba\uff08\u8eab\u4efd\u63d0\u4f9b\u5546\uff09\u3002\u5b83\u4e3a\u201c\u54ea\u4e2a\u7528\u6237\u53d1\u9001\u4e86\u6b64\u8bf7\u6c42\u201d\u95ee\u9898\u63d0\u4f9b\u7b54\u6848\uff0c\u800c\u65e0\u9700\u60a8\u81ea\u5df1\u7ba1\u7406\u7528\u6237\u3002<\/p>\n<p><b>NOTE<\/b>  It isn\u2019t strictly necessary to understand these protocols to add authentication to your APIs, but I think it\u2019s best to have a basic understanding of them so that you understand where your APIs fit into the security landscape. If you want to learn more about OpenID Connect, OpenID Connect in Action, by Prabath Siriwardena (Manning, 2023), provides lots more details.<br \/>\n\u6ce8\u610f:\u4e3a\u60a8\u7684 API \u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u5e76\u4e0d\u662f\u7edd\u5bf9\u5fc5\u8981\u7684\uff0c\u4f46\u6211\u8ba4\u4e3a\u6700\u597d\u5bf9\u5b83\u4eec\u6709\u4e00\u4e2a\u57fa\u672c\u7684\u4e86\u89e3\uff0c\u4ee5\u4fbf\u60a8\u4e86\u89e3\u60a8\u7684 API \u5728\u5b89\u5168\u73af\u5883\u4e2d\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u60a8\u60f3\u4e86\u89e3\u6709\u5173 OpenID Connect \u7684\u66f4\u591a\u4fe1\u606f\uff0cPrabath Siriwardena\uff08\u66fc\u5b81\uff0c2023 \u5e74\uff09\u7684 OpenID Connect in Action \u63d0\u4f9b\u4e86\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>Open ID Connect is built on top of the OAuth 2.0 protocol, so it helps to understand that protocol a little first. OAuth 2.0 is an authorization protocol. It allows a user to delegate access of a resource to a different service in a controlled manner without revealing any additional details, such as your identity or any other information.<br \/>\nOpen ID Connect \u6784\u5efa\u5728 OAuth 2.0 \u534f\u8bae\u4e4b\u4e0a\uff0c\u56e0\u6b64\u9996\u5148\u4e86\u89e3\u8be5\u534f\u8bae\u4f1a\u6709\u6240\u5e2e\u52a9\u3002OAuth 2.0 \u662f\u4e00\u79cd\u6388\u6743\u534f\u8bae\u3002\u5b83\u5141\u8bb8\u7528\u6237\u4ee5\u53d7\u63a7\u65b9\u5f0f\u5c06\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u59d4\u6258\u7ed9\u5176\u4ed6\u670d\u52a1\uff0c\u800c\u65e0\u9700\u900f\u9732\u4efb\u4f55\u5176\u4ed6\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f8b\u5982\u60a8\u7684\u8eab\u4efd\u6216\u4efb\u4f55\u5176\u4ed6\u4fe1\u606f\u3002<\/p>\n<p>That\u2019s all a bit abstract, so let\u2019s consider an example. You want to print some photos of your dog through a photo printing service, dogphotos.com. You sign up to the dogphotos.com service, and they give you two options for uploading your photos:<br \/>\n\u8fd9\u4e00\u5207\u90fd\u6709\u70b9\u62bd\u8c61\uff0c\u6240\u4ee5\u8ba9\u6211\u4eec\u8003\u8651\u4e00\u4e2a\u4f8b\u5b50\u3002\u60a8\u60f3\u901a\u8fc7\u7167\u7247\u6253\u5370\u670d\u52a1\u6253\u5370\u4e00\u4e9b\u60a8\u7684\u72d7\u7684\u7167\u7247\uff0cdogphotos.com\u3002\u60a8\u6ce8\u518c\u4e86 dogphotos.com \u670d\u52a1\uff0c\u4ed6\u4eec\u4e3a\u60a8\u63d0\u4f9b\u4e86\u4e24\u79cd\u4e0a\u4f20\u7167\u7247\u7684\u9009\u9879\uff1a<\/p>\n<p>\u2022  Upload from your computer.<br \/>\n\u4ece\u60a8\u7684\u8ba1\u7b97\u673a\u4e0a\u4f20\u3002<\/p>\n<p>\u2022  Download directly from Facebook using OAuth 2.0.<br \/>\n\u4f7f\u7528 OAuth 2.0 \u76f4\u63a5\u4ece Facebook \u4e0b\u8f7d\u3002<\/p>\n<p>As you\u2019re using a new laptop, you haven\u2019t downloaded all the photos of your dog to your computer, so you choose to use OAuth 2.0 instead, as shown in figure 25.5. This triggers the following sequence:<br \/>\n\u7531\u4e8e\u60a8\u4f7f\u7528\u7684\u662f\u65b0\u7b14\u8bb0\u672c\u7535\u8111\uff0c\u56e0\u6b64\u60a8\u5c1a\u672a\u5c06\u72d7\u7684\u6240\u6709\u7167\u7247\u4e0b\u8f7d\u5230\u8ba1\u7b97\u673a\u4e0a\uff0c\u56e0\u6b64\u60a8\u9009\u62e9\u4f7f\u7528 OAuth 2.0\uff0c\u5982\u56fe 25.5 \u6240\u793a\u3002\u8fd9\u5c06\u89e6\u53d1\u4ee5\u4e0b\u5e8f\u5217\uff1a<\/p>\n<ol>\n<li>\n<p>dogphotos.com redirects you to Facebook, where you must sign in (if you haven\u2019t already).<br \/>\ndogphotos.com \u4f1a\u5c06\u60a8\u91cd\u5b9a\u5411\u5230 Facebook\uff0c\u60a8\u5fc5\u987b\u5728\u6b64\u5904\u767b\u5f55\uff08\u5982\u679c\u60a8\u5c1a\u672a\u767b\u5f55\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>Once you\u2019re authenticated, Facebook shows a consent screen, which describes the data dogphotos.com wants to access, which should be your photos only in this case.<br \/>\n\u901a\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u540e\uff0cFacebook \u4f1a\u663e\u793a\u4e00\u4e2a\u540c\u610f\u5c4f\u5e55\uff0c\u5176\u4e2d\u63cf\u8ff0\u4e86 dogphotos.com \u60f3\u8981\u8bbf\u95ee\u7684\u6570\u636e\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u8fd9\u4e9b\u6570\u636e\u5e94\u8be5\u53ea\u662f\u60a8\u7684\u7167\u7247\u3002<\/p>\n<\/li>\n<li>\n<p>When you choose OK, Facebook automatically redirects you to a URL on dogphotos.com and includes an authorization code in the URL.<br \/>\n\u5f53\u60a8\u9009\u62e9 OK \uff08\u786e\u5b9a\uff09 \u65f6\uff0cFacebook \u4f1a\u81ea\u52a8\u5c06\u60a8\u91cd\u5b9a\u5411\u5230 dogphotos.com \u4e0a\u7684 URL\uff0c\u5e76\u5728 URL \u4e2d\u5305\u542b\u6388\u6743\u4ee3\u7801\u3002<\/p>\n<\/li>\n<li>\n<p>dogphotos.com uses this code, in combination with a secret known only by Facebook and dogphotos.com, to retrieve an access token from Facebook.<br \/>\ndogphotos.com \u5c06\u6b64\u4ee3\u7801\u4e0e\u53ea\u6709 Facebook \u548c dogphotos.com \u77e5\u9053\u7684\u5bc6\u94a5\u7ed3\u5408\u4f7f\u7528\uff0c\u4ece Facebook \u68c0\u7d22\u8bbf\u95ee\u4ee4\u724c\u3002<\/p>\n<\/li>\n<li>\n<p>Finally, dogphotos.com uses the token to call the Facebook API and retrieve your dog photos!<br \/>\n\u6700\u540e\uff0cdogphotos.com \u4f7f\u7528\u4ee4\u724c\u8c03\u7528 Facebook API \u5e76\u68c0\u7d22\u60a8\u7684\u72d7\u7167\u7247\uff01<\/p>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2505.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.5 Using OAuth 2.0 to authorize dogphotos.com to access your photos on Facebook<br \/>\n\u56fe 25.5 \u4f7f\u7528 OAuth 2.0 \u6388\u6743 dogphotos.com \u8bbf\u95ee\u60a8\u5728 Facebook \u4e0a\u7684\u7167\u7247<\/p>\n<p>There\u2019s a lot going on in this example, but it gives some nice benefits:<br \/>\n\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\u6709\u5f88\u591a\u5185\u5bb9\uff0c\u4f46\u5b83\u63d0\u4f9b\u4e86\u4e00\u4e9b\u4e0d\u9519\u7684\u597d\u5904\uff1a<\/p>\n<p>\u2022  You didn\u2019t have to give your Facebook credentials to dogphotos.com. You simply signed in to Facebook as normal.<br \/>\n\u60a8\u4e0d\u5fc5\u5c06\u60a8\u7684 Facebook \u51ed\u636e\u63d0\u4f9b\u7ed9 dogphotos.com\u3002\u60a8\u53ea\u9700\u7167\u5e38\u767b\u5f55 Facebook\u3002<\/p>\n<p>\u2022  You had control of which details dogphotos.com could access on your behalf via the Facebook photos API.<br \/>\n\u60a8\u53ef\u4ee5\u63a7\u5236 dogphotos.com \u53ef\u4ee5\u901a\u8fc7 Facebook \u7167\u7247 API \u4ee3\u8868\u60a8\u8bbf\u95ee\u54ea\u4e9b\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>\u2022  You didn\u2019t have to give dogphotos.com any of your identity information (though in practice, this is often requested).<br \/>\n\u60a8\u4e0d\u5fc5\u5411 dogphotos.com \u63d0\u4f9b\u4efb\u4f55\u8eab\u4efd\u4fe1\u606f\uff08\u5c3d\u7ba1\u5728\u5b9e\u8df5\u4e2d\uff0c\u8fd9\u7ecf\u5e38\u88ab\u8981\u6c42\uff09\u3002<\/p>\n<p>Effectively, you delegated your access of the Facebook photos API to dogphotos.com. This approach is why OAuth 2.0 is described as an authorization protocol, not an authentication protocol. dogphotos.com doesn\u2019t know your identity on Facebook; it is authorized only to access the photos API on behalf of someone.<br \/>\n\u5b9e\u9645\u4e0a\uff0c\u60a8\u5c06 Facebook \u7167\u7247 API \u7684\u8bbf\u95ee\u6743\u9650\u59d4\u6258\u7ed9\u4e86 dogphotos.com\u3002\u8fd9\u79cd\u65b9\u6cd5\u5c31\u662f\u4e3a\u4ec0\u4e48 OAuth 2.0 \u88ab\u63cf\u8ff0\u4e3a\u6388\u6743\u534f\u8bae\uff0c\u800c\u4e0d\u662f\u8eab\u4efd\u9a8c\u8bc1\u534f\u8bae\u7684\u539f\u56e0\u3002dogphotos.com \u4e0d\u77e5\u9053\u60a8\u5728 Facebook \u4e0a\u7684\u8eab\u4efd;\u5b83\u4ec5\u88ab\u6388\u6743\u4ee3\u8868\u67d0\u4eba\u8bbf\u95ee Photos API\u3002<\/p>\n<blockquote>\n<p>OAuth 2.0 authorization flows and grant types<br \/>\nOAuth 2.0 \u6388\u6743\u6d41\u7a0b\u548c\u6388\u6743\u7c7b\u578b<\/p>\n<\/blockquote>\n<p>The OAuth 2.0 example shows in this section uses a common flow or grant type, as it\u2019s called in OAuth 2.0, for obtaining a token from an identity provider. Oauth 2.0 defines several grant types and extensions, each designed for a different scenario:<br \/>\n\u672c\u8282\u4e2d\u6240\u793a\u7684 OAuth 2.0 \u793a\u4f8b\u4f7f\u7528\u901a\u7528\u6d41\u7a0b\u6216\u6388\u6743\u7c7b\u578b\uff08\u5728 OAuth 2.0 \u4e2d\u79f0\u4e3a\uff09\u4ece\u8eab\u4efd\u63d0\u4f9b\u5546\u5904\u83b7\u53d6\u4ee4\u724c\u3002Oauth 2.0 \u5b9a\u4e49\u4e86\u591a\u79cd\u6388\u6743\u7c7b\u578b\u548c\u6269\u5c55\uff0c\u6bcf\u79cd\u7c7b\u578b\u548c\u6269\u5c55\u90fd\u9488\u5bf9\u4e0d\u540c\u7684\u573a\u666f\u800c\u8bbe\u8ba1\uff1a<\/p>\n<blockquote>\n<p>\u2022  Authorization code\u2014This is the flow I described in figure 25.5, in which an application uses the combination of an authorization code and a secret to retrieve a token.<br \/>\n\u6388\u6743\u7801 - \u8fd9\u662f\u6211\u5728\u56fe 25.5 \u4e2d\u63cf\u8ff0\u7684\u6d41\u7a0b\uff0c\u5176\u4e2d\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u6388\u6743\u7801\u548c\u5bc6\u94a5\u7684\u7ec4\u5408\u6765\u68c0\u7d22\u4ee4\u724c\u3002<\/p>\n<p>\u2022  Proof Key for Code Exchange (PKCE)\u2014This is an extension to the authorization code that you should always favor, if possible, as it provides additional protections against certain attacks, as described in the RFC at <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7636\">https:\/\/www.rfc-editor.org\/rfc\/rfc7636<\/a>.<br \/>\n\u4ee3\u7801\u4ea4\u6362\u8bc1\u660e\u5bc6\u94a5 \uff08PKCE\uff09 - \u8fd9\u662f\u6388\u6743\u7801\u7684\u6269\u5c55\uff0c\u5982\u679c\u53ef\u80fd\uff0c\u60a8\u5e94\u8be5\u59cb\u7ec8\u4f7f\u7528\u8be5\u6269\u5c55\uff0c\u56e0\u4e3a\u5b83\u63d0\u4f9b\u4e86\u9488\u5bf9\u67d0\u4e9b\u653b\u51fb\u7684\u989d\u5916\u4fdd\u62a4\uff0c\u5982 RFC <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7636\">https:\/\/www.rfc-editor.org\/rfc\/rfc7636<\/a> \u4e2d\u6240\u8ff0\u3002<\/p>\n<p>\u2022  Client credentials\u2014This is used when no user is involved, such as when you have an API talking to another API.<br \/>\n\u5ba2\u6237\u7aef\u51ed\u636e - \u5f53\u4e0d\u6d89\u53ca\u7528\u6237\u65f6 \uff08\u4f8b\u5982\uff0c\u5f53 API \u4e0e\u5176\u4ed6 API \u901a\u4fe1\u65f6\uff09 \u4f7f\u7528\u6b64\u51ed\u636e\u3002<\/p>\n<p>Many more grants are available (see <a href=\"https:\/\/oauth.net\/2\/grant-types\">https:\/\/oauth.net\/2\/grant-types<\/a>), and each grant is suited to a different situation. The examples are the most common types, but if your scenario doesn\u2019t match these, it\u2019s worth exploring the other OAuth 2.0 grants available before thinking you need to invent your own! And with Oauth 2.1 coming soon (<a href=\"http:\/\/mng.bz\/XNav\">http:\/\/mng.bz\/XNav<\/a>), there may well be updated guidance to be aware of.<br \/>\n\u8fd8\u6709\u66f4\u591a\u7684\u8d44\u52a9\u91d1\u53ef\u4f9b\u9009\u62e9\uff08\u89c1 <a href=\"https:\/\/oauth.net\/2\/grant-types\uff09\uff0c\u6bcf\u79cd\u8d44\u52a9\u91d1\u90fd\u9002\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u51b5\u3002\u8fd9\u4e9b\u793a\u4f8b\u662f\u6700\u5e38\u89c1\u7684\u7c7b\u578b\uff0c\u4f46\u5982\u679c\u60a8\u7684\u65b9\u6848\u4e0e\u8fd9\u4e9b\u4e0d\u5339\u914d\uff0c\u5219\u503c\u5f97\u5148\u63a2\u7d22\u5176\u4ed6\u53ef\u7528\u7684\">https:\/\/oauth.net\/2\/grant-types\uff09\uff0c\u6bcf\u79cd\u8d44\u52a9\u91d1\u90fd\u9002\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u51b5\u3002\u8fd9\u4e9b\u793a\u4f8b\u662f\u6700\u5e38\u89c1\u7684\u7c7b\u578b\uff0c\u4f46\u5982\u679c\u60a8\u7684\u65b9\u6848\u4e0e\u8fd9\u4e9b\u4e0d\u5339\u914d\uff0c\u5219\u503c\u5f97\u5148\u63a2\u7d22\u5176\u4ed6\u53ef\u7528\u7684<\/a> OAuth 2.0 \u6388\u6743\uff0c\u7136\u540e\u518d\u8003\u8651\u60a8\u9700\u8981\u521b\u5efa\u81ea\u5df1\u7684\u6388\u6743\uff01\u968f\u7740 Oauth 2.1 \u7684\u5373\u5c06\u63a8\u51fa \uff08<a href=\"http:\/\/mng.bz\/XNav\uff09\uff0c\u53ef\u80fd\u4f1a\u6709\u66f4\u65b0\u7684\u6307\u5357\u9700\u8981\u6ce8\u610f\">http:\/\/mng.bz\/XNav\uff09\uff0c\u53ef\u80fd\u4f1a\u6709\u66f4\u65b0\u7684\u6307\u5357\u9700\u8981\u6ce8\u610f<\/a>\u3002<\/p>\n<\/blockquote>\n<p>OAuth 2.0 is great for the scenario I\u2019ve described so far, in which you want to delegate access to a resource (your photos) to someone else (dogphotos.com). But it\u2019s also common for apps to want to know your identity in addition to accessing an API. For example, dogphotos.com may want to be able to contact you via Facebook if there\u2019s a problem with your photos.<br \/>\nOAuth 2.0 \u975e\u5e38\u9002\u5408\u6211\u5230\u76ee\u524d\u4e3a\u6b62\u63cf\u8ff0\u7684\u65b9\u6848\uff0c\u5728\u8be5\u65b9\u6848\u4e2d\uff0c\u60a8\u5e0c\u671b\u5c06\u5bf9\u8d44\u6e90\uff08\u60a8\u7684\u7167\u7247\uff09\u7684\u8bbf\u95ee\u6743\u9650\u59d4\u6d3e\u7ed9\u5176\u4ed6\u4eba \uff08dogphotos.com\uff09\u3002\u4f46\u662f\uff0c\u9664\u4e86\u8bbf\u95ee API \u4e4b\u5916\uff0c\u5e94\u7528\u7a0b\u5e8f\u8fd8\u60f3\u77e5\u9053\u60a8\u7684\u8eab\u4efd\u4e5f\u5f88\u5e38\u89c1\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u7684\u7167\u7247\u6709\u95ee\u9898\uff0cdogphotos.com \u53ef\u80fd\u5e0c\u671b\u80fd\u591f\u901a\u8fc7 Facebook \u4e0e\u60a8\u8054\u7cfb\u3002<\/p>\n<p>This is where OpenID Connect comes in. OpenID Connect takes the same basic flows as OAuth 2.0 and adds some conventions, discoverability, and authentication. At a high level, OpenID Connect treats your identity (such as an ID or email address) as a resource that is protected in the same way as any other API. You still need to consent to give dogphotos.com access to your identity details, but once you do, it\u2019s an extra API call for dogphotos.com to retrieve your identity details, as shown in figure 25.6.<br \/>\n\u8fd9\u5c31\u662f OpenID Connect \u7684\u7528\u6b66\u4e4b\u5730\u3002OpenID Connect \u91c7\u7528\u4e0e OAuth 2.0 \u76f8\u540c\u7684\u57fa\u672c\u6d41\u7a0b\uff0c\u5e76\u6dfb\u52a0\u4e86\u4e00\u4e9b\u7ea6\u5b9a\u3001\u53ef\u53d1\u73b0\u6027\u548c\u8eab\u4efd\u9a8c\u8bc1\u3002\u6982\u62ec\u5730\u8bf4\uff0cOpenID Connect \u5c06\u60a8\u7684\u8eab\u4efd\uff08\u4f8b\u5982 ID \u6216\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff09\u89c6\u4e3a\u4e00\u79cd\u8d44\u6e90\uff0c\u5176\u4fdd\u62a4\u65b9\u5f0f\u4e0e\u4efb\u4f55\u5176\u4ed6 API \u76f8\u540c\u3002\u60a8\u4ecd\u7136\u9700\u8981\u540c\u610f\u624d\u80fd\u6388\u4e88 dogphotos.com \u8bbf\u95ee\u60a8\u7684\u8eab\u4efd\u8be6\u7ec6\u4fe1\u606f\u7684\u6743\u9650\uff0c\u4f46\u662f\u4e00\u65e6\u540c\u610f\uff0cdogphotos.com \u5c06\u8fdb\u884c\u989d\u5916\u7684 API \u8c03\u7528\u6765\u68c0\u7d22\u60a8\u7684\u8eab\u4efd\u8be6\u7ec6\u4fe1\u606f\uff0c\u5982\u56fe 25.6 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2506.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.6 Using OpenID Connect to authenticate with Facebook and retrieve identity information. The overall flow is the same as with Oauth 2.0, as shown in figure 25.5, but with an additional identity token describing the authentication event and API call to retrieve the identity details.<br \/>\n\u56fe 25.6 \u4f7f\u7528 OpenID Connect \u5411 Facebook \u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u5e76\u68c0\u7d22\u8eab\u4efd\u4fe1\u606f\u3002\u6574\u4e2a\u6d41\u7a0b\u4e0e Oauth 2.0 \u76f8\u540c\uff0c\u5982\u56fe 25.5 \u6240\u793a\uff0c\u4f46\u4f7f\u7528\u4e00\u4e2a\u989d\u5916\u7684\u8eab\u4efd\u4ee4\u724c\u6765\u63cf\u8ff0\u8eab\u4efd\u9a8c\u8bc1\u4e8b\u4ef6\u548c API \u8c03\u7528\u6765\u68c0\u7d22\u8eab\u4efd\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>OpenID Connect is a crucial authentication component in many systems, but if you\u2019re building the API only (for example, the Facebook photos API from figures 25.5 and 25.6), all you really care about are the tokens in the requests; how that token was obtained is less important from a technical standpoint. In the next section we\u2019ll look in detail at these tokens and how they work.<br \/>\nOpenID Connect \u662f\u8bb8\u591a\u7cfb\u7edf\u4e2d\u7684\u5173\u952e\u8eab\u4efd\u9a8c\u8bc1\u7ec4\u4ef6\uff0c\u4f46\u5982\u679c\u60a8\u53ea\u6784\u5efa API\uff08\u4f8b\u5982\uff0c\u56fe 25.5 \u548c 25.6 \u4e2d\u7684 Facebook \u7167\u7247 API\uff09\uff0c\u90a3\u4e48\u60a8\u771f\u6b63\u5173\u5fc3\u7684\u53ea\u662f\u8bf7\u6c42\u4e2d\u7684\u4ee4\u724c;\u4ece\u6280\u672f\u89d2\u5ea6\u6765\u770b\uff0c\u8be5\u4ee3\u5e01\u662f\u5982\u4f55\u83b7\u5f97\u7684\u5e76\u4e0d\u91cd\u8981\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u8be6\u7ec6\u4ecb\u7ecd\u8fd9\u4e9b\u4ee4\u724c\u53ca\u5176\u5de5\u4f5c\u539f\u7406\u3002<\/p>\n<h2>25.2 Understanding bearer token authentication<\/h2>\n<p>25.2 \u4e86\u89e3\u6301\u6709\u8005\u4ee4\u724c\u8eab\u4efd\u9a8c\u8bc1<\/p>\n<p>In this section you\u2019ll learn about bearer tokens: what they are, how they can be used for security with APIs, and the common JWT format for tokens. You\u2019ll learn about some of the limitations of the tokens, approaches to work around these, and some common concepts such as audiences and scopes.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u4e0d\u8bb0\u540d\u4ee4\u724c\uff1a\u5b83\u4eec\u662f\u4ec0\u4e48\uff0c\u5982\u4f55\u901a\u8fc7 API \u4f7f\u7528\u5b83\u4eec\u6765\u786e\u4fdd\u5b89\u5168\u6027\uff0c\u4ee5\u53ca\u4ee4\u724c\u7684\u5e38\u89c1 JWT \u683c\u5f0f\u3002\u60a8\u5c06\u4e86\u89e3\u4ee4\u724c\u7684\u4e00\u4e9b\u9650\u5236\u3001\u89e3\u51b3\u8fd9\u4e9b\u95ee\u9898\u7684\u65b9\u6cd5\uff0c\u4ee5\u53ca\u4e00\u4e9b\u5e38\u89c1\u6982\u5ff5\uff0c\u4f8b\u5982\u53d7\u4f17\u548c\u8303\u56f4\u3002<\/p>\n<p>The name bearer token consists of two parts that describe its use:<br \/>\n\u540d\u79f0\u6301\u6709\u8005\u4ee4\u724c\u7531\u63cf\u8ff0\u5176\u7528\u9014\u7684\u4e24\u4e2a\u90e8\u5206\u7ec4\u6210\uff1a<\/p>\n<p>\u2022  Token\u2014A security token is a string that provides access to a protected resource.<br \/>\n\u4ee4\u724c - \u5b89\u5168\u4ee4\u724c\u662f\u63d0\u4f9b\u5bf9\u53d7\u4fdd\u62a4\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u7684\u5b57\u7b26\u4e32\u3002<\/p>\n<p>\u2022  Bearer\u2014A bearer token is one in which anyone who has the token (the bearer) can use it like anyone else. You don\u2019t need to prove that you were the one who received the token originally or have access to any additional key. You can think of a bearer token as being a bit like money: if it\u2019s in your possession, you can spend it!<br \/>\nBearer - \u5728\u201c\u4e0d\u8bb0\u540d\u4ee4\u724c\u201d\u4e2d\uff0c\u4efb\u4f55\u62e5\u6709\u8be5\u4ee4\u724c \uff08\u201cBearer\u201d\uff09 \u7684\u4eba\u90fd\u53ef\u4ee5\u50cf\u5176\u4ed6\u4efb\u4f55\u4eba\u4e00\u6837\u4f7f\u7528\u5b83\u3002\u60a8\u65e0\u9700\u8bc1\u660e\u60a8\u662f\u6700\u521d\u63a5\u6536\u4ee4\u724c\u7684\u4eba\uff0c\u4e5f\u65e0\u9700\u8bc1\u660e\u60a8\u6709\u6743\u8bbf\u95ee\u4efb\u4f55\u5176\u4ed6\u5bc6\u94a5\u3002\u60a8\u53ef\u4ee5\u5c06\u4e0d\u8bb0\u540d\u4ee3\u5e01\u60f3\u8c61\u6210\u6709\u70b9\u50cf\u91d1\u94b1\uff1a\u5982\u679c\u60a8\u62e5\u6709\u5b83\uff0c\u60a8\u5c31\u53ef\u4ee5\u82b1\u6389\u5b83\uff01<\/p>\n<p>If the second point makes you a little uneasy, that\u2019s good. You should think of bearer tokens as being a lot like passwords: you must protect them at all costs! You should avoid including bearer tokens in URL query strings, for example, as these may be automatically logged, exposing the token accidentally.<br \/>\n\u5982\u679c\u7b2c\u4e8c\u70b9\u8ba9\u4f60\u6709\u70b9\u4e0d\u5b89\uff0c\u90a3\u5f88\u597d\u3002\u60a8\u5e94\u8be5\u5c06\u4e0d\u8bb0\u540d\u4ee4\u724c\u89c6\u4e3a\u5f88\u50cf\u5bc6\u7801\uff1a\u60a8\u5fc5\u987b\u4e0d\u60dc\u4e00\u5207\u4ee3\u4ef7\u4fdd\u62a4\u5b83\u4eec\uff01\u4f8b\u5982\uff0c\u60a8\u5e94\u8be5\u907f\u514d\u5728 URL \u67e5\u8be2\u5b57\u7b26\u4e32\u4e2d\u5305\u542b\u4e0d\u8bb0\u540d\u4ee4\u724c\uff0c\u56e0\u4e3a\u8fd9\u4e9b\u4ee4\u724c\u53ef\u80fd\u4f1a\u88ab\u81ea\u52a8\u8bb0\u5f55\uff0c\u4ece\u800c\u610f\u5916\u5730\u66b4\u9732\u4ee4\u724c\u3002<\/p>\n<blockquote>\n<p>Everything old is new again: Cookies for APIs<br \/>\n\u65e7\u4e8b\u7269\u53c8\u662f\u65b0\u7684\uff1aAPI\u7684 Cookie <\/p>\n<p>Bearer token authentication is extremely common for APIs, but as with everything in tech, the landscape is constantly evolving. One area that has seen a lot of change is the process of securing SPAs like React, Angular, and Blazor WASM. The advice for some years was to use the Authorization code with PKCE grant (<a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8252#section-6\">https:\/\/www.rfc-editor.org\/rfc\/rfc8252#section-6<\/a>), but the big problem with this pattern is that the bearer tokens for calling the API are ultimately stored in the browser.<br \/>\n\u4e0d\u8bb0\u540d\u4ee4\u724c\u8eab\u4efd\u9a8c\u8bc1\u5bf9\u4e8e API \u6765\u8bf4\u6781\u4e3a\u5e38\u89c1\uff0c\u4f46\u4e0e\u6280\u672f\u9886\u57df\u7684\u4e00\u5207\u4e00\u6837\uff0c\u5f62\u52bf\u4e5f\u5728\u4e0d\u65ad\u53d1\u5c55\u3002\u4e00\u4e2a\u53d1\u751f\u5f88\u5927\u53d8\u5316\u7684\u9886\u57df\u662f\u4fdd\u62a4 React\u3001Angular \u548c Blazor WASM \u7b49 SPA \u7684\u8fc7\u7a0b\u3002\u51e0\u5e74\u6765\uff0c\u4eba\u4eec\u7684\u5efa\u8bae\u662f\u5c06\u6388\u6743\u7801\u4e0e PKCE grant \uff08<a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8252#section-6\">https:\/\/www.rfc-editor.org\/rfc\/rfc8252#section-6<\/a>\uff09 \u4e00\u8d77\u4f7f\u7528\uff0c\u4f46\u8fd9\u79cd\u6a21\u5f0f\u7684\u6700\u5927\u95ee\u9898\u662f\uff0c\u7528\u4e8e\u8c03\u7528 API \u7684\u4e0d\u8bb0\u540d\u4ee4\u724c\u6700\u7ec8\u5b58\u50a8\u5728\u6d4f\u89c8\u5668\u4e2d\u3002<\/p>\n<p>An alternative pattern has emerged recently: the Backend for Frontend (BFF) pattern. In this approach, you have a traditional ASP.NET Core application (the backend, which hosts the Blazor WASM or other SPA application (the frontend). The main job of the ASP.NET Core application is to handle OpenID Connect authentication, store the bearer tokens securely, and set an authentication cookie, exactly like a traditional web app.<br \/>\n\u6700\u8fd1\u51fa\u73b0\u4e86\u53e6\u4e00\u79cd\u6a21\u5f0f\uff1aBackend for Frontend \uff08BFF\uff09 \u6a21\u5f0f\u3002\u5728\u6b64\u65b9\u6cd5\u4e2d\uff0c\u4f60\u6709\u4e00\u4e2a\u4f20\u7edf\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\uff08\u540e\u7aef\uff0c\u6258\u7ba1 Blazor WASM \u6216\u5176\u4ed6 SPA \u5e94\u7528\u7a0b\u5e8f\uff08\u524d\u7aef\uff09\u3002ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7684\u4e3b\u8981\u5de5\u4f5c\u662f\u5904\u7406 OpenID Connect \u8eab\u4efd\u9a8c\u8bc1\uff0c\u5b89\u5168\u5730\u5b58\u50a8\u6301\u6709\u8005\u4ee4\u724c\uff0c\u5e76\u8bbe\u7f6e\u8eab\u4efd\u9a8c\u8bc1 Cookie\uff0c\u5c31\u50cf\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u4e00\u6837\u3002<\/p>\n<p>The frontend app in the browser sends requests to the backend app, which automatically includes the cookie. The backend swaps out the authentication cookie for the appropriate bearer token and forwards the request to the real API.<br \/>\n\u6d4f\u89c8\u5668\u4e2d\u7684\u524d\u7aef\u5e94\u7528\u7a0b\u5e8f\u5c06\u8bf7\u6c42\u53d1\u9001\u5230\u540e\u7aef\u5e94\u7528\u7a0b\u5e8f\uff0c\u540e\u7aef\u5e94\u7528\u7a0b\u5e8f\u4f1a\u81ea\u52a8\u5305\u542b Cookie\u3002\u540e\u7aef\u5c06\u8eab\u4efd\u9a8c\u8bc1 Cookie \u6362\u6210\u76f8\u5e94\u7684\u4e0d\u8bb0\u540d\u4ee4\u724c\uff0c\u5e76\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u5b9e\u9645 API\u3002<\/p>\n<p>The big advantages of this approach are that no bearer tokens are ever sent to the browser, and much of the frontend code is significantly simplified. The main down side is that you need to run the additional backend service to support the frontend app. Nevertheless, this is quickly becoming the recommended approach. You can read more about the pattern in Duende\u2019s documentation at <a href=\"http:\/\/mng.bz\/yQdB\">http:\/\/mng.bz\/yQdB<\/a>. Alternatively, you can find a project template for the BFF pattern from Damien Boden at <a href=\"http:\/\/mng.bz\/MBlW\">http:\/\/mng.bz\/MBlW<\/a>.<br \/>\n\u8fd9\u79cd\u65b9\u6cd5\u7684\u4e00\u5927\u4f18\u70b9\u662f\u4e0d\u4f1a\u5411\u6d4f\u89c8\u5668\u53d1\u9001\u4e0d\u8bb0\u540d\u4ee4\u724c\uff0c\u5e76\u4e14\u5927\u90e8\u5206\u524d\u7aef\u4ee3\u7801\u90fd\u5f97\u5230\u4e86\u663e\u8457\u7b80\u5316\u3002\u4e3b\u8981\u7f3a\u70b9\u662f\u60a8\u9700\u8981\u8fd0\u884c\u989d\u5916\u7684\u540e\u7aef\u670d\u52a1\u6765\u652f\u6301\u524d\u7aef\u5e94\u7528\u7a0b\u5e8f\u3002\u5c3d\u7ba1\u5982\u6b64\uff0c\u8fd9\u6b63\u8fc5\u901f\u6210\u4e3a\u63a8\u8350\u7684\u65b9\u6cd5\u3002\u60a8\u53ef\u4ee5\u5728 Duende \u7684\u6587\u6863 <a href=\"http:\/\/mng.bz\/yQdB\">http:\/\/mng.bz\/yQdB<\/a> \u4e2d\u9605\u8bfb\u6709\u5173\u8be5\u6a21\u5f0f\u7684\u66f4\u591a\u4fe1\u606f\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u5728 <a href=\"http:\/\/mng.bz\/MBlW\">http:\/\/mng.bz\/MBlW<\/a> \u4e0a\u627e\u5230 Damien Boden \u63d0\u4f9b\u7684 BFF \u6a21\u5f0f\u7684\u9879\u76ee\u6a21\u677f\u3002<\/p>\n<\/blockquote>\n<p>Bearer tokens don\u2019t have to have any particular value; they could be a completely random string, for example. However, the most common format and the format used by OpenID Connect is a JWT. JWTs (defined in <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7519.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc7519.html<\/a>) consist of three parts:<br \/>\n\u4e0d\u8bb0\u540d\u4ee4\u724c\u4e0d\u5fc5\u5177\u6709\u4efb\u4f55\u7279\u5b9a\u503c;\u4f8b\u5982\uff0c\u5b83\u4eec\u53ef\u4ee5\u662f\u4e00\u4e2a\u5b8c\u5168\u968f\u673a\u7684\u5b57\u7b26\u4e32\u3002\u4f46\u662f\uff0c\u6700\u5e38\u89c1\u7684\u683c\u5f0f\u548c OpenID Connect \u4f7f\u7528\u7684\u683c\u5f0f\u662f JWT\u3002JWT\uff08\u5728 <a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc7519.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc7519.html<\/a> \u4e2d\u5b9a\u4e49\uff09\u7531\u4e09\u4e2a\u90e8\u5206\u7ec4\u6210\uff1a<\/p>\n<p>\u2022  A JavaScript Object Notation (JSON) header describing the token<br \/>\n\u63cf\u8ff0\u4ee4\u724c\u7684 JavaScript \u5bf9\u8c61\u8868\u793a\u6cd5 \uff08JSON\uff09 \u6807\u5934<\/p>\n<p>\u2022  A JSON payload containing the claims<br \/>\n\u5305\u542b\u58f0\u660e\u7684 JSON \u6709\u6548\u8d1f\u8f7d<\/p>\n<p>\u2022  A binary signature created from the header and the payload<br \/>\n\u4ece\u6807\u5934\u548c\u6709\u6548\u8d1f\u8f7d\u521b\u5efa\u7684\u4e8c\u8fdb\u5236\u7b7e\u540d<\/p>\n<p>Each part is base64-encoded and concatenated with a '.' into a single string that can be safely passed in HTTP headers, for example, as shown in figure 25.7. The signature is created using key material that must be shared by the provider that created the token and any API that consumes it. This ensures that the JWT can\u2019t be tampered with, such as to add extra claims to a token.<br \/>\n\u6bcf\u4e2a\u90e8\u5206\u90fd\u7ecf\u8fc7 base64 \u7f16\u7801\uff0c\u5e76\u7528 '.' \u8fde\u63a5\u6210\u4e00\u4e2a\u5b57\u7b26\u4e32\uff0c\u8be5\u5b57\u7b26\u4e32\u53ef\u4ee5\u5728 HTTP \u6807\u5934\u4e2d\u5b89\u5168\u5730\u4f20\u9012\uff0c\u4f8b\u5982\uff0c\u5982\u56fe 25.7 \u6240\u793a\u3002\u7b7e\u540d\u662f\u4f7f\u7528\u5bc6\u94a5\u6750\u6599\u521b\u5efa\u7684\uff0c\u8be5\u5bc6\u94a5\u6750\u6599\u5fc5\u987b\u7531\u521b\u5efa\u4ee4\u724c\u7684\u63d0\u4f9b\u5546\u548c\u4f7f\u7528\u4ee4\u724c\u7684\u4efb\u4f55 API \u5171\u4eab\u3002\u8fd9\u53ef\u786e\u4fdd JWT \u65e0\u6cd5\u88ab\u7be1\u6539\uff0c\u4f8b\u5982\u5411\u4ee4\u724c\u6dfb\u52a0\u989d\u5916\u7684\u58f0\u660e\u3002<\/p>\n<p><b>WARNING<\/b> Always validate the signature of any JWTs you consume, as described in the JWT Best Current Practices RFC (<a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8725\">https:\/\/www.rfc-editor.org\/rfc\/rfc8725<\/a>). ASP.NET Core does this by default.<br \/>\n\u8b66\u544a:\u59cb\u7ec8\u9a8c\u8bc1\u60a8\u4f7f\u7528\u7684\u4efb\u4f55 JWT \u7684\u7b7e\u540d\uff0c\u5982 JWT \u5f53\u524d\u6700\u4f73\u5b9e\u8df5 RFC \uff08<a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8725\">https:\/\/www.rfc-editor.org\/rfc\/rfc8725<\/a>\uff09 \u4e2d\u6240\u8ff0\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cASP.NET Core \u6267\u884c\u6b64\u4f5c\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2507.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.7 An example JWT, decoded using the website <a href=\"https:\/\/jwt.io\">https:\/\/jwt.io<\/a>. The JWT consists of three parts: the header, the payload, and the signature. You must always verify the signature of any JWTs you receive.<br \/>\n\u56fe 25.7 \u4f7f\u7528 website <a href=\"https:\/\/jwt.io\">https:\/\/jwt.io<\/a> \u89e3\u7801\u7684 JWT \u793a\u4f8bJWT \u7531\u4e09\u90e8\u5206\u7ec4\u6210\uff1a\u6807\u5934\u3001\u6709\u6548\u8d1f\u8f7d\u548c\u7b7e\u540d\u3002\u60a8\u5fc5\u987b\u59cb\u7ec8\u9a8c\u8bc1\u60a8\u6536\u5230\u7684\u4efb\u4f55 JWT \u7684\u7b7e\u540d\u3002<\/p>\n<p>Figure 25.7 shows the claims included in the JWT, some of which have cryptic names like iss and iat. These are standard claim names used in OpenID Connect (standing for \u201cIssuer\u201d and \u201cIssued at,\u201d respectively). You generally don\u2019t need to worry about these, as they\u2019re automatically handled by ASP.NET Core when it decodes the token. Nevertheless, it\u2019s helpful to understand what some of these claims mean, as it will help when things go wrong:<br \/>\n\u56fe 25.7 \u663e\u793a\u4e86 JWT \u4e2d\u5305\u542b\u7684\u58f0\u660e\uff0c\u5176\u4e2d\u4e00\u4e9b\u58f0\u660e\u5177\u6709\u6666\u6da9\u96be\u61c2\u7684\u540d\u79f0\uff0c\u5982 iss \u548c iat\u3002\u8fd9\u4e9b\u662f OpenID Connect \u4e2d\u4f7f\u7528\u7684\u6807\u51c6\u58f0\u660e\u540d\u79f0\uff08\u5206\u522b\u4ee3\u8868\u201c\u9881\u53d1\u8005\u201d\u548c\u201c\u9881\u53d1\u8005\u201d\uff09\u3002\u60a8\u901a\u5e38\u65e0\u9700\u62c5\u5fc3\u8fd9\u4e9b\uff0c\u56e0\u4e3a\u5b83\u4eec\u7531 ASP.NET Core \u5728\u89e3\u7801\u4ee4\u724c\u65f6\u81ea\u52a8\u5904\u7406\u3002\u5c3d\u7ba1\u5982\u6b64\uff0c\u4e86\u89e3\u5176\u4e2d\u4e00\u4e9b\u7d22\u8d54\u7684\u542b\u4e49\u4f1a\u6709\u6240\u5e2e\u52a9\uff0c\u56e0\u4e3a\u5f53\u51fa\u73b0\u95ee\u9898\u65f6\u5b83\u4f1a\u6709\u6240\u5e2e\u52a9\uff1a<\/p>\n<p>\u2022  sub\u2014The subject of the token, the unique identifier of the subject it\u2019s describing. This will often be a user, in which case it may be the identity provider\u2019s unique ID for the user.<br \/>\nsub - \u4ee4\u724c\u7684\u4e3b\u9898\uff0c\u5373\u5b83\u6240\u63cf\u8ff0\u7684\u4e3b\u9898\u7684\u552f\u4e00\u6807\u8bc6\u7b26\u3002\u8fd9\u901a\u5e38\u662f\u4e00\u4e2a\u7528\u6237\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5b83\u53ef\u80fd\u662f\u8eab\u4efd\u63d0\u4f9b\u5546\u7684\u7528\u6237\u552f\u4e00 ID\u3002<\/p>\n<p>\u2022  aud\u2014The audience of the token, specifying the domains for which this token was created. When an API validates the token, the API should confirm that the JWT\u2019s aud claim contains the domain of the API.<br \/>\naud - \u4ee4\u724c\u7684\u53d7\u4f17\uff0c\u6307\u5b9a\u4e3a\u5176\u521b\u5efa\u6b64\u4ee4\u724c\u7684\u57df\u3002\u5f53 API \u9a8c\u8bc1\u4ee4\u724c\u65f6\uff0cAPI \u5e94\u786e\u8ba4 JWT \u7684 aud \u58f0\u660e\u5305\u542b API \u7684\u57df\u3002<\/p>\n<p>\u2022  scope\u2014The scopes granted in the token. Scopes define what the user\/app consented to (and is allowed to do). Taking the example from section 25.1, dogphotos.com may have requested the photos.read and photos.edit scopes, but if the user consented only to the photos.read scope, the photos.edit scope would not be in the JWT it receives for use with the Facebook photos API. It\u2019s up to the API itself to interpret what each scope means for the business logic of the request.<br \/>\nscope - \u4ee4\u724c\u4e2d\u6388\u4e88\u7684\u8303\u56f4\u3002\u8303\u56f4\u5b9a\u4e49\u7528\u6237\/\u5e94\u7528\u7a0b\u5e8f\u540c\u610f \uff08\u548c\u5141\u8bb8\uff09 \u6267\u884c\u7684\u4f5c\u3002\u4ee5\u7b2c 25.1 \u8282\u4e3a\u4f8b\uff0cdogphotos.com \u53ef\u80fd\u5df2\u7ecf\u8bf7\u6c42\u4e86photos.read\u548cphotos.edit\u8303\u56f4\uff0c\u4f46\u662f\u5982\u679c\u7528\u6237\u53ea\u540c\u610fphotos.read\u8303\u56f4\uff0c\u5219photos.edit\u8303\u56f4\u5c06\u4e0d\u5728\u5b83\u6536\u5230\u7684\u7528\u4e8e Facebook \u7167\u7247 API \u7684 JWT \u4e2d\u3002\u7531 API \u672c\u8eab\u6765\u89e3\u91ca\u6bcf\u4e2a\u8303\u56f4\u5bf9\u8bf7\u6c42\u7684\u4e1a\u52a1\u903b\u8f91\u7684\u542b\u4e49\u3002<\/p>\n<p>\u2022  exp\u2014The expiration time of the token, after which it is no longer valid, expressed as the number of seconds since midnight on January 1, 1970 (known as the Unix timestamp).<br \/>\nexp - \u4ee4\u724c\u7684\u8fc7\u671f\u65f6\u95f4 \uff08\u8d85\u8fc7\u6b64\u65f6\u95f4\u540e\uff09 \u4e0d\u518d\u6709\u6548\uff0c\u8868\u793a\u4e3a\u81ea 1970 \u5e74 1 \u6708 1 \u65e5\u5348\u591c\u4ee5\u6765\u7684\u79d2\u6570 \uff08\u79f0\u4e3a Unix \u65f6\u95f4\u6233\uff09\u3002<\/p>\n<p>An important point to realize is that JWTs are not encrypted. That means anyone can read the contents of a JWT by default. Another standard, JSON Web Encryption (JWE), can be used to wrap a JWT in an encrypted envelope that can\u2019t be read unless you have the key. Many identity providers include support for using JWEs with nested JWTs, and ASP.NET Core includes support for both out of the box, so it\u2019s something to consider.<br \/>\n\u9700\u8981\u6ce8\u610f\u7684\u4e00\u4e2a\u91cd\u8981\u70b9\u662f JWT \u672a\u52a0\u5bc6\u3002\u8fd9\u610f\u5473\u7740\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u8bfb\u53d6 JWT \u7684\u5185\u5bb9\u3002\u53e6\u4e00\u4e2a\u6807\u51c6 JSON Web \u52a0\u5bc6 \uff08JWE\uff09 \u53ef\u7528\u4e8e\u5c06 JWT \u5305\u88c5\u5728\u52a0\u5bc6\u4fe1\u5c01\u4e2d\uff0c\u9664\u975e\u60a8\u62e5\u6709\u5bc6\u94a5\uff0c\u5426\u5219\u65e0\u6cd5\u8bfb\u53d6\u8be5\u4fe1\u5c01\u3002\u8bb8\u591a\u8eab\u4efd\u63d0\u4f9b\u5546\u90fd\u652f\u6301\u5c06 JWE \u4e0e\u5d4c\u5957\u7684 JWT \u4e00\u8d77\u4f7f\u7528\uff0c\u800c ASP.NET Core \u4e5f\u652f\u6301\u5f00\u7bb1\u5373\u7528\uff0c\u56e0\u6b64\u9700\u8981\u8003\u8651\u8fd9\u4e00\u70b9\u3002<\/p>\n<blockquote>\n<p>Bearer tokens, access tokens, reference tokens, oh my!<br \/>\n\u4e0d\u8bb0\u540d\u4ee4\u724c\u3001\u8bbf\u95ee\u4ee4\u724c\u3001\u5f15\u7528\u4ee4\u724c\uff0c\u5929\u54ea\uff01<\/p>\n<p>The concept of a bearer token described in this section is a generic idea that can be used in several ways and for different purposes. You\u2019ve already read about access tokens and identity tokens used in OpenID Connect. These are both bearer tokens; their different names describe the purpose of the token.<br \/>\n\u672c\u8282\u4e2d\u63cf\u8ff0\u7684 bearer token \u7684\u6982\u5ff5\u662f\u4e00\u4e2a\u901a\u7528\u6982\u5ff5\uff0c\u53ef\u4ee5\u4ee5\u591a\u79cd\u65b9\u5f0f\u7528\u4e8e\u4e0d\u540c\u7684\u76ee\u7684\u3002\u60a8\u5df2\u7ecf\u9605\u8bfb\u4e86 OpenID Connect \u4e2d\u4f7f\u7528\u7684\u8bbf\u95ee\u4ee4\u724c\u548c\u8eab\u4efd\u4ee4\u724c\u3002\u8fd9\u4e9b\u90fd\u662f\u4e0d\u8bb0\u540d\u4ee4\u724c;\u5b83\u4eec\u7684\u4e0d\u540c\u540d\u79f0\u63cf\u8ff0\u4e86\u4ee4\u724c\u7684\u7528\u9014\u3002<\/p>\n<p>The following list describes some of the types of tokens you might read about or run into:<br \/>\n\u4ee5\u4e0b\u5217\u8868\u63cf\u8ff0\u4e86\u60a8\u53ef\u80fd\u4f1a\u9605\u8bfb\u6216\u9047\u5230\u7684\u4e00\u4e9b\u4ee4\u724c\u7c7b\u578b\uff1a<\/p>\n<p>\u2022  Access token\u2014Access tokens are used to authorize access to a resource. These are the tokens typically referred to when you talk about bearer authentication. They come in two flavors:<br \/>\n\u8bbf\u95ee\u4ee4\u724c - \u8bbf\u95ee\u4ee4\u724c\u7528\u4e8e\u6388\u6743\u8bbf\u95ee\u8d44\u6e90\u3002\u8fd9\u4e9b\u662f\u60a8\u5728\u8c08\u8bba\u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u65f6\u901a\u5e38\u63d0\u5230\u7684\u4ee4\u724c\u3002\u5b83\u4eec\u6709\u4e24\u79cd\u53e3\u5473\uff1a<\/p>\n<\/blockquote>\n<p>Self-contained\u2014These are the most common tokens, with JWT as the most common format. They contain metadata, claims, and a signature. The strength of self-contained tokens\u2014that they contain all the data and can be validated offline\u2014is also their weakness, as they can\u2019t be revoked. Due to this, they typically have a limited valid lifespan. They can also become large if they contain many claims, which increases request sizes.<br \/>\n\u81ea\u5305\u542b \u2014 \u8fd9\u4e9b\u662f\u6700\u5e38\u89c1\u7684\u4ee4\u724c\uff0c\u5176\u4e2d JWT \u662f\u6700\u5e38\u89c1\u7684\u683c\u5f0f\u3002\u5b83\u4eec\u5305\u542b\u5143\u6570\u636e\u3001\u58f0\u660e\u548c\u7b7e\u540d\u3002\u81ea\u5305\u542b\u4ee4\u724c\u7684\u4f18\u52bf\uff08\u5b83\u4eec\u5305\u542b\u6240\u6709\u6570\u636e\u5e76\u4e14\u53ef\u4ee5\u79bb\u7ebf\u9a8c\u8bc1\uff09\u4e5f\u662f\u5b83\u4eec\u7684\u5f31\u70b9\uff0c\u56e0\u4e3a\u5b83\u4eec\u65e0\u6cd5\u64a4\u9500\u3002\u56e0\u6b64\uff0c\u5b83\u4eec\u7684\u6709\u6548\u5bff\u547d\u901a\u5e38\u6709\u9650\u3002\u5982\u679c\u5b83\u4eec\u5305\u542b\u8bb8\u591a\u58f0\u660e\uff0c\u5b83\u4eec\u4e5f\u4f1a\u53d8\u5f97\u5f88\u5927\uff0c\u8fd9\u4f1a\u589e\u52a0\u8bf7\u6c42\u5927\u5c0f\u3002<\/p>\n<p>Reference token\u2014These don\u2019t contain any data and are typically a random string. When a protected API receives a reference token, it must exchange the reference token with the identity provider for the claims (for example, a JWT). This approach ensures more privacy, as the claims are never exposed to the client, and the token can be revoked at the identity provider. However, it requires an extra HTTP round trip every time the API receives a request. This makes reference tokens a good option for high-security environments, where the performance effect is less critical.<br \/>\n\u5f15\u7528\u4ee4\u724c \u2013 \u8fd9\u4e9b\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u636e\uff0c\u901a\u5e38\u662f\u968f\u673a\u5b57\u7b26\u4e32\u3002\u5f53\u53d7\u4fdd\u62a4\u7684 API \u6536\u5230\u5f15\u7528\u4ee4\u724c\u65f6\uff0c\u5b83\u5fc5\u987b\u4e0e\u8eab\u4efd\u63d0\u4f9b\u5546\u4ea4\u6362\u5f15\u7528\u4ee4\u724c\u4ee5\u83b7\u53d6\u58f0\u660e\uff08\u4f8b\u5982 JWT\uff09\u3002\u6b64\u65b9\u6cd5\u53ef\u786e\u4fdd\u66f4\u591a\u9690\u79c1\uff0c\u56e0\u4e3a\u58f0\u660e\u6c38\u8fdc\u4e0d\u4f1a\u5411\u5ba2\u6237\u7aef\u516c\u5f00\uff0c\u5e76\u4e14\u53ef\u4ee5\u5728\u8eab\u4efd\u63d0\u4f9b\u5546\u5904\u64a4\u9500\u4ee4\u724c\u3002\u4f46\u662f\uff0c\u6bcf\u6b21 API \u6536\u5230\u8bf7\u6c42\u65f6\uff0c\u5b83\u90fd\u9700\u8981\u989d\u5916\u7684 HTTP \u5f80\u8fd4\u3002\u8fd9\u4f7f\u5f97 reference tokens \u6210\u4e3a\u9ad8\u5b89\u5168\u6027\u73af\u5883\u7684\u4e0d\u9519\u9009\u62e9\uff0c\u56e0\u4e3a\u5728\u8fd9\u79cd\u73af\u5883\u4e2d\uff0c\u6027\u80fd\u5f71\u54cd\u4e0d\u592a\u91cd\u8981\u3002<\/p>\n<blockquote>\n<p>\u2022  ID token\u2014This token is used in OpenID Connect (<a href=\"http:\/\/mng.bz\/a1M7\">http:\/\/mng.bz\/a1M7<\/a>) to describe an authentication event. It may contain additional claims about the authenticated user, but this is not required; if the claims aren\u2019t provided in the ID token, they can be retrieved from the identity provider\u2019s UserInfo endpoint. The ID token is always a JWT, but you should never send it to other APIs; it is not an access token. The ID token can also be used to log out the user at the identity provider.<br \/>\nID \u4ee4\u724c - \u6b64\u4ee4\u724c\u5728 OpenID Connect \uff08<a href=\"http:\/\/mng.bz\/a1M7\">http:\/\/mng.bz\/a1M7<\/a>\uff09 \u4e2d\u7528\u4e8e\u63cf\u8ff0\u8eab\u4efd\u9a8c\u8bc1\u4e8b\u4ef6\u3002\u5b83\u53ef\u80fd\u5305\u542b\u6709\u5173\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u7684\u5176\u4ed6\u58f0\u660e\uff0c\u4f46\u8fd9\u4e0d\u662f\u5fc5\u9700\u7684;\u5982\u679c ID \u4ee4\u724c\u4e2d\u672a\u63d0\u4f9b\u58f0\u660e\uff0c\u5219\u53ef\u4ee5\u4ece\u8eab\u4efd\u63d0\u4f9b\u5546\u7684 UserInfo \u7ec8\u7aef\u8282\u70b9\u68c0\u7d22\u5b83\u4eec\u3002ID \u4ee4\u724c\u59cb\u7ec8\u662f JWT\uff0c\u4f46\u60a8\u7edd\u4e0d\u5e94\u5c06\u5176\u53d1\u9001\u5230\u5176\u4ed6 API;\u5b83\u4e0d\u662f\u8bbf\u95ee\u4ee4\u724c\u3002ID \u4ee4\u724c\u8fd8\u53ef\u7528\u4e8e\u5728\u8eab\u4efd\u63d0\u4f9b\u5546\u5904\u6ce8\u9500\u7528\u6237\u3002<\/p>\n<p>\u2022  Refresh token\u2014For security reasons, access tokens typically have relatively short lifetimes, sometimes as low as 5 minutes. After this time, the access token is no longer valid, and you need to retrieve a new one. Making users log in to their identity provider every 5 minutes is clearly a bad experience, so as part of the OAuth or OpenID Connect flow you can also request a refresh token.<br \/>\n\u5237\u65b0\u4ee4\u724c - \u51fa\u4e8e\u5b89\u5168\u539f\u56e0\uff0c\u8bbf\u95ee\u4ee4\u724c\u7684\u751f\u547d\u5468\u671f\u901a\u5e38\u76f8\u5bf9\u8f83\u77ed\uff0c\u6709\u65f6\u4f4e\u81f3 5 \u5206\u949f\u3002\u5728\u6b64\u65f6\u95f4\u4e4b\u540e\uff0c\u8bbf\u95ee\u4ee4\u724c\u4e0d\u518d\u6709\u6548\uff0c\u60a8\u9700\u8981\u68c0\u7d22\u65b0\u7684\u8bbf\u95ee\u4ee4\u724c\u3002\u8ba9\u7528\u6237\u6bcf 5 \u5206\u949f\u767b\u5f55\u4e00\u6b21\u8eab\u4efd\u63d0\u4f9b\u5546\u663e\u7136\u662f\u4e00\u79cd\u7cdf\u7cd5\u7684\u4f53\u9a8c\uff0c\u56e0\u6b64\u4f5c\u4e3a OAuth \u6216 OpenID Connect \u6d41\u7a0b\u7684\u4e00\u90e8\u5206\uff0c\u60a8\u8fd8\u53ef\u4ee5\u8bf7\u6c42\u5237\u65b0\u4ee4\u724c\u3002<\/p>\n<p>When an access token expires, you can send the refresh token to an identity provider, and it returns a new access token without the user\u2019s needing to log in again. The power to obtain valid access tokens means that it\u2019s critical to protect refresh tokens; should an attacker obtain a refresh token, they effectively have the power to impersonate a user.<br \/>\n\u5f53\u8bbf\u95ee\u4ee4\u724c\u8fc7\u671f\u65f6\uff0c\u60a8\u53ef\u4ee5\u5c06\u5237\u65b0\u4ee4\u724c\u53d1\u9001\u7ed9\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u5b83\u4f1a\u8fd4\u56de\u65b0\u7684\u8bbf\u95ee\u4ee4\u724c\uff0c\u800c\u65e0\u9700\u7528\u6237\u518d\u6b21\u767b\u5f55\u3002\u83b7\u53d6\u6709\u6548\u8bbf\u95ee\u4ee4\u724c\u7684\u80fd\u529b\u610f\u5473\u7740\u4fdd\u62a4\u5237\u65b0\u4ee4\u724c\u81f3\u5173\u91cd\u8981;\u5982\u679c\u653b\u51fb\u8005\u83b7\u53d6\u4e86\u5237\u65b0\u4ee4\u724c\uff0c\u4ed6\u4eec\u5b9e\u9645\u4e0a\u5c31\u6709\u80fd\u529b\u6a21\u62df\u7528\u6237\u3002<\/p>\n<p>In most of your work building and interacting with APIs, you\u2019ll likely be using self-contained JWT access tokens. These are what I\u2019m primarily referring to in this chapter whenever I mention bearer tokens or bearer authentication.<br \/>\n\u5728\u6784\u5efa API \u548c\u4e0e API \u4ea4\u4e92\u7684\u5927\u90e8\u5206\u5de5\u4f5c\u4e2d\uff0c\u60a8\u53ef\u80fd\u4f1a\u4f7f\u7528\u81ea\u5305\u542b\u7684 JWT \u8bbf\u95ee\u4ee4\u724c\u3002\u8fd9\u4e9b\u662f\u6211\u5728\u672c\u7ae0\u4e2d\u63d0\u5230 bearer tokens \u6216 bearer authentication \u65f6\u4e3b\u8981\u5f15\u7528\u7684\u5185\u5bb9\u3002<\/p>\n<\/blockquote>\n<p>Now you know what a token is, as well as how they\u2019re issued by identity providers using the OpenID Connect and OAuth 2.0 protocols. Before we get to some code in section 25.3, we\u2019ll see what a typical authentication flow looks like for an ASP.NET Core API app using JWT bearer tokens for authentication.<br \/>\n\u73b0\u5728\uff0c\u60a8\u77e5\u9053\u4ec0\u4e48\u662f\u4ee4\u724c\uff0c\u4ee5\u53ca\u8eab\u4efd\u63d0\u4f9b\u5546\u5982\u4f55\u4f7f\u7528 OpenID Connect \u548c OAuth 2.0 \u534f\u8bae\u9881\u53d1\u4ee4\u724c\u3002\u5728\u6211\u4eec\u8fdb\u5165\u7b2c 25.3 \u8282\u4e2d\u7684\u4e00\u4e9b\u4ee3\u7801\u4e4b\u524d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u4f7f\u7528 JWT \u4e0d\u8bb0\u540d\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u7684 ASP.NET Core API \u5e94\u7528\u7a0b\u5e8f\u7684\u5178\u578b\u8eab\u4efd\u9a8c\u8bc1\u6d41\u7a0b\u662f\u4ec0\u4e48\u6837\u7684\u3002<\/p>\n<p>At a high level, authenticating using bearer tokens is identical to authenticating using cookies for a traditional app that has already authenticated, which you saw in figure 25.1. The request to the API contains the bearer token in a header. Any middleware before the authentication middleware sees the request as unauthenticated, exactly the same as for cookie authentication, as shown in figure 25.8.<br \/>\n\u5728\u9ad8\u7ea7\u522b\u4e0a\uff0c\u4f7f\u7528 bearer tokens \u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u4e0e\u4f7f\u7528 cookie \u5bf9\u5df2\u7ecf\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u7684\u4f20\u7edf\u5e94\u7528\u7a0b\u5e8f\u76f8\u540c\uff0c\u5982\u56fe 25.1 \u6240\u793a\u3002\u5bf9 API \u7684\u8bf7\u6c42\u5728\u6807\u5934\u4e2d\u5305\u542b\u4e0d\u8bb0\u540d\u4ee4\u724c\u3002\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4e4b\u524d\u7684\u4efb\u4f55\u4e2d\u95f4\u4ef6\u90fd\u5c06\u8bf7\u6c42\u89c6\u4e3a\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\uff0c\u8fd9\u4e0e cookie \u8eab\u4efd\u9a8c\u8bc1\u5b8c\u5168\u76f8\u540c\uff0c\u5982\u56fe 25.8 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2508.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.8 When an API request contains a bearer token, the token is validated and deserialized by the authentication middleware. The middleware creates a ClaimsPrincipal from the token, optionally transforming it with additional claims, and sets the HttpContext.User property. Subsequent middleware sees the request as authenticated.<br \/>\n\u56fe 25.8 \u5f53 API \u8bf7\u6c42\u5305\u542b\u4e0d\u8bb0\u540d\u4ee4\u724c\u65f6\uff0c\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4f1a\u9a8c\u8bc1\u548c\u53cd\u5e8f\u5217\u5316\u8be5\u4ee4\u724c\u3002\u4e2d\u95f4\u4ef6\u4ece\u4ee4\u724c\u521b\u5efa ClaimsPrincipal\uff0c\u53ef\u4ee5\u9009\u62e9\u4f7f\u7528\u5176\u4ed6\u58f0\u660e\u5bf9\u5176\u8fdb\u884c\u8f6c\u6362\uff0c\u5e76\u8bbe\u7f6e HttpContext.User \u5c5e\u6027\u3002\u540e\u7eed\u4e2d\u95f4\u4ef6\u5c06\u8bf7\u6c42\u89c6\u4e3a\u5df2\u9a8c\u8bc1\u3002<\/p>\n<p>Things are a bit different in the AuthenticationMiddleware. Instead of deserializing a cookie containing the ClaimsPrincipal, the middleware decodes the JWT token in the Authorization header. It validates the signature using the signing keys from the identity provider, and verifies that the audience has the expected value and that the token has not expired.<br \/>\nAuthenticationMiddleware \u4e2d\u7684\u60c5\u51b5\u7565\u6709\u4e0d\u540c\u3002\u4e2d\u95f4\u4ef6\u4e0d\u662f\u53cd\u5e8f\u5217\u5316\u5305\u542b ClaimsPrincipal \u7684 Cookie\uff0c\u800c\u662f\u89e3\u7801 Authorization \u6807\u5934\u4e2d\u7684 JWT \u4ee4\u724c\u3002\u5b83\u4f7f\u7528\u6765\u81ea\u8eab\u4efd\u63d0\u4f9b\u5546\u7684\u7b7e\u540d\u5bc6\u94a5\u9a8c\u8bc1\u7b7e\u540d\uff0c\u5e76\u9a8c\u8bc1\u53d7\u4f17\u662f\u5426\u5177\u6709\u9884\u671f\u503c\u4ee5\u53ca\u4ee4\u724c\u662f\u5426\u672a\u8fc7\u671f\u3002<\/p>\n<p>If the token is valid, the authentication middleware creates a ClaimsPrincipal representing the authenticated request and sets it on HttpContext.User. All middleware after the authentication middleware sees the request as authenticated.<br \/>\n\u5982\u679c\u4ee4\u724c\u6709\u6548\uff0c\u5219\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u5c06\u521b\u5efa\u4e00\u4e2a ClaimsPrincipal\uff0c\u8868\u793a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u8bf7\u6c42\uff0c\u5e76\u5728 HttpContext.User \u4e0a\u8bbe\u7f6e\u5b83\u3002\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4e4b\u540e\u7684\u6240\u6709\u4e2d\u95f4\u4ef6\u90fd\u5c06\u8bf7\u6c42\u89c6\u4e3a\u5df2\u9a8c\u8bc1\u3002<\/p>\n<p><b>TIP<\/b> If the claims in the token don\u2019t match the key values you\u2019re expecting, you can use claims transformation to remap claims. This applies to cookie authentication too, but it\u2019s particularly common when you\u2019re receiving tokens from third-party identity providers, where you don\u2019t control the names of claims. You can also use this approach to add extra claims for a user, which weren\u2019t in the original token. To learn more about claims transformation, see <a href=\"http:\/\/mng.bz\/gBJV\">http:\/\/mng.bz\/gBJV<\/a>.<br \/>\n\u63d0\u793a:\u5982\u679c\u4ee4\u724c\u4e2d\u7684\u58f0\u660e\u4e0e\u9884\u671f\u7684\u952e\u503c\u4e0d\u5339\u914d\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528\u58f0\u660e\u8f6c\u6362\u6765\u91cd\u65b0\u6620\u5c04\u58f0\u660e\u3002\u8fd9\u4e5f\u9002\u7528\u4e8e Cookie \u8eab\u4efd\u9a8c\u8bc1\uff0c\u4f46\u5f53\u60a8\u4ece\u7b2c\u4e09\u65b9\u8eab\u4efd\u63d0\u4f9b\u5546\u63a5\u6536\u4ee4\u724c\u65f6\uff0c\u8fd9\u79cd\u60c5\u51b5\u5c24\u5176\u5e38\u89c1\uff0c\u56e0\u4e3a\u60a8\u65e0\u6cd5\u63a7\u5236\u58f0\u660e\u7684\u540d\u79f0\u3002\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528\u6b64\u65b9\u6cd5\u4e3a\u7528\u6237\u6dfb\u52a0\u539f\u59cb\u4ee4\u724c\u4e2d\u6ca1\u6709\u7684\u989d\u5916\u58f0\u660e\u3002\u8981\u4e86\u89e3\u6709\u5173\u58f0\u660e\u8f6c\u6362\u7684\u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 <a href=\"http:\/\/mng.bz\/gBJV\">http:\/\/mng.bz\/gBJV<\/a>\u3002<\/p>\n<p>We\u2019ve covered a lot of theory about JWT tokens in this chapter, so you\u2019ll be pleased to hear it\u2019s time to look at some code!<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u4eec\u5df2\u7ecf\u4ecb\u7ecd\u4e86\u8bb8\u591a\u5173\u4e8e JWT \u4ee4\u724c\u7684\u7406\u8bba\uff0c\u56e0\u6b64\u60a8\u4f1a\u5f88\u9ad8\u5174\u542c\u5230\u662f\u65f6\u5019\u67e5\u770b\u4e00\u4e9b\u4ee3\u7801\u4e86\uff01<\/p>\n<h2>25.3 Adding JWT bearer authentication to minimal APIs<\/h2>\n<p>25.3 \u5c06 JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u6dfb\u52a0\u5230\u6700\u5c0f API<\/p>\n<p>In this section you\u2019ll learn how to add JWT bearer token authentication to an ASP.NET Core app. I use the minimal API Recipe API application we started in chapter 12 in this chapter, but the process is identical if you\u2019re building an API application using web API controllers.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5c06 JWT \u4e0d\u8bb0\u540d\u4ee4\u724c\u8eab\u4efd\u9a8c\u8bc1\u6dfb\u52a0\u5230 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u3002\u6211\u4f7f\u7528\u6211\u4eec\u5728\u672c\u7ae0\u7b2c 12 \u7ae0\u4e2d\u5f00\u59cb\u7684\u6700\u5c0f API Recipe API \u5e94\u7528\u7a0b\u5e8f\uff0c\u4f46\u5982\u679c\u60a8\u4f7f\u7528 Web API \u63a7\u5236\u5668\u6784\u5efa API \u5e94\u7528\u7a0b\u5e8f\uff0c\u5219\u8fc7\u7a0b\u662f\u76f8\u540c\u7684\u3002<\/p>\n<p>.NET 7 significantly simplified the number of steps you need to get started with JWT authentication by adding some conventions, which we\u2019ll discuss shortly. To add JWT to an existing API application, first install the Microsoft.AspNetCore.Authentication.JwtBearer NuGet package using the .NET CLI<br \/>\n.NET 7 \u901a\u8fc7\u6dfb\u52a0\u4e00\u4e9b\u7ea6\u5b9a\uff0c\u5927\u5927\u7b80\u5316\u4e86\u5f00\u59cb\u4f7f\u7528 JWT \u8eab\u4efd\u9a8c\u8bc1\u6240\u9700\u7684\u6b65\u9aa4\u6570\uff0c\u6211\u4eec\u7a0d\u540e\u5c06\u5bf9\u6b64\u8fdb\u884c\u8ba8\u8bba\u3002\u8981\u5c06 JWT \u6dfb\u52a0\u5230\u73b0\u6709 API \u5e94\u7528\u7a0b\u5e8f\uff0c\u8bf7\u9996\u5148\u4f7f\u7528 .NET CLI \u5b89\u88c5 Microsoft.AspNetCore.Authentication.JwtBearer NuGet \u5305<\/p>\n<pre><code>dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer<\/code><\/pre>\n<p>or by adding the <PackageReference> to your project directly:<br \/>\n\u6216\u8005\u76f4\u63a5\u5c06 \u6dfb\u52a0\u5230\u60a8\u7684\u9879\u76ee\u4e2d\uff1a<\/p>\n<pre><code>&lt;PackageReference Include=&quot;Microsoft.AspNetCore.Authentication.JwtBearer&quot;\n    Version=&quot;7.0.0&quot; \/&gt;<\/code><\/pre>\n<p>Next, add the required services to configure JWT authentication for your application, as shown in listing 25.1. As you may remember, the authentication and authorization middleware are automatically added to your middleware pipeline by WebApplication, but if you want to control the position of the middleware, you can override the location, as I do here.<br \/>\n\u63a5\u4e0b\u6765\uff0c\u6dfb\u52a0\u6240\u9700\u7684\u670d\u52a1\u6765\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e JWT \u8eab\u4efd\u9a8c\u8bc1\uff0c\u5982\u6e05\u5355 25.1 \u6240\u793a\u3002\u60a8\u53ef\u80fd\u8fd8\u8bb0\u5f97\uff0c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u4e2d\u95f4\u4ef6\u7531 WebApplication \u81ea\u52a8\u6dfb\u52a0\u5230\u60a8\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\uff0c\u4f46\u5982\u679c\u60a8\u60f3\u63a7\u5236\u4e2d\u95f4\u4ef6\u7684\u4f4d\u7f6e\uff0c\u60a8\u53ef\u4ee5\u8986\u76d6\u8be5\u4f4d\u7f6e\uff0c\u5c31\u50cf\u6211\u5728\u8fd9\u91cc\u6240\u505a\u7684\u90a3\u6837\u3002<\/p>\n<p>Listing 25.1 Adding JWT bearer authentication to a minimal API application<br \/>\n\u793a\u4f8b 25.1 \u5411\u6700\u5c0f API \u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0 JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddAuthentication() \u2776\n.AddJwtBearer(); \u2777\nbuilder.Services.AddAuthorization(); \u2778\nbuilder.Services.AddScoped&lt;RecipeService&gt;();\nWebApplication app = builder.Build();\napp.UseAuthentication(); \u2779\napp.UseAuthorization(); \u277a\napp.MapGet(&quot;\/recipe&quot;, async (RecipeService service) =&gt;\n{\nreturn await service.GetRecipes();\n}).RequireAuthorization(); \u277b\napp.Run();<\/code><\/pre>\n<p>\u2776 Adds the core authentication services<br \/>\n\u6dfb\u52a0\u6838\u5fc3\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1<\/p>\n<p>\u2777 Adds and configures JWT authentication<br \/>\n\u6dfb\u52a0\u548c\u914d\u7f6e JWT \u8eab\u4efd\u9a8c\u8bc1<\/p>\n<p>\u2778 Adds the core authorization services<br \/>\n\u6dfb\u52a0\u6838\u5fc3\u6388\u6743\u670d\u52a1<\/p>\n<p>\u2779 Adds the authentication middleware<br \/>\n\u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6<\/p>\n<p>\u277a Adds the authorization middleware<br \/>\n\u6dfb\u52a0\u6388\u6743\u4e2d\u95f4\u4ef6<\/p>\n<p>\u277b Adds an authorization policy to the minimal API endpoint<br \/>\n\u5c06\u6388\u6743\u7b56\u7565\u6dfb\u52a0\u5230\u6700\u5c0f API \u7aef\u70b9<\/p>\n<p>As well as configuring the JWT authentication, listing 25.1 adds an authorization policy to the one minimal API endpoint shown in the app. The RequireAuthorization() function adds a simple \u201cIs authenticated\u201d authorization policy to the endpoint. This is exactly analgous to when you add an [Authorize] attribute to MVC or Web API controllers. Any requests for this endpoint must be authenticated; otherwise, the request is rejected by the authorization middleware with a 401 Unauthorized reponse, as shown in figure 25.9.<br \/>\n\u9664\u4e86\u914d\u7f6e JWT \u8eab\u4efd\u9a8c\u8bc1\u4e4b\u5916\uff0c\u6e05\u5355 25.1 \u8fd8\u5411\u5e94\u7528\u7a0b\u5e8f\u4e2d\u663e\u793a\u7684\u4e00\u4e2a\u6700\u5c0f API \u7aef\u70b9\u6dfb\u52a0\u4e86\u4e00\u4e2a\u6388\u6743\u7b56\u7565\u3002RequireAuthorization\uff08\uff09 \u51fd\u6570\u5411\u7ec8\u7aef\u8282\u70b9\u6dfb\u52a0\u4e00\u4e2a\u7b80\u5355\u7684 \u201cIs authenticated\u201d \u6388\u6743\u7b56\u7565\u3002\u8fd9\u4e0e\u5411 MVC \u6216 Web API \u63a7\u5236\u5668\u6dfb\u52a0 [Authorize] \u5c5e\u6027\u65f6\u5b8c\u5168\u76f8\u540c\u3002\u5bf9\u6b64\u7ec8\u7aef\u8282\u70b9\u7684\u4efb\u4f55\u8bf7\u6c42\u90fd\u5fc5\u987b\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1;\u5426\u5219\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u4f1a\u62d2\u7edd\u8be5\u8bf7\u6c42\uff0c\u5e76\u7ed9\u51fa 401 Unauthorized \u54cd\u5e94\uff0c\u5982\u56fe 25.9 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2509.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.9 If you send a request to an API protected with JWT bearer authentication and don\u2019t include a token, you\u2019ll receive a 401 Unauthorized challenge response.<br \/>\n\u56fe 25.9 \u5982\u679c\u60a8\u5411\u53d7 JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u4fdd\u62a4\u7684 API \u53d1\u9001\u8bf7\u6c42\uff0c\u5e76\u4e14\u4e0d\u5305\u542b\u4ee4\u724c\uff0c\u60a8\u5c06\u6536\u5230 401 Unauthorized \u8d28\u8be2\u54cd\u5e94\u3002<\/p>\n<blockquote>\n<p>Authentication schemes: Choosing between cookies and bearer tokens<br \/>\n\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\uff1a\u5728 Cookie \u548c Bearer Tokens\u4e4b\u95f4\u8fdb\u884c\u9009\u62e9 <\/p>\n<p>One question you may have while reading about bearer authentication is how the authentication middleware knows whether to look for the cookie or a header. The answer is authentication schemes.<br \/>\n\u5728\u9605\u8bfb\u6709\u5173Bearer Authentication\u7684\u6587\u7ae0\u65f6\uff0c\u60a8\u53ef\u80fd\u4f1a\u9047\u5230\u4e00\u4e2a\u95ee\u9898\uff0c\u5373\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u5982\u4f55\u77e5\u9053\u662f\u67e5\u627e Cookie \u8fd8\u662f\u6807\u5934\u3002\u7b54\u6848\u662f\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u3002<\/p>\n<p>An authentication scheme in ASP.NET Core has an ID and an associated authentication handler that controls how the user is authenticated, as well as how authentication and authorization failures should be handled.<br \/>\nASP.NET Core \u4e2d\u7684\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u5177\u6709\u4e00\u4e2a ID \u548c\u4e00\u4e2a\u5173\u8054\u7684\u8eab\u4efd\u9a8c\u8bc1\u5904\u7406\u7a0b\u5e8f\uff0c\u7528\u4e8e\u63a7\u5236\u5982\u4f55\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4ee5\u53ca\u5e94\u5982\u4f55\u5904\u7406\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u5931\u8d25\u3002<\/p>\n<p>For example, in chapter 23 the cookie authentication scheme was used implicitly by ASP.NET Core Identity. The cookie authentication handler in this case authenticates users by looking for a cookie and redirects users to the login or \u201caccess denied\u201d pages for authentication or authorization failures.<br \/>\n\u4f8b\u5982\uff0c\u5728\u7b2c 23 \u7ae0\u4e2d\uff0cASP.NET Core Identity \u9690\u5f0f\u4f7f\u7528\u4e86 cookie \u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0cCookie \u8eab\u4efd\u9a8c\u8bc1\u5904\u7406\u7a0b\u5e8f\u901a\u8fc7\u67e5\u627e Cookie \u6765\u9a8c\u8bc1\u7528\u6237\uff0c\u5e76\u5c06\u7528\u6237\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u6216\u201c\u62d2\u7edd\u8bbf\u95ee\u201d\u9875\uff0c\u4ee5\u67e5\u627e\u9a8c\u8bc1\u6216\u6388\u6743\u5931\u8d25\u3002<\/p>\n<p>In listing 25.1 you registered the JWT Bearer authentication scheme. The JWT bearer authentication handler reads tokens from the Authorization header and returns 401 and 403 responses for authentication or authorization failures.<br \/>\n\u5728\u5217\u8868 25.1 \u4e2d\uff0c\u60a8\u6ce8\u518c\u4e86 JWT Bearer \u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u3002JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u5904\u7406\u7a0b\u5e8f\u4ece Authorization \u6807\u5934\u4e2d\u8bfb\u53d6\u4ee4\u724c\uff0c\u5e76\u8fd4\u56de 401 \u548c 403 \u8eab\u4efd\u9a8c\u8bc1\u6216\u6388\u6743\u5931\u8d25\u7684\u54cd\u5e94\u3002<\/p>\n<p>When you register only a single authentication scheme, such as in listing 25.1, ASP.NET Core automatically sets that as the default, but it\u2019s possible to register multiple authentication schemes. This is particularly common if you are using OpenID Connect with a traditional web app, for example. In these cases you can choose which scheme is used for authentication events or authentication failures and how the schemes should interact.<br \/>\n\u5f53\u60a8\u4ec5\u6ce8\u518c\u5355\u4e2a\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u65f6\uff0c\u4f8b\u5982\u6e05\u5355 25.1 \u4e2d\uff0cASP.NET Core \u4f1a\u81ea\u52a8\u5c06\u5176\u8bbe\u7f6e\u4e3a\u9ed8\u8ba4\u503c\uff0c\u4f46\u53ef\u4ee5\u6ce8\u518c\u591a\u4e2a\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u3002\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u5c06 OpenID Connect \u4e0e\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4e00\u8d77\u4f7f\u7528\uff0c\u8fd9\u79cd\u60c5\u51b5\u5c24\u5176\u5e38\u89c1\u3002\u5728\u8fd9\u4e9b\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u4ee5\u9009\u62e9\u5c06\u54ea\u4e2a\u65b9\u6848\u7528\u4e8e\u8eab\u4efd\u9a8c\u8bc1\u4e8b\u4ef6\u6216\u8eab\u4efd\u9a8c\u8bc1\u5931\u8d25\uff0c\u4ee5\u53ca\u8fd9\u4e9b\u65b9\u6848\u5e94\u5982\u4f55\u4ea4\u4e92\u3002<\/p>\n<p>Using multiple authentication schemes can be confusing, so it\u2019s important to follow the documentation closely when configuring authentication for your app. You can read more about authentication schemes at <a href=\"http:\/\/mng.bz\/5w1a\">http:\/\/mng.bz\/5w1a<\/a>. If you need only a single scheme, you shouldn\u2019t have any problems, but otherwise, here be dragons!<br \/>\n\u4f7f\u7528\u591a\u4e2a\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u53ef\u80fd\u4f1a\u9020\u6210\u6df7\u6dc6\uff0c\u56e0\u6b64\u5728\u4e3a\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u8eab\u4efd\u9a8c\u8bc1\u65f6\uff0c\u8bf7\u52a1\u5fc5\u4e25\u683c\u9075\u5faa\u6587\u6863\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"http:\/\/mng.bz\/5w1a\">http:\/\/mng.bz\/5w1a<\/a> \u4e0a\u9605\u8bfb\u6709\u5173\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u7684\u66f4\u591a\u4fe1\u606f\u3002\u5982\u679c\u4f60\u53ea\u9700\u8981\u4e00\u4e2a\u65b9\u6848\uff0c\u4f60\u5e94\u8be5\u4e0d\u4f1a\u6709\u4efb\u4f55\u95ee\u9898\uff0c\u4f46\u9664\u6b64\u4e4b\u5916\uff0c\u8fd9\u91cc\u6709\u9f99\uff01<\/p>\n<\/blockquote>\n<p>Great! The 401 response in figure 25.9 verifies that the app is behaving correctly for unauthenticated requests. The obvious next step is to send a request to your API that includes a valid JWT bearer token. Unfortunately, this is where things traditionally get tricky. How do you generate a valid JWT? Luckily, in .NET 7, the .NET CLI comes with a tool to make creating test tokens easy.<br \/>\n\u4f1f\u5927\uff01\u56fe 25.9 \u4e2d\u7684 401 \u54cd\u5e94\u9a8c\u8bc1\u4e86\u5e94\u7528\u7a0b\u5e8f\u662f\u5426\u5bf9\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u8bf7\u6c42\u884c\u4e3a\u6b63\u786e\u3002\u663e\u800c\u6613\u89c1\u7684\u4e0b\u4e00\u6b65\u662f\u5411 API \u53d1\u9001\u5305\u542b\u6709\u6548 JWT \u4e0d\u8bb0\u540d\u4ee4\u724c\u7684\u8bf7\u6c42\u3002\u4e0d\u5e78\u7684\u662f\uff0c\u8fd9\u662f\u4f20\u7edf\u4e0a\u4e8b\u60c5\u53d8\u5f97\u68d8\u624b\u7684\u5730\u65b9\u3002\u5982\u4f55\u751f\u6210\u6709\u6548\u7684 JWT\uff1f\u5e78\u8fd0\u7684\u662f\uff0c\u5728 .NET 7 \u4e2d\uff0c.NET CLI \u9644\u5e26\u4e86\u4e00\u4e2a\u5de5\u5177\uff0c\u53ef\u4ee5\u8f7b\u677e\u521b\u5efa\u6d4b\u8bd5\u4ee4\u724c\u3002<\/p>\n<h2>25.4 Using the user-jwts tool for local JWT testing<\/h2>\n<p>25.4 \u4f7f\u7528 user-jwts \u5de5\u5177\u8fdb\u884c\u672c\u5730 JWT \u6d4b\u8bd5<\/p>\n<p>In section 25.3 you added JWT authentication to your application and protected your API with a basic authorization policy. The problem is that you can\u2019t test your API unless you can generate JWT tokens. In production you\u2019ll likely have an identity provider such as Auth0, Azure Active Directory, or IdentityServer to generate tokens for you using OpenID Connect. But that can make for cumbersome local testing. In this section you\u2019ll learn how to use the .NET CLI to generate JWTs for local testing.<br \/>\n\u5728\u7b2c 25.3 \u8282\u4e2d\uff0c\u60a8\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u4e86 JWT \u8eab\u4efd\u9a8c\u8bc1\uff0c\u5e76\u4f7f\u7528\u57fa\u672c\u6388\u6743\u7b56\u7565\u4fdd\u62a4\u60a8\u7684 API\u3002\u95ee\u9898\u662f\uff0c\u9664\u975e\u53ef\u4ee5\u751f\u6210 JWT \u4ee4\u724c\uff0c\u5426\u5219\u65e0\u6cd5\u6d4b\u8bd5 API\u3002\u5728\u751f\u4ea7\u73af\u5883\u4e2d\uff0c\u60a8\u53ef\u80fd\u4f1a\u6709\u4e00\u4e2a\u8eab\u4efd\u63d0\u4f9b\u5546\uff08\u5982 Auth0\u3001Azure Active Directory \u6216 IdentityServer\uff09\u6765\u4f7f\u7528 OpenID Connect \u4e3a\u60a8\u751f\u6210\u4ee4\u724c\u3002\u4f46\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u672c\u5730\u6d4b\u8bd5\u53d8\u5f97\u7e41\u7410\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528 .NET CLI \u751f\u6210\u7528\u4e8e\u672c\u5730\u6d4b\u8bd5\u7684 JWT\u3002<\/p>\n<p>In .NET 7, the .NET CLI includes a tool called user-jwts that you can use to generate tokens. This tool acts as a mini identity provider, meaning that you can generate tokens with any claims you may need, and your API can verify them using signing key material generated by the tool.<br \/>\n\u5728 .NET 7 \u4e2d\uff0c.NET CLI \u5305\u62ec\u4e00\u4e2a\u540d\u4e3a user-jwts \u7684\u5de5\u5177\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u751f\u6210\u4ee4\u724c\u3002\u6b64\u5de5\u5177\u5145\u5f53\u5fae\u578b\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u8fd9\u610f\u5473\u7740\u60a8\u53ef\u4ee5\u4f7f\u7528\u53ef\u80fd\u9700\u8981\u7684\u4efb\u4f55\u58f0\u660e\u751f\u6210\u4ee4\u724c\uff0c\u5e76\u4e14\u60a8\u7684 API \u53ef\u4ee5\u4f7f\u7528\u8be5\u5de5\u5177\u751f\u6210\u7684\u7b7e\u540d\u5bc6\u94a5\u6750\u6599\u5bf9\u5176\u8fdb\u884c\u9a8c\u8bc1\u3002<\/p>\n<p><b>TIP<\/b> The user-jwts tool is built into the software development kit (SDK), so there\u2019s nothing extra to install. You need to enable User Secrets for your project, but user-jwts will do this for you if you haven\u2019t already. The user-jwts tool uses User Secrets to store the signing key material used to generate the JWTs, which your app uses to validate the JWT signatures.<br \/>\n\u63d0\u793a: user-jwts \u5de5\u5177\u5185\u7f6e\u4e8e\u8f6f\u4ef6\u5f00\u53d1\u5de5\u5177\u5305 \uff08SDK\uff09 \u4e2d\uff0c\u56e0\u6b64\u65e0\u9700\u5b89\u88c5\u4efb\u4f55\u989d\u5916\u5185\u5bb9\u3002\u60a8\u9700\u8981\u4e3a\u9879\u76ee\u542f\u7528 User Secrets\uff0c\u4f46\u5982\u679c\u60a8\u5c1a\u672a\u542f\u7528 user-jwts\uff0c\u5219 user-jwts \u5c06\u4e3a\u60a8\u6267\u884c\u6b64\u4f5c\u3002user-jwts \u5de5\u5177\u4f7f\u7528\u7528\u6237\u5bc6\u94a5\u6765\u5b58\u50a8\u7528\u4e8e\u751f\u6210 JWT \u7684\u7b7e\u540d\u5bc6\u94a5\u6750\u6599\uff0c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u4f7f\u7528\u8be5\u6750\u6599\u6765\u9a8c\u8bc1 JWT \u7b7e\u540d\u3002<\/p>\n<p>Let\u2019s look at how to create a JWT with the user-jwts tool and use that to send a request to our application.<br \/>\n\u8ba9\u6211\u4eec\u770b\u770b\u5982\u4f55\u4f7f\u7528 user-jwts \u5de5\u5177\u521b\u5efa JWT\uff0c\u5e76\u4f7f\u7528\u5b83\u5411\u6211\u4eec\u7684\u5e94\u7528\u7a0b\u5e8f\u53d1\u9001\u8bf7\u6c42\u3002<\/p>\n<h3>25.4.1 Creating JWTs with the user-jwts tool<\/h3>\n<p>25.4.1 \u4f7f\u7528 user-jwts \u5de5\u5177\u521b\u5efa JWT<\/p>\n<p>To create a JWT that you can use in requests to your API, run the following with the user-jwts tool from inside your project folder:<br \/>\n\u8981\u521b\u5efa\u53ef\u5728 API \u8bf7\u6c42\u4e2d\u4f7f\u7528\u7684 JWT\uff0c\u8bf7\u4f7f\u7528 user-jwts \u5de5\u5177\u4ece\u9879\u76ee\u6587\u4ef6\u5939\u5185\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a<\/p>\n<pre><code>dotnet user-jwts create<\/code><\/pre>\n<p>This command does several things:<br \/>\n\u6b64\u547d\u4ee4\u6267\u884c\u4ee5\u4e0b\u51e0\u9879\u4f5c\uff1a<\/p>\n<p>\u2022  Enables User Secrets in the project if they\u2019re not already configured, as though you had manually run dotnet user-secrets init.<br \/>\n\u5982\u679c\u5c1a\u672a\u914d\u7f6e\u7528\u6237\u5bc6\u94a5\uff0c\u8bf7\u5728\u9879\u76ee\u4e2d\u542f\u7528\u7528\u6237\u5bc6\u94a5\uff0c\u5c31\u50cf\u60a8\u624b\u52a8\u8fd0\u884c dotnet user-secrets init \u4e00\u6837\u3002<\/p>\n<p>\u2022  Adds the signing key material to User Secrets, which you can view by running dotnet user-secrets list as described in chapter 10, which prints out the key material configuration, as in this example:<br \/>\n\u5c06\u7b7e\u540d\u5bc6\u94a5\u6750\u6599\u6dfb\u52a0\u5230\u7528\u6237\u5bc6\u94a5\u4e2d\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u8fd0\u884c dotnet user-secrets list \u6765\u67e5\u770b\uff0c\u5982\u7b2c 10 \u7ae0\u6240\u8ff0\uff0c\u8be5\u5217\u8868\u5c06\u6253\u5370\u51fa\u5bc6\u94a5\u6750\u6599\u914d\u7f6e\uff0c\u5982\u4e0b\u4f8b\u6240\u793a\uff1a<\/p>\n<pre><code>Authentication:Schemes:Bearer:SigningKeys:0:Value =\n    rIhUzB3DIbtbUwiIxkgoKfFDkLpY+gIJOB4eaQzczq8=\nAuthentication:Schemes:Bearer:SigningKeys:0:Length = 32\nAuthentication:Schemes:Bearer:SigningKeys:0:Issuer = dotnet-user-jwts\nAuthentication:Schemes:Bearer:SigningKeys:0:Id = c99a872d<\/code><\/pre>\n<p>\u2022  Configures the JWT authentication services to support tokens generated by the user-jwts tool by adding configuration to appsettings.Development.json, as follows:<br \/>\n\u901a\u8fc7\u5411 appsettings \u6dfb\u52a0\u914d\u7f6e\uff0c\u914d\u7f6e JWT \u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u4ee5\u652f\u6301 user-jwts \u5de5\u5177\u751f\u6210\u7684\u4ee4\u724c\u3002Development.json\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n<pre><code>{\n  &quot;Authentication&quot;: {\n    &quot;Schemes&quot;: {\n      &quot;Bearer&quot;: {\n        &quot;ValidAudiences&quot;: [\n          &quot;http:\/\/localhost:5073&quot;,\n          &quot;https:\/\/localhost:7112&quot;\n        ],\n        &quot;ValidIssuer&quot;: &quot;dotnet-user-jwts&quot;\n      }\n    }\n  }\n}<\/code><\/pre>\n<p>The user-jwts tool automatically configures the valid audiences based on the profiles in your launchSettings.json file. All the applicationUrls listed in launchSettings.json are listed as valid audiences, so it doesn\u2019t matter which profile you use to run your app; the generated token should be valid. The JWT bearer authentication service automatically reads this configuration and configures itself to support user-jwts JWTs.<br \/>\nuser-jwts \u5de5\u5177\u4f1a\u6839\u636e launchSettings.json \u6587\u4ef6\u4e2d\u7684\u7528\u6237\u6863\u6848\u81ea\u52a8\u914d\u7f6e\u6709\u6548\u53d7\u4f17\u3002launchSettings.json\u4e2d\u5217\u51fa\u7684\u6240\u6709 applicationUrls \u90fd\u5217\u4e3a\u6709\u6548\u53d7\u4f17\uff0c\u56e0\u6b64\u4f7f\u7528\u54ea\u4e2a\u914d\u7f6e\u6587\u4ef6\u6765\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u5e76\u4e0d\u91cd\u8981;\u751f\u6210\u7684 Token \u5e94\u8be5\u662f\u6709\u6548\u7684\u3002JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u4f1a\u81ea\u52a8\u8bfb\u53d6\u6b64\u914d\u7f6e\uff0c\u5e76\u5c06\u81ea\u8eab\u914d\u7f6e\u4e3a\u652f\u6301 user-jwts JWT\u3002<\/p>\n<p>\u2022  Creates a JWT. By default, the token is created with a sub and unique_claim set to your operating system\u2019s username, with aud claims for each of the applicationUrls in your launchSettings.json and an issuer of dotnet-user-jwts. You\u2019ll notice that these match the values added to your APIs configuration file.<br \/>\nAfter calling dotnet user-jwts create, the JWT token is printed to the console, along with the sub name used and the ID of the token. I\u2019ve truncated the tokens throughout this chapter for brevity:<br \/>\n\u521b\u5efa JWT\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u4ee4\u724c\u662f\u4f7f\u7528 sub \u521b\u5efa\u7684\uff0cunique_claim\u8bbe\u7f6e\u4e3a\u4f5c\u7cfb\u7edf\u7684\u7528\u6237\u540d\uff0claunchSettings.json\u4e2d\u7684\u6bcf\u4e2a applicationUrls \u90fd\u6709 aud \u58f0\u660e\uff0c\u5e76\u4e14\u9881\u53d1\u8005\u662f dotnet-user-jwts\u3002\u60a8\u4f1a\u6ce8\u610f\u5230\uff0c\u8fd9\u4e9b\u503c\u4e0e\u6dfb\u52a0\u5230 API \u914d\u7f6e\u6587\u4ef6\u7684\u503c\u5339\u914d\u3002<br \/>\n\u8c03\u7528 dotnet user-jwts create \u540e\uff0cJWT \u4ee4\u724c\u4ee5\u53ca\u4f7f\u7528\u7684\u5b50\u540d\u79f0\u548c\u4ee4\u724c\u7684 ID \u5c06\u6253\u5370\u5230\u63a7\u5236\u53f0\u3002\u4e3a\u7b80\u6d01\u8d77\u89c1\uff0c\u6211\u5728\u672c\u7ae0\u4e2d\u622a\u65ad\u4e86\u6807\u8bb0\uff1a<\/p>\n<pre><code>New JWT saved with ID &#039;f2080e51&#039;.\nName: andrewlock\n\nToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFuZHJl\u2026<\/code><\/pre>\n<p><b>TIP<\/b> You can visualize exactly what\u2019s in the token by copy and pasting it into <a href=\"https:\/\/jwt.io\">https:\/\/jwt.io<\/a>, as I showed in figure 25.7.<br \/>\n\u63d0\u793a:\u60a8\u53ef\u4ee5\u901a\u8fc7\u5c06\u4ee4\u724c\u590d\u5236\u5e76\u7c98\u8d34\u5230 <a href=\"https:\/\/jwt.io\">https:\/\/jwt.io<\/a> \u4e2d\u6765\u51c6\u786e\u53ef\u89c6\u5316\u4ee4\u724c\u4e2d\u7684\u5185\u5bb9\uff0c\u5982\u56fe 25.7 \u6240\u793a\u3002<\/p>\n<p>Now that you have a token, it\u2019s time to test it. To use the token, you need to add an Authorization header to requests using the following format (where <code>&lt;token&gt;<\/code> is the full token printed by user-jwts):<br \/>\n\u73b0\u5728\u60a8\u6709\u4e86\u4e00\u4e2a\u4ee4\u724c\uff0c\u662f\u65f6\u5019\u6d4b\u8bd5\u5b83\u4e86\u3002\u8981\u4f7f\u7528\u8be5\u4ee4\u724c\uff0c\u60a8\u9700\u8981\u4f7f\u7528\u4ee5\u4e0b\u683c\u5f0f\u5411\u8bf7\u6c42\u6dfb\u52a0 Authorization \u6807\u5934\uff08\u5176\u4e2d<code>&lt;token&gt;<\/code>  \u662f user-jwts \u6253\u5370\u7684\u5b8c\u6574\u4ee4\u724c\uff09\uff1a<\/p>\n<pre><code>Authorization: Bearer &lt;token&gt;<\/code><\/pre>\n<p>If any part of this header is incorrect\u2014if you misspell Authorization, misspell Bearer, don\u2019t include a space between Bearer and your token, or mistype your token\u2014you\u2019ll get a 401 Unauthorized response.<br \/>\n\u5982\u679c\u6b64\u6807\u5934\u7684\u4efb\u4f55\u90e8\u5206\u4e0d\u6b63\u786e\uff08\u5982\u679c\u62fc\u5199\u9519\u8bef Authorization\u3001\u62fc\u5199\u9519\u8bef Bearer\u3001\u5728 Bearer \u548c\u4ee4\u724c\u4e4b\u95f4\u4e0d\u5305\u542b\u7a7a\u683c\u6216\u952e\u5165\u9519\u8bef\u4ee4\u724c\uff09\uff0c\u60a8\u5c06\u6536\u5230 401 Unauthorized \u54cd\u5e94\u3002<\/p>\n<p><b>TIP<\/b> If you get 401 Unauthorized responses even after adding an Authorization header to your requests, double-check your spelling, and make sure that the token is added correct with the &quot;Bearer &quot; prefix. Typos have a way of creeping in here! You can also increase the logging level in your API to see why failures are happening, as you\u2019ll learn in chapter 26.<br \/>\n\u63d0\u793a:\u5982\u679c\u5728\u5411\u8bf7\u6c42\u6dfb\u52a0 Authorization \u6807\u5934\u540e\u4ecd\u6536\u5230 401 Unauthorized \u54cd\u5e94\uff0c\u8bf7\u4ed4\u7ec6\u68c0\u67e5\u60a8\u7684\u62fc\u5199\uff0c\u5e76\u786e\u4fdd\u4f7f\u7528\u201cBearer\u201d\u524d\u7f00\u6b63\u786e\u6dfb\u52a0\u4ee4\u724c\u3002\u9519\u522b\u5b57\u603b\u6709\u529e\u6cd5\u6084\u6084\u6e9c\u8fdb\u6765\uff01\u60a8\u8fd8\u53ef\u4ee5\u63d0\u9ad8 API \u4e2d\u7684\u65e5\u5fd7\u8bb0\u5f55\u7ea7\u522b\uff0c\u4ee5\u67e5\u770b\u5931\u8d25\u53d1\u751f\u7684\u539f\u56e0\uff0c\u60a8\u5c06\u5728\u7b2c 26 \u7ae0\u4e2d\u5b66\u5230\u3002<\/p>\n<p>Once you have added the token you can call your API, which should now return successfully, as shown in figure 25.10.<br \/>\n\u6dfb\u52a0\u4ee4\u724c\u540e\uff0c\u60a8\u53ef\u4ee5\u8c03\u7528\u60a8\u7684 API\uff0c\u73b0\u5728\u5e94\u8be5\u6210\u529f\u8fd4\u56de\uff0c\u5982\u56fe 25.10 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2510.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.10 Sending a request with an Authorization Bearer using Postman. The Authorization header must have the format Bearer <code>&lt;token&gt;<\/code>. You can also configure this in the Authorization tab of Postman.<br \/>\n\u56fe 25.10 \u4f7f\u7528 Postman \u5411\u6388\u6743\u6301\u6709\u8005\u53d1\u9001\u8bf7\u6c42\u3002Authorization \u6807\u5934\u5fc5\u987b\u5177\u6709 Bearer <code>&lt;token&gt;<\/code>\u683c\u5f0f\u3002\u60a8\u8fd8\u53ef\u4ee5\u5728 Postman \u7684 Authorization \uff08\u6388\u6743\uff09 \u9009\u9879\u5361\u4e2d\u914d\u7f6e\u6b64\u9879\u3002<\/p>\n<p>The default token created by the JWT is sufficient to authenticate with your API, but depending on your requirements, you may want to customize the JWT to add or change claims. In the next section you\u2019ll learn how.<br \/>\nJWT \u521b\u5efa\u7684\u9ed8\u8ba4\u4ee4\u724c\u8db3\u4ee5\u4f7f\u7528 API \u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4f46\u6839\u636e\u60a8\u7684\u8981\u6c42\uff0c\u60a8\u53ef\u80fd\u9700\u8981\u81ea\u5b9a\u4e49 JWT \u4ee5\u6dfb\u52a0\u6216\u66f4\u6539\u58f0\u660e\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u4f5c\u3002<\/p>\n<h3>25.4.2 Customizing your JWTs<\/h3>\n<p>25.4.2 \u81ea\u5b9a\u4e49 JWT<\/p>\n<p>By default, the user-jwts tool creates a bare-bones JWT that you can use to call your app. If you need more customization, you can pass extra options to the dotnet user-jwts create command to control the JWT it generates. Some of the most useful options are<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cuser-jwts \u5de5\u5177\u4f1a\u521b\u5efa\u4e00\u4e2a\u57fa\u672c JWT\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u8c03\u7528\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u5982\u679c\u9700\u8981\u66f4\u591a\u81ea\u5b9a\u4e49\uff0c\u53ef\u4ee5\u5c06\u989d\u5916\u7684\u9009\u9879\u4f20\u9012\u7ed9 dotnet user-jwts create \u547d\u4ee4\uff0c\u4ee5\u63a7\u5236\u5b83\u751f\u6210\u7684 JWT\u3002\u4e00\u4e9b\u6700\u6709\u7528\u7684\u9009\u9879\u662f<\/p>\n<p>\u2022  --name sets the sub and unique_name claims for the JWT instead of using the operating system user as the name.<br \/>\n--name \u8bbe\u7f6e JWT \u7684 sub \u548c unique_name \u58f0\u660e\uff0c\u800c\u4e0d\u662f\u4f7f\u7528\u4f5c\u7cfb\u7edf\u7528\u6237\u4f5c\u4e3a\u540d\u79f0\u3002<\/p>\n<p>\u2022  --claim <code>&lt;key&gt;=&lt;value&gt;<\/code> adds a claim called <code>&lt;key&gt;<\/code> with value <code>&lt;value&gt;<\/code> to the JWT. Use this option multiple times to add claims.<br \/>\n--claim  <code>&lt;key&gt;=&lt;value&gt;<\/code> \u5c06\u8c03\u7528<code>&lt;key&gt;<\/code>\u7684 value  <code>&lt;value&gt;<\/code> \u58f0\u660e\u6dfb\u52a0\u5230 JWT\u3002\u591a\u6b21\u4f7f\u7528\u6b64\u9009\u9879\u53ef\u6dfb\u52a0\u58f0\u660e\u3002<\/p>\n<p>\u2022  --scope <code>&lt;value&gt;<\/code> adds a scope claim called <code>&lt;value&gt;<\/code> to the JWT. Use this option multiple times to add scopes.<br \/>\n--scope <code>&lt;value&gt;<\/code> \u6dfb\u52a0\u4e00\u4e2a<code>&lt;value&gt;<\/code>\u8c03\u7528 JWT \u7684 scope \u58f0\u660e\u3002\u591a\u6b21\u4f7f\u7528\u6b64\u9009\u9879\u53ef\u6dfb\u52a0\u8303\u56f4\u3002<\/p>\n<p>These aren\u2019t the only options; you can control essentially everything about the generated JWT. Run dotnet user-jwts create --help to see all the options available. One option that may be useful in certain automated scripts or tests is the --output option. This controls how the JWT is printed to the console after creation. The default value, default, prints a summary of the JWT and the token itself, as you saw previously:<br \/>\n\u8fd9\u4e9b\u5e76\u4e0d\u662f\u552f\u4e00\u7684\u9009\u62e9;\u60a8\u57fa\u672c\u4e0a\u53ef\u4ee5\u63a7\u5236\u6709\u5173\u751f\u6210\u7684 JWT \u7684\u6240\u6709\u5185\u5bb9\u3002\u8fd0\u884c dotnet user-jwts create --help \u67e5\u770b\u6240\u6709\u53ef\u7528\u9009\u9879\u3002\u5728\u67d0\u4e9b\u81ea\u52a8\u5316\u811a\u672c\u6216\u6d4b\u8bd5\u4e2d\u53ef\u80fd\u6709\u7528\u7684\u4e00\u4e2a\u9009\u9879\u662f --output \u9009\u9879\u3002\u8fd9\u63a7\u5236\u4e86 JWT \u5728\u521b\u5efa\u540e\u5982\u4f55\u6253\u5370\u5230\u63a7\u5236\u53f0\u3002\u9ed8\u8ba4\u503c default \u6253\u5370 JWT \u548c\u4ee4\u724c\u672c\u8eab\u7684\u6458\u8981\uff0c\u5982\u60a8\u4e4b\u524d\u6240\u89c1\uff1a<\/p>\n<pre><code>New JWT saved with ID &#039;f2080e51&#039;.\nName: andrewlock\n\nToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFuZHJl\u2026<\/code><\/pre>\n<p>This is handy if you\u2019re creating tokens ad hoc at the command line, but the alternative output options may be more useful for scripts. For example, running<br \/>\n\u5982\u679c\u60a8\u5728\u547d\u4ee4\u884c\u4e2d\u4e34\u65f6\u521b\u5efa\u4ee4\u724c\uff0c\u8fd9\u5f88\u65b9\u4fbf\uff0c\u4f46\u66ff\u4ee3\u8f93\u51fa\u9009\u9879\u53ef\u80fd\u5bf9\u811a\u672c\u66f4\u6709\u7528\u3002\u4f8b\u5982\uff0c\u8fd0\u884c<\/p>\n<pre><code>dotnet user-jwts create --output token<\/code><\/pre>\n<p>outputs the token only,<br \/>\n\u4ec5\u8f93\u51fa token\uff0c<\/p>\n<pre><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFuZHJl\u2026<\/code><\/pre>\n<p>which is much more convenient if you\u2019re trying to parse the output in a script, for example. Alternatively, you can pass --output json, which prints details about the JWT instead, as in this example:<br \/>\n\u4f8b\u5982\uff0c\u5982\u679c\u60a8\u5c1d\u8bd5\u5728\u811a\u672c\u4e2d\u89e3\u6790\u8f93\u51fa\uff0c\u8fd9\u4f1a\u66f4\u65b9\u4fbf\u3002\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u4f20\u9012 --output json\uff0c\u5b83\u6539\u4e3a\u6253\u5370\u6709\u5173 JWT \u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5982\u4ee5\u4e0b\u793a\u4f8b\u6240\u793a\uff1a<\/p>\n<pre><code>{\n  &quot;Id&quot;: &quot;8bf9b2fd&quot;,\n  &quot;Scheme&quot;: &quot;Bearer&quot;,\n  &quot;Name&quot;: &quot;andrewlock&quot;,\n  &quot;Audience&quot;: &quot; https:\/\/localhost:7236, http:\/\/localhost:5229&quot;,\n  &quot;NotBefore&quot;: &quot;2022-10-22T17:50:26+00:00&quot;,\n  &quot;Expires&quot;: &quot;2023-01-22T17:50:26+00:00&quot;,\n  &quot;Issued&quot;: &quot;2022-10-22T17:50:26+00:00&quot;,\n  &quot;Token&quot;: &quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Im\u2026&quot;,\n  &quot;Scopes&quot;: [],\n  &quot;Roles&quot;: [],\n  &quot;CustomClaims&quot;: {}\n}<\/code><\/pre>\n<p>Note that this isn\u2019t the payload of the token; it\u2019s the configuration details used to create the JWT. The token itself is exposed in the Token field. Again, this may be useful if you\u2019re generating JWTs using a script and need to parse the output.<br \/>\n\u8bf7\u6ce8\u610f\uff0c\u8fd9\u4e0d\u662f\u4ee4\u724c\u7684\u6709\u6548\u8d1f\u8f7d;\u5b83\u662f\u7528\u4e8e\u521b\u5efa JWT \u7684\u914d\u7f6e\u8be6\u7ec6\u4fe1\u606f\u3002\u4ee4\u724c\u672c\u8eab\u5728 Token \u5b57\u6bb5\u4e2d\u516c\u5f00\u3002\u540c\u6837\uff0c\u5982\u679c\u60a8\u4f7f\u7528\u811a\u672c\u751f\u6210 JWT \u5e76\u9700\u8981\u89e3\u6790\u8f93\u51fa\uff0c\u8fd9\u53ef\u80fd\u5f88\u6709\u7528\u3002<\/p>\n<h3>25.4.3 Managing your local JWTs<\/h3>\n<p>25.4.3 \u7ba1\u7406\u672c\u5730 JWT<\/p>\n<p>When you\u2019re generating a JWT, the user-jwts tool automatically saves the JWT configuration (the JSON shown in section 25.4.2) to your hard drive. This is stored next to the secrets.json file that contains the User Secrets, in a location that varies depending on your operating system and the <code>&lt;UserSecretsId&gt;<\/code> in your project file:<br \/>\n\u751f\u6210 JWT \u65f6\uff0cuser-jwts \u5de5\u5177\u4f1a\u81ea\u52a8\u5c06 JWT \u914d\u7f6e\uff08\u7b2c 25.4.2 \u8282\u4e2d\u663e\u793a\u7684 JSON\uff09\u4fdd\u5b58\u5230\u60a8\u7684\u786c\u76d8\u9a71\u52a8\u5668\u3002\u5b83\u5b58\u50a8\u5728\u5305\u542b User Secrets \u7684 secrets.json \u6587\u4ef6\u65c1\u8fb9\uff0c\u5176<code>&lt;UserSecretsId&gt;<\/code>\u4f4d\u7f6e\u56e0\u4f5c\u7cfb\u7edf\u548c\u9879\u76ee\u6587\u4ef6\u800c\u5f02\uff1a<\/p>\n<p>\u2022  Windows\u2014<code>%APPDATA%\\Microsoft\\UserSecrets\\&lt;UserSecretsId&gt;\\user-jwts.json<\/code><br \/>\n\u2022  Linux and macOS\u2014<code>~\/.microsoft\/usersecrets\/&lt;UserSecretsId&gt;\/user-jwts.json<\/code><\/p>\n<p>As for User Secrets, JWTs created by user-jwts aren\u2019t encrypted, but they\u2019re outside your project directory, so they are a better approach to managing secrets locally. The generated JWTs should be used only for local testing; you should be using a real identity provider for production systems to securely produce JWTs for a logged-in user. This is the reason why the user-jwts tool updates only appsettings.Development.json with the required configuration, not appsettings.json; it stops you from accidentally using user-jwts in production. You should add your production identity provider details in appsettings.json instead.<br \/>\n\u5bf9\u4e8e\u7528\u6237\u5bc6\u94a5\uff0c\u7531 user-jwts \u521b\u5efa\u7684 JWT \u672a\u52a0\u5bc6\uff0c\u4f46\u5b83\u4eec\u4f4d\u4e8e\u9879\u76ee\u76ee\u5f55\u4e4b\u5916\uff0c\u56e0\u6b64\u5b83\u4eec\u662f\u5728\u672c\u5730\u7ba1\u7406\u5bc6\u94a5\u7684\u66f4\u597d\u65b9\u6cd5\u3002\u751f\u6210\u7684 JWT \u5e94\u4ec5\u7528\u4e8e\u672c\u5730\u6d4b\u8bd5;\u60a8\u5e94\u8be5\u4e3a\u751f\u4ea7\u7cfb\u7edf\u4f7f\u7528\u771f\u5b9e\u8eab\u4efd\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4ee5\u4fbf\u4e3a\u767b\u5f55\u7528\u6237\u5b89\u5168\u5730\u751f\u6210 JWT\u3002\u8fd9\u5c31\u662f user-jwts \u5de5\u5177\u4ec5\u66f4\u65b0 appsettings \u7684\u539f\u56e0\u3002Development.json \u4f7f\u7528\u6240\u9700\u7684\u914d\u7f6e\uff0c\u800c\u4e0d\u662f appsettings.json;\u5b83\u53ef\u4ee5\u9632\u6b62\u60a8\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u610f\u5916\u4f7f\u7528 user-jwt\u3002\u60a8\u5e94\u8be5\u6539\u4e3a\u5728 appsettings.json \u4e2d\u6dfb\u52a0\u751f\u4ea7\u8eab\u4efd\u63d0\u4f9b\u5546\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>As well as editing the user-jwts.json file manually, you can use the user-jwts tool to manage the JWTs stored locally. In addition to using create, you can call dotnet user-jwts <code>&lt;command&gt;<\/code> from the project folder, where <code>&lt;command&gt;<\/code> is one of the following options:<br \/>\n\u9664\u4e86\u624b\u52a8\u7f16\u8f91 user-jwts.json \u6587\u4ef6\u5916\uff0c\u60a8\u8fd8\u53ef\u4ee5\u4f7f\u7528 user-jwts \u5de5\u5177\u6765\u7ba1\u7406\u672c\u5730\u5b58\u50a8\u7684 JWT\u3002\u9664\u4e86\u4f7f\u7528 create \u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u4ece\u9879\u76ee\u6587\u4ef6\u5939\u8c03\u7528 dotnet user-jwts<code>&lt;command&gt;<\/code> \uff0c\u5176\u4e2d<code>&lt;command&gt;<\/code> \u662f\u4ee5\u4e0b\u9009\u9879\u4e4b\u4e00\uff1a<\/p>\n<p>\u2022  list\u2014Lists a summary of all the tokens stored in user-jwts.json for the project.<br \/>\nlist - \u5217\u51fa\u9879\u76eeuser-jwts.json\u4e2d\u5b58\u50a8\u7684\u6240\u6709\u6807\u8bb0\u7684\u6458\u8981\u3002<\/p>\n<p>\u2022  clear\u2014Deletes all the tokens created for a project.<br \/>\nclear - \u5220\u9664\u4e3a\u9879\u76ee\u521b\u5efa\u7684\u6240\u6709\u6807\u8bb0\u3002<\/p>\n<p>\u2022  remove\u2014Deletes a single token for the project, using the token ID displayed by the list command.<br \/>\nremove - \u4f7f\u7528 list \u547d\u4ee4\u663e\u793a\u7684\u4ee4\u724c ID \u5220\u9664\u9879\u76ee\u7684\u5355\u4e2a\u4ee4\u724c\u3002<\/p>\n<p>\u2022  print\u2014Outputs the details of a single JWT, using the token ID, as key value pairs.<br \/>\nprint - \u4f7f\u7528\u4ee4\u724c ID \u4f5c\u4e3a\u952e\u503c\u5bf9\u8f93\u51fa\u5355\u4e2a JWT \u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>\u2022  key\u2014Can be used to view or reset the signing key material of tokens stored in the User Secrets Manager. Note that resetting the key material renders all previous JWTs generated by the tool invalid.<br \/>\nkey - \u53ef\u7528\u4e8e\u67e5\u770b\u6216\u91cd\u7f6e\u5b58\u50a8\u5728 User Secrets Manager \u4e2d\u7684\u4ee4\u724c\u7684\u7b7e\u540d\u5bc6\u94a5\u6750\u6599\u3002\u8bf7\u6ce8\u610f\uff0c\u91cd\u7f6e\u5bc6\u94a5\u6750\u6599\u4f1a\u4f7f\u8be5\u5de5\u5177\u4e4b\u524d\u751f\u6210\u7684\u6240\u6709 JWT \u65e0\u6548\u3002<\/p>\n<p>The user-jwts tool is handy for generating JWTs locally, but you must remember to add it to your local testing tool for all requests. If you\u2019re using Postman for testing, you need to add the JWT to your request, as I showed in figure 25.10. However, if you\u2019re using Swagger UI as I described in chapter 11, things aren\u2019t quite that simple. In the next section you\u2019ll learn how to describe your authorization requirements in your OpenAPI document.<br \/>\nuser-jwts \u5de5\u5177\u5bf9\u4e8e\u5728\u672c\u5730\u751f\u6210 JWT \u975e\u5e38\u65b9\u4fbf\uff0c\u4f46\u60a8\u5fc5\u987b\u8bb0\u4f4f\u5c06\u5176\u6dfb\u52a0\u5230\u6240\u6709\u8bf7\u6c42\u7684\u672c\u5730\u6d4b\u8bd5\u5de5\u5177\u4e2d\u3002\u5982\u679c\u60a8\u4f7f\u7528 Postman \u8fdb\u884c\u6d4b\u8bd5\uff0c\u5219\u9700\u8981\u5c06 JWT \u6dfb\u52a0\u5230\u60a8\u7684\u8bf7\u6c42\u4e2d\uff0c\u5982\u56fe 25.10 \u6240\u793a\u3002\u4f46\u662f\uff0c\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f\u6211\u5728\u7b2c 11 \u7ae0\u4e2d\u63cf\u8ff0\u7684 Swagger UI\uff0c\u4e8b\u60c5\u5c31\u6ca1\u6709\u90a3\u4e48\u7b80\u5355\u4e86\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5728 OpenAPI \u6587\u6863\u4e2d\u63cf\u8ff0\u60a8\u7684\u6388\u6743\u8981\u6c42\u3002<\/p>\n<h2>25.5 Describing your authentication requirements to OpenAPI<\/h2>\n<p>25.5 \u5411 OpenAPI \u63cf\u8ff0\u60a8\u7684\u8eab\u4efd\u9a8c\u8bc1\u8981\u6c42<\/p>\n<p>In chapter 11 you learned how to add an OpenAPI document to your ASP.NET Core app that describes your API. This is used to power tooling such as automatic client generation, as well as Swagger UI. In this section you\u2019ll learn how to add authentication requirements to your OpenAPI document so you can test your API using Swagger UI with tokens generated by the user-jwts tool.<br \/>\n\u5728\u7b2c 11 \u7ae0\u4e2d\uff0c\u60a8\u5b66\u4e60\u4e86\u5982\u4f55\u5c06 OpenAPI \u6587\u6863\u6dfb\u52a0\u5230\u60a8\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u4ee5\u63cf\u8ff0 API\u3002\u8fd9\u7528\u4e8e\u652f\u6301\u81ea\u52a8\u5ba2\u6237\u7aef\u751f\u6210\u4ee5\u53ca Swagger UI \u7b49\u5de5\u5177\u3002\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5411 OpenAPI \u6587\u6863\u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u8981\u6c42\uff0c\u4ee5\u4fbf\u60a8\u53ef\u4ee5\u4f7f\u7528 Swagger UI \u548c user-jwts \u5de5\u5177\u751f\u6210\u7684\u4ee4\u724c\u6765\u6d4b\u8bd5\u60a8\u7684 API\u3002<\/p>\n<p>One of the slightly annoying things about adding authentication and authorization to your APIs is that it makes testing harder. You can\u2019t just fire a web request from a browser; you must use a tool like Postman that you can add headers to. Even for command-line aficionados, curl commands can become unwieldy once you need to add authorization headers. And tokens expire and are typically harder to generate. The list goes on!<br \/>\n\u5411 API \u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7684\u4e00\u4e2a\u7a0d\u5fae\u4ee4\u4eba\u8ba8\u538c\u7684\u4e8b\u60c5\u662f\uff0c\u5b83\u4f7f\u6d4b\u8bd5\u53d8\u5f97\u66f4\u52a0\u56f0\u96be\u3002\u60a8\u4e0d\u80fd\u53ea\u4ece\u6d4f\u89c8\u5668\u89e6\u53d1 Web \u8bf7\u6c42;\u60a8\u5fc5\u987b\u4f7f\u7528\u50cf Postman \u8fd9\u6837\u53ef\u4ee5\u6dfb\u52a0\u6807\u5934\u7684\u5de5\u5177\u3002\u5373\u4f7f\u5bf9\u4e8e\u547d\u4ee4\u884c\u7231\u597d\u8005\u6765\u8bf4\uff0c\u4e00\u65e6\u60a8\u9700\u8981\u6dfb\u52a0\u6388\u6743\u6807\u5934\uff0ccurl \u547d\u4ee4\u4e5f\u4f1a\u53d8\u5f97\u7b28\u62d9\u3002\u4ee4\u724c\u4f1a\u8fc7\u671f\uff0c\u901a\u5e38\u66f4\u96be\u751f\u6210\u3002\u540d\u5355\u8fd8\u5728\u7ee7\u7eed\uff01<\/p>\n<p>I\u2019ve seen these difficulties lead people to disable authentication requirements for local testing or to try to add them only late in a product\u2019s life cycle. I strongly suggest you don\u2019t do this! Trying to add real authentication late in a project is likely to cause headaches and bugs that you could easily have caught if you weren\u2019t trying to work around the security complexity.<br \/>\n\u6211\u770b\u5230\u8fd9\u4e9b\u56f0\u96be\u5bfc\u81f4\u4eba\u4eec\u7981\u7528\u672c\u5730\u6d4b\u8bd5\u7684\u8eab\u4efd\u9a8c\u8bc1\u8981\u6c42\uff0c\u6216\u8005\u5c1d\u8bd5\u4ec5\u5728\u4ea7\u54c1\u751f\u547d\u5468\u671f\u7684\u540e\u671f\u624d\u6dfb\u52a0\u5b83\u4eec\u3002\u6211\u5f3a\u70c8\u5efa\u8bae\u4f60\u4e0d\u8981\u8fd9\u6837\u505a\uff01\u5c1d\u8bd5\u5728\u9879\u76ee\u540e\u671f\u6dfb\u52a0\u771f\u6b63\u7684\u8eab\u4efd\u9a8c\u8bc1\u53ef\u80fd\u4f1a\u5bfc\u81f4\u4ee4\u4eba\u5934\u75bc\u548c\u9519\u8bef\uff0c\u5982\u679c\u60a8\u4e0d\u5c1d\u8bd5\u89e3\u51b3\u5b89\u5168\u6027\u590d\u6742\u6027\uff0c\u60a8\u5f88\u5bb9\u6613\u53d1\u73b0\u8fd9\u4e9b\u9519\u8bef\u3002<\/p>\n<p><b>TIP<\/b> Add real authentication and authorization to your APIs as soon as you understand the requirements, as you will likely catch more security-related bugs.<br \/>\n\u63d0\u793a:\u4e86\u89e3\u8981\u6c42\u540e\uff0c\u7acb\u5373\u5411 API \u6dfb\u52a0\u771f\u6b63\u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\uff0c\u56e0\u4e3a\u60a8\u53ef\u80fd\u4f1a\u53d1\u73b0\u66f4\u591a\u4e0e\u5b89\u5168\u76f8\u5173\u7684\u9519\u8bef\u3002<\/p>\n<p>The user-jwts tool can help significantly with these challenges, as you can easily generate tokens in a format you need, optionally with a long expiration (so you don\u2019t need to keep renewing them) without having to wrestle with an identity provider directly. Nevertheless, you need a way to add these tokens to whichever tool you use for testing, such as Swagger UI.<br \/>\nuser-jwts \u5de5\u5177\u53ef\u4ee5\u6781\u5927\u5730\u5e2e\u52a9\u89e3\u51b3\u8fd9\u4e9b\u6311\u6218\uff0c\u56e0\u4e3a\u60a8\u53ef\u4ee5\u8f7b\u677e\u5730\u4ee5\u6240\u9700\u7684\u683c\u5f0f\u751f\u6210\u4ee4\u724c\uff0c\u5e76\u4e14\u53ef\u4ee5\u9009\u62e9\u5177\u6709\u8f83\u957f\u7684\u8fc7\u671f\u65f6\u95f4\uff08\u56e0\u6b64\u60a8\u65e0\u9700\u4e0d\u65ad\u7eed\u8ba2\u5b83\u4eec\uff09\uff0c\u800c\u65e0\u9700\u76f4\u63a5\u4e0e\u8eab\u4efd\u63d0\u4f9b\u5546\u640f\u6597\u3002\u4e0d\u8fc7\uff0c\u60a8\u9700\u8981\u4e00\u79cd\u65b9\u6cd5\u5c06\u8fd9\u4e9b\u4ee4\u724c\u6dfb\u52a0\u5230\u7528\u4e8e\u6d4b\u8bd5\u7684\u4efb\u4f55\u5de5\u5177\u4e2d\uff0c\u4f8b\u5982 Swagger UI\u3002<\/p>\n<p>Swagger UI is based on the OpenAPI definition of your API, so the best (and easiest) way to add support for authentication to Swagger UI is to update the security requirements of your application in your OpenAPI document. This consists of two steps:<br \/>\nSwagger UI \u57fa\u4e8e API \u7684 OpenAPI \u5b9a\u4e49\uff0c\u56e0\u6b64\u5411 Swagger UI \u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u652f\u6301\u7684\u6700\u4f73\uff08\u4e5f\u662f\u6700\u7b80\u5355\u7684\uff09\u65b9\u6cd5\u662f\u5728 OpenAPI \u6587\u6863\u4e2d\u66f4\u65b0\u5e94\u7528\u7a0b\u5e8f\u7684\u5b89\u5168\u8981\u6c42\u3002\u8fd9\u5305\u62ec\u4e24\u4e2a\u6b65\u9aa4\uff1a<\/p>\n<p>\u2022  Define the security scheme your API uses, such as OAuth 2.0, OpenID Connect, or simple Bearer authentication.<br \/>\n\u5b9a\u4e49 API \u4f7f\u7528\u7684\u5b89\u5168\u65b9\u6848\uff0c\u4f8b\u5982 OAuth 2.0\u3001OpenID Connect \u6216\u7b80\u5355\u7684 Bearer \u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>\u2022  Declare which endpoints in your API use the security scheme.<br \/>\n\u58f0\u660e API \u4e2d\u7684\u54ea\u4e9b\u7aef\u70b9\u4f7f\u7528\u5b89\u5168\u65b9\u6848\u3002<\/p>\n<p>The following listing shows how to configure an OpenAPI document using Swashbuckle for an API that uses JWT bearer authentication. The values defined on OpenApiSecurityScheme match the default settings configured by the user-jwts tool when you use AddJwtBearer(). AddSecurityDefinition() defines a security scheme for your API, and AddSecurityRequirement() declares that the whole API is protected using the security scheme.<br \/>\n\u4e0b\u9762\u7684\u6e05\u5355\u663e\u793a\u4e86\u5982\u4f55\u4f7f\u7528 Swashbuckle \u4e3a\u4f7f\u7528 JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u7684 API \u914d\u7f6e OpenAPI \u6587\u6863\u3002\u5728 OpenApiSecurityScheme \u4e0a\u5b9a\u4e49\u7684\u503c\u4e0e\u4f7f\u7528 AddJwtBearer\uff08\uff09 \u65f6 user-jwts \u5de5\u5177\u914d\u7f6e\u7684\u9ed8\u8ba4\u8bbe\u7f6e\u5339\u914d\u3002AddSecurityDefinition\uff08\uff09 \u4e3a\u60a8\u7684 API \u5b9a\u4e49\u4e00\u4e2a\u5b89\u5168\u65b9\u6848\uff0cAddSecurityRequirement\uff08\uff09 \u58f0\u660e\u4f7f\u7528\u8be5\u5b89\u5168\u65b9\u6848\u4fdd\u62a4\u6574\u4e2a API\u3002<\/p>\n<p>Listing 25.2 Adding bearer authentication to an OpenAPI document using Swashbuckle<br \/>\n\u6e05\u5355 25.2 \u4f7f\u7528 Swashbuckle \u5411 OpenAPI \u6587\u6863\u6dfb\u52a0\u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1<\/p>\n<pre><code>WebApplicationBuilder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddAuthentication().AddJwtBearer();\nbuilder.Services.AddAuthorization();\n\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen(x =&gt;\n{\n    x.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo {\n        Title = &quot;Recipe App&quot;, Version = &quot;v1&quot; });\n\n    var security = new OpenApiSecurityScheme    #A\n    {\n        Name = HeaderNames.Authorization,    #B\n        Type = SecuritySchemeType.ApiKey,    #C\n        In = ParameterLocation.Header,    #D\n        Description = &quot;JWT Authorization header&quot;,  #E\n        Reference = new OpenApiReference\n        {\n            Id = JwtBearerDefaults.AuthenticationScheme,  #F\n            Type = ReferenceType.SecurityScheme   #G\n        }\n    };\n\n    x.AddSecurityDefinition(security.Reference.Id, security);  #H\n    x.AddSecurityRequirement(new OpenApiSecurityRequirement   #I\n        {{security, Array.Empty&lt;string&gt;()}});  #I\n});\n\nvar app = builder.Build();\n\napp.UseSwagger();\napp.UseSwaggerUI();\n\napp.UseRouting();\napp.UseAuthentication();\napp.UseAuthorization();\n\napp.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello world!&quot;).RequireAuthorization();\napp.Run();<\/code><\/pre>\n<p>\u2776 Defines the security used by your API<br \/>\n\u5b9a\u4e49 API\u4f7f\u7528\u7684\u5b89\u5168\u6027<\/p>\n<p>\u2777 The name of the header to use (required)<br \/>\n\u8981\u4f7f\u7528\u7684\u6807\u5934\u7684\u540d\u79f0\uff08\u5fc5\u9700\uff09<\/p>\n<p>\u2778 The type of security; may be OAuth2 or OpenIdConnect if using those (required)<br \/>\n\u5b89\u5168\u6027\u7684\u7c7b\u578b;\u53ef\u80fd\u662f OAuth2 \u6216 OpenIdConnect\uff08\u5982\u679c\u9700\u8981\uff09<\/p>\n<p>\u2779 Where the token will be provided (required)<br \/>\n\u5c06\u63d0\u4f9b\u4ee4\u724c\u7684\u4f4d\u7f6e\uff08\u5fc5\u9700\uff09<\/p>\n<p>\u277a A friendly description of the scheme, used in the UI<br \/>\n\u5728UI\u4e2d\u4f7f\u7528\u65b9\u6848\u7684\u53cb\u597d\u63cf\u8ff0<\/p>\n<p>\u277b A unique ID for the scheme. This uses the default JWT scheme name.<br \/>\n\u65b9\u6848\u7684\u552f\u4e00 ID\u3002\u8fd9\u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 JWT \u65b9\u6848\u540d\u79f0\u3002<\/p>\n<p>\u277c The type of OpenID object (required)<br \/>\nOpenID \u5bf9\u8c61\u7684\u7c7b\u578b\uff08\u5fc5\u9700\uff09<\/p>\n<p>\u277d Adds the security definition to the OpenAPI document<br \/>\n\u5c06\u5b89\u5168\u5b9a\u4e49\u6dfb\u52a0\u5230 OpenAPI \u6587\u6863<\/p>\n<p>\u277e Marks the whole API as protected by the security definition<br \/>\n\u5c06\u6574\u4e2a API \u6807\u8bb0\u4e3a\u53d7\u5b89\u5168\u5b9a\u4e49\u4fdd\u62a4<\/p>\n<p>When you run your application after adding the definition to your OpenAPI document, you should see an Authorize button in the top-right corner of Swagger UI, as shown in figure 25.11. Choosing this button opens a dialog box describing your authentication scheme, including a text box to enter your token. You must enter Bearer <token> in this box with a space between them. Choose Authorize, which saves the value, and then Close. Now when you send a request to the API, Swagger UI attaches the token in the Authorization header, and the request succeeds.<br \/>\n\u5728\u5c06\u5b9a\u4e49\u6dfb\u52a0\u5230 OpenAPI \u6587\u6863\u540e\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u60a8\u5e94\u8be5\u4f1a\u5728 Swagger UI \u7684\u53f3\u4e0a\u89d2\u770b\u5230\u4e00\u4e2a Authorize \u6309\u94ae\uff0c\u5982\u56fe 25.11 \u6240\u793a\u3002\u9009\u62e9\u6b64\u6309\u94ae\u5c06\u6253\u5f00\u4e00\u4e2a\u63cf\u8ff0\u60a8\u7684\u8eab\u4efd\u9a8c\u8bc1\u65b9\u6848\u7684\u5bf9\u8bdd\u6846\uff0c\u5176\u4e2d\u5305\u62ec\u4e00\u4e2a\u7528\u4e8e\u8f93\u5165\u4ee4\u724c\u7684\u6587\u672c\u6846\u3002\u60a8\u5fc5\u987b\u5728\u6b64\u6846\u4e2d\u8f93\u5165 Bearer \uff0c\u5e76\u5728\u5b83\u4eec\u4e4b\u95f4\u7559\u51fa\u7a7a\u683c\u3002\u9009\u62e9 Authorize \uff08\u6388\u6743\uff09 \u4ee5\u4fdd\u5b58\u503c\uff0c\u7136\u540e\u9009\u62e9 Close \uff08\u5173\u95ed\uff09\u3002\u73b0\u5728\uff0c\u5f53\u60a8\u5411 API \u53d1\u9001\u8bf7\u6c42\u65f6\uff0cSwagger UI \u4f1a\u5728 Authorization \u6807\u5934\u4e2d\u9644\u52a0\u4ee4\u724c\uff0c\u5e76\u4e14\u8bf7\u6c42\u6210\u529f\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2511.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.11 Adding an Authorization header using Swagger UI. When adding the token, ensure that you enter Bearer <token>, including the Bearer prefix. Swagger UI then attaches the token to all subsequent requests, so you are authorized to call the API.<br \/>\n\u56fe 25.11 \u4f7f\u7528 Swagger UI \u6dfb\u52a0 Authorization \u6807\u5934\u3002\u6dfb\u52a0\u4ee4\u724c\u65f6\uff0c\u8bf7\u786e\u4fdd\u8f93\u5165 Bearer \uff0c\u5305\u62ec Bearer \u524d\u7f00\u3002\u7136\u540e\uff0cSwagger UI \u4f1a\u5c06\u4ee4\u724c\u9644\u52a0\u5230\u6240\u6709\u540e\u7eed\u8bf7\u6c42\uff0c\u4ee5\u4fbf\u60a8\u6709\u6743\u8c03\u7528 API\u3002<\/p>\n<p>If you\u2019re specifically using OpenID Connect or OAuth 2.0 to protect your APIs, you can configure these in the OpenApiSecurityScheme document instead of using bearer authentication. In that case, choosing Authorize in Swagger UI would redirect you to your identity provider to sign in and retrieve a token without your having to copy and paste anything. That\u2019s extremely useful if you\u2019re running an identity provider locally or exposing Swagger UI in production.<br \/>\n\u5982\u679c\u60a8\u4e13\u95e8\u4f7f\u7528 OpenID Connect \u6216 OAuth 2.0 \u6765\u4fdd\u62a4 API\uff0c\u5219\u53ef\u4ee5\u5728 OpenApiSecurityScheme \u6587\u6863\u4e2d\u914d\u7f6e\u8fd9\u4e9b API\uff0c\u800c\u4e0d\u662f\u4f7f\u7528\u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5728 Swagger UI \u4e2d\u9009\u62e9 Authorize \uff08\u6388\u6743\uff09 \u4f1a\u5c06\u60a8\u91cd\u5b9a\u5411\u5230\u60a8\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u4ee5\u767b\u5f55\u5e76\u68c0\u7d22\u4ee4\u724c\uff0c\u800c\u65e0\u9700\u590d\u5236\u548c\u7c98\u8d34\u4efb\u4f55\u5185\u5bb9\u3002\u5982\u679c\u60a8\u5728\u672c\u5730\u8fd0\u884c\u8eab\u4efd\u63d0\u4f9b\u5546\u6216\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u516c\u5f00 Swagger UI\uff0c\u8fd9\u5c06\u975e\u5e38\u6709\u7528\u3002<\/p>\n<p>The example in listing 25.2 shows the configuration when your whole API is protected by an authorization requirement. That\u2019s the most common situation in my experience, but you may want to expose certain endpoints to anonymous users without any authorization requirements. In that case, you can configure Swashbuckle to conditionally apply the requirement to only those endpoints with a requirement.<br \/>\n\u6e05\u5355 25.2 \u4e2d\u7684\u793a\u4f8b\u663e\u793a\u4e86\u6574\u4e2a API \u53d7\u6388\u6743\u9700\u6c42\u4fdd\u62a4\u65f6\u7684\u914d\u7f6e\u3002\u6839\u636e\u6211\u7684\u7ecf\u9a8c\uff0c\u8fd9\u662f\u6700\u5e38\u89c1\u7684\u60c5\u51b5\uff0c\u4f46\u60a8\u53ef\u80fd\u5e0c\u671b\u5c06\u67d0\u4e9b\u7aef\u70b9\u516c\u5f00\u7ed9\u533f\u540d\u7528\u6237\uff0c\u800c\u65e0\u9700\u4efb\u4f55\u6388\u6743\u8981\u6c42\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u4ee5\u5c06 Swashbuckle \u914d\u7f6e\u4e3a\u6709\u6761\u4ef6\u5730\u4ec5\u5c06\u8981\u6c42\u5e94\u7528\u4e8e\u5177\u6709\u8981\u6c42\u7684\u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n<p><b>TIP<\/b> See the Swashbuckle documentation to learn how to configure this and many other features related to OpenAPI document generation: <a href=\"http:\/\/mng.bz\/6D1A\">http:\/\/mng.bz\/6D1A<\/a>. Swashbuckle is highly extensible, but as always, it\u2019s worth considering whether the added complexity you introduce to achieve perfect documentation of your API is worth the tradeoff. For publicly exposed OpenAPI documents, this may well be the case, but for local testing or internal APIs, the argument may be harder to make.<br \/>\n\u63d0\u793a:\u8bf7\u53c2\u9605 Swashbuckle \u6587\u6863\uff0c\u4e86\u89e3\u5982\u4f55\u914d\u7f6e\u6b64\u529f\u80fd\u4ee5\u53ca\u4e0e OpenAPI \u6587\u6863\u751f\u6210\u76f8\u5173\u7684\u8bb8\u591a\u5176\u4ed6\u529f\u80fd\uff1a<a href=\"http:\/\/mng.bz\/6D1A\u3002Swashbuckle\">http:\/\/mng.bz\/6D1A\u3002Swashbuckle<\/a> \u5177\u6709\u9ad8\u5ea6\u53ef\u6269\u5c55\u6027\uff0c\u4f46\u4e0e\u5f80\u5e38\u4e00\u6837\uff0c\u503c\u5f97\u8003\u8651\u4e3a\u5b9e\u73b0 API \u7684\u5b8c\u7f8e\u6587\u6863\u800c\u5f15\u5165\u7684\u989d\u5916\u590d\u6742\u6027\u662f\u5426\u503c\u5f97\u6743\u8861\u3002\u5bf9\u4e8e\u516c\u5f00\u516c\u5f00\u7684 OpenAPI \u6587\u6863\uff0c\u60c5\u51b5\u5f88\u53ef\u80fd\u5982\u6b64\uff0c\u4f46\u5bf9\u4e8e\u672c\u5730\u6d4b\u8bd5\u6216\u5185\u90e8 API\uff0c\u53ef\u80fd\u66f4\u96be\u63d0\u51fa\u8bba\u70b9\u3002<\/p>\n<p>In this chapter we\u2019ve looked in depth at using JWT bearer tokens for authentication and explored the parallels with cookie authentication for traditional apps. In the final section of this chapter we look at authorization and how you can apply different authorization policies to your minimal API endpoints.<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u4eec\u6df1\u5165\u63a2\u8ba8\u4e86\u5982\u4f55\u4f7f\u7528 JWT \u4e0d\u8bb0\u540d\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5e76\u63a2\u8ba8\u4e86\u4e0e\u4f20\u7edf\u5e94\u7528\u7a0b\u5e8f\u7684 cookie \u8eab\u4efd\u9a8c\u8bc1\u7684\u76f8\u4f3c\u4e4b\u5904\u3002\u5728\u672c\u7ae0\u7684\u6700\u540e\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u6388\u6743\u4ee5\u53ca\u5982\u4f55\u5c06\u4e0d\u540c\u7684\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e\u60a8\u7684\u6700\u5c0f API \u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n<h2>25.6 Applying authorization policies to minimal API endpoints<\/h2>\n<p>25.6 \u5c06\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e\u6700\u5c0f API \u7aef\u70b9<\/p>\n<p>So far in this chapter we\u2019ve focused on authentication: the process of validating the identity of the request initiator. For APIs, this typically requires decoding and validating a JWT bearer token in the authentication middleware and setting the ClaimsPrincipal for the request, as you saw in section 25.2. In this section we look at the next stage in protecting your APIs, authorization, and how you can apply different authorization requirements to your minimal API endpoints.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u4eec\u91cd\u70b9\u4ecb\u7ecd\u4e86\u8eab\u4efd\u9a8c\u8bc1\uff1a\u9a8c\u8bc1\u8bf7\u6c42\u53d1\u8d77\u8005\u8eab\u4efd\u7684\u8fc7\u7a0b\u3002\u5bf9\u4e8e API\uff0c\u8fd9\u901a\u5e38\u9700\u8981\u5728\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4e2d\u89e3\u7801\u548c\u9a8c\u8bc1 JWT \u4e0d\u8bb0\u540d\u4ee4\u724c\uff0c\u5e76\u4e3a\u8bf7\u6c42\u8bbe\u7f6e ClaimsPrincipal\uff0c\u5982\u7b2c 25.2 \u8282\u6240\u793a\u3002\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u4fdd\u62a4 API \u7684\u4e0b\u4e00\u9636\u6bb5\u3001\u6388\u6743\uff0c\u4ee5\u53ca\u5982\u4f55\u5c06\u4e0d\u540c\u7684\u6388\u6743\u8981\u6c42\u5e94\u7528\u4e8e\u6700\u5c0f API \u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n<p>The good news is that authorization for minimal APIs is essentially identical to the authorization process you learned about in chapter 24 for Razor Pages and MVC controllers. The same concept of authorization policies, requirements, handlers, and claims-based authorization apply in the same way and use the exact same services. Figure 25.12 shows how this looks for a request to a minimal API endpoint protected with bearer authentication, which is remarkably similar to the Razor Pages equivalent in figure 24.2.<br \/>\n\u597d\u6d88\u606f\u662f\uff0c\u6700\u5c0f API \u7684\u6388\u6743\u4e0e\u60a8\u5728\u7b2c 24 \u7ae0\u4e2d\u4e86\u89e3\u7684 Razor Pages \u548c MVC \u63a7\u5236\u5668\u7684\u6388\u6743\u8fc7\u7a0b\u57fa\u672c\u76f8\u540c\u3002\u76f8\u540c\u7684\u6388\u6743\u7b56\u7565\u3001\u8981\u6c42\u3001\u5904\u7406\u7a0b\u5e8f\u548c\u57fa\u4e8e\u58f0\u660e\u7684\u6388\u6743\u6982\u5ff5\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u5e94\u7528\uff0c\u5e76\u4f7f\u7528\u5b8c\u5168\u76f8\u540c\u7684\u670d\u52a1\u3002\u56fe 25.12 \u663e\u793a\u4e86\u5982\u4f55\u67e5\u627e\u5bf9\u53d7\u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u4fdd\u62a4\u7684\u6700\u5c0f API \u7aef\u70b9\u7684\u8bf7\u6c42\uff0c\u8fd9\u4e0e\u56fe 24.2 \u4e2d\u7684 Razor Pages \u7b49\u6548\u9879\u975e\u5e38\u76f8\u4f3c\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2512.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 25.12 Authorizing a request to a minimal API endpoint. The routing middleware selects an endpoint that is protected by an authorization requirement. The authentication middleware decodes and verifies the bearer token, creating a ClaimsPrincipal, which the authorization middleware uses along with the endpoint metadata to determine whether the request is authorized.<br \/>\n\u56fe 25.12 \u6388\u6743\u5bf9\u6700\u5c0f API \u7aef\u70b9\u7684\u8bf7\u6c42\u3002\u8def\u7531\u4e2d\u95f4\u4ef6\u9009\u62e9\u53d7\u6388\u6743\u8981\u6c42\u4fdd\u62a4\u7684\u7ec8\u7aef\u8282\u70b9\u3002\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u5bf9\u6301\u6709\u8005\u4ee4\u724c\u8fdb\u884c\u89e3\u7801\u548c\u9a8c\u8bc1\uff0c\u521b\u5efa\u4e00\u4e2a ClaimsPrincipal\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u5c06\u5176\u4e0e\u7ec8\u7ed3\u70b9\u5143\u6570\u636e\u4e00\u8d77\u4f7f\u7528\uff0c\u4ee5\u786e\u5b9a\u8bf7\u6c42\u662f\u5426\u83b7\u5f97\u6388\u6743\u3002<\/p>\n<p>You\u2019ve already seen that you can apply a general authorization requirement by calling RequireAuthorization() on an endpoint or a route group. This is directly equivalent to adding the [Authorize] attribute to a Razor Page or MVC controller action. In fact, you can use the same [Authorize] attribute on an endpoint if you wish, so the following two endpoint definitions are equivalent:<br \/>\n\u60a8\u5df2\u7ecf\u770b\u5230\uff0c\u60a8\u53ef\u4ee5\u901a\u8fc7\u5728\u7ec8\u7aef\u8282\u70b9\u6216\u8def\u7531\u7ec4\u4e0a\u8c03\u7528 RequireAuthorization\uff08\uff09 \u6765\u5e94\u7528\u5e38\u89c4\u6388\u6743\u8981\u6c42\u3002\u8fd9\u76f4\u63a5\u7b49\u6548\u4e8e\u5c06 [Authorize] \u5c5e\u6027\u6dfb\u52a0\u5230 Razor Page \u6216 MVC \u63a7\u5236\u5668\u4f5c\u3002\u4e8b\u5b9e\u4e0a\uff0c\u5982\u679c\u9700\u8981\uff0c\u53ef\u4ee5\u5728\u7ec8\u7ed3\u70b9\u4e0a\u4f7f\u7528\u76f8\u540c\u7684 [Authorize] \u5c5e\u6027\uff0c\u56e0\u6b64\u4ee5\u4e0b\u4e24\u4e2a\u7ec8\u7ed3\u70b9\u5b9a\u4e49\u662f\u7b49\u6548\u7684\uff1a<\/p>\n<pre><code>app.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello world!&quot;).RequireAuthorization();\napp.MapGet(&quot;\/&quot;, [Authorize] () =&gt; &quot;Hello world!&quot;);<\/code><\/pre>\n<p>If you want to require a specific policy (the &quot;CanCreate&quot; policy, for example), you can pass the policy names to the RequireAuthorization() method the same way you would for the [Authorize] attribute:<br \/>\n\u5982\u679c\u8981\u8981\u6c42\u7279\u5b9a\u7b56\u7565\uff08\u4f8b\u5982\u201cCanCreate\u201d\u7b56\u7565\uff09\uff0c\u5219\u53ef\u4ee5\u5c06\u7b56\u7565\u540d\u79f0\u4f20\u9012\u7ed9 RequireAuthorization\uff08\uff09 \u65b9\u6cd5\uff0c\u5c31\u50cf\u5bf9 [Authorize] \u5c5e\u6027\u6240\u505a\u7684\u90a3\u6837\uff1a<\/p>\n<pre><code>app.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello world!&quot;).RequireAuthorization(&quot;CanCreate&quot;);\napp.MapGet(&quot;\/&quot;, [Authorize(&quot;CanCreate&quot;)] () =&gt; &quot;Hello world!&quot;);<\/code><\/pre>\n<p>Similarly, you can exclude endpoints from authentication requirements using the AllowAnonymous() function or [AllowAnonymous] attribute:<br \/>\n\u540c\u6837\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528 AllowAnonymous\uff08\uff09 \u51fd\u6570\u6216 [AllowAnonymous] \u5c5e\u6027\u4ece\u8eab\u4efd\u9a8c\u8bc1\u8981\u6c42\u4e2d\u6392\u9664\u7aef\u70b9\uff1a<\/p>\n<pre><code>app.MapGet(&quot;\/&quot;, () =&gt; &quot;Hello world!&quot;).AllowAnonymous();\napp.MapGet(&quot;\/&quot;, [AllowAnonymous] () =&gt; &quot;Hello world!&quot;);<\/code><\/pre>\n<p>This is a good start, but as you saw in chapter 24, you often need to perform resource-based authorization. For example, in the context of the recipe API, users should be allowed to edit or delete only recipes that they created; they can\u2019t edit someone else\u2019s recipe. That means you need to know details about the resource (the recipe) before determining whether a request is authorized.<br \/>\n\u8fd9\u662f\u4e00\u4e2a\u597d\u7684\u5f00\u59cb\uff0c\u4f46\u6b63\u5982\u60a8\u5728\u7b2c 24 \u7ae0\u4e2d\u770b\u5230\u7684\u90a3\u6837\uff0c\u60a8\u901a\u5e38\u9700\u8981\u6267\u884c\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u3002\u4f8b\u5982\uff0c\u5728\u914d\u65b9 API \u7684\u4e0a\u4e0b\u6587\u4e2d\uff0c\u5e94\u4ec5\u5141\u8bb8\u7528\u6237\u7f16\u8f91\u6216\u5220\u9664\u4ed6\u4eec\u521b\u5efa\u7684\u914d\u65b9;\u4ed6\u4eec\u65e0\u6cd5\u7f16\u8f91\u5176\u4ed6\u4eba\u7684\u914d\u65b9\u3002\u8fd9\u610f\u5473\u7740\u5728\u786e\u5b9a\u8bf7\u6c42\u662f\u5426\u83b7\u5f97\u6388\u6743\u4e4b\u524d\uff0c\u60a8\u9700\u8981\u4e86\u89e3\u6709\u5173\u8d44\u6e90\uff08\u914d\u65b9\uff09\u7684\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>Resource-based authorization is essentially the same for minimal API endpoints as for Razor Pages or MVC controllers. You must follow several steps, most of which we covered in chapter 24:<br \/>\n\u6700\u5c0f API \u7aef\u70b9\u7684\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u4e0e Razor Pages \u6216 MVC \u63a7\u5236\u5668\u7684\u6388\u6743\u57fa\u672c\u76f8\u540c\u3002\u60a8\u5fc5\u987b\u9075\u5faa\u51e0\u4e2a\u6b65\u9aa4\uff0c\u5176\u4e2d\u5927\u90e8\u5206\u6211\u4eec\u5728\u7b2c 24 \u7ae0\u4e2d\u4ecb\u7ecd\uff1a<\/p>\n<ol>\n<li>\n<p>Create an <code>AuthorizationHandler&lt;TRequirement, TResource&gt;<\/code>, and register it in the DI container, as shown in chapter 24.<br \/>\n\u521b\u5efa\u4e00\u4e2a<code>AuthorizationHandler&lt;TRequirement, TResource&gt;<\/code> \uff0c\u5e76\u5728 DI \u5bb9\u5668\u4e2d\u6ce8\u518c\u5b83\uff0c\u5982\u7b2c 24 \u7ae0\u6240\u793a\u3002<\/p>\n<\/li>\n<li>\n<p>Inject the IAuthorizationService into your endpoint handler.<br \/>\n\u5c06 IAuthorizationService \u6ce8\u5165\u5230\u7ec8\u7aef\u8282\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u3002<\/p>\n<\/li>\n<li>\n<p>Call IAuthorizationService.AuthorizeAsync(user, resource, policy), passing in the ClaimsPrincipal for the request, the resource to authorize access to, and the policy to apply.<br \/>\n\u8c03\u7528 IAuthorizationService.AuthorizeAsync\uff08user\uff0c resource\uff0c policy\uff09\uff0c\u4f20\u5165\u8bf7\u6c42\u7684 ClaimsPrincipal\u3001\u8981\u6388\u6743\u8bbf\u95ee\u7684\u8d44\u6e90\u4ee5\u53ca\u8981\u5e94\u7528\u7684\u7b56\u7565\u3002<\/p>\n<\/li>\n<\/ol>\n<p>The first step is identical to the process shown in chapter 24, so you can reuse the same authorization handlers whether you\u2019re using Razor Pages, minimal APIs, or both! You can access the IAuthorizationService from a minimal API endpoint using standard dependency injection (DI), which you learned about in chapters 8 and 9.<br \/>\n\u7b2c\u4e00\u6b65\u4e0e\u7b2c 24 \u7ae0\u4e2d\u6240\u793a\u7684\u8fc7\u7a0b\u76f8\u540c\uff0c\u56e0\u6b64\u65e0\u8bba\u60a8\u4f7f\u7528\u7684\u662f Razor Pages\u3001\u6700\u5c11\u7684 API\uff0c\u8fd8\u662f\u540c\u65f6\u4f7f\u7528\u8fd9\u4e24\u8005\uff0c\u60a8\u90fd\u53ef\u4ee5\u91cd\u590d\u4f7f\u7528\u76f8\u540c\u7684\u6388\u6743\u5904\u7406\u7a0b\u5e8f\uff01\u60a8\u53ef\u4ee5\u4f7f\u7528\u6807\u51c6\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165 \uff08DI\uff09 \u4ece\u6700\u5c0f API \u7ec8\u7aef\u8282\u70b9\u8bbf\u95ee IAuthorizationService\uff0c\u60a8\u5728\u7b2c 8 \u7ae0\u548c\u7b2c 9 \u7ae0\u4e2d\u5bf9\u6b64\u8fdb\u884c\u4e86\u4e86\u89e3\u3002<\/p>\n<p>Listing 25.3 shows an example minimal API endpoint that uses resource-based authorization to protect the \u201cdelete\u201d action for a recipe. The IAuthorizationService and HttpContext.User property are injected into the handler method along with the RecipeService. The endpoint then retrieves the recipe and calls AuthorizeAsync() to determine whether to continue with the delete or return a 403 Forbidden response.<br \/>\n\u6e05\u5355 25.3 \u663e\u793a\u4e86\u4e00\u4e2a\u793a\u4f8b\u6700\u5c0f API \u7aef\u70b9\uff0c\u5b83\u4f7f\u7528\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\u6765\u4fdd\u62a4\u914d\u65b9\u7684 \u201cdelete\u201d\u4f5c\u3002IAuthorizationService \u548c HttpContext.User \u5c5e\u6027\u4e0e RecipeService \u4e00\u8d77\u6ce8\u5165\u5904\u7406\u7a0b\u5e8f\u65b9\u6cd5\u4e2d\u3002\u7136\u540e\uff0c\u7ec8\u7aef\u8282\u70b9\u68c0\u7d22\u914d\u65b9\u5e76\u8c03\u7528 AuthorizeAsync\uff08\uff09 \u4ee5\u786e\u5b9a\u662f\u7ee7\u7eed\u5220\u9664\u8fd8\u662f\u8fd4\u56de 403 Forbidden \u54cd\u5e94\u3002<\/p>\n<p>Listing 25.3 Using resource authorization to protect a minimal API endpoint<br \/>\n\u6e05\u5355 25.3 \u4f7f\u7528\u8d44\u6e90\u6388\u6743\u4fdd\u62a4\u6700\u5c0f API \u7aef\u70b9<\/p>\n<pre><code>app.MapDelete(&quot;recipe\/{id}&quot;, async (\n    int id, RecipeService service,\n    IAuthorizationService authService,    #A\n    ClaimsPrincipal user) =&gt;    #B\n{\n    var recipe = await service.GetRecipe(id);    #C\n    var result = await authService.AuthorizeAsync(    #D\n        user, recipe, &quot;CanManageRecipe&quot;);    #D\n\n    if (!result.Succeeded)    #E\n    {    #E\n        return Results.Forbid();    #E\n    }    #E\n\n    await service.DeleteRecipe(id);  #F\n    return Results.NoContent();  #F\n});<\/code><\/pre>\n<p>\u2776 Injected to perform resource-based authorization<br \/>\n\u6ce8\u5165\u4ee5\u6267\u884c\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743<\/p>\n<p>\u2777 The HttpContext.User claims principal for the request<br \/>\nHttpContext.User \u58f0\u660e\u8bf7\u6c42\u7684\u4e3b\u4f53<\/p>\n<p>\u2778 Fetches the recipe to access<br \/>\n\u83b7\u53d6\u914d\u65b9\u4ee5\u8bbf\u95ee<\/p>\n<p>\u2779 Performs resource-based authorization, passing in the user, resource, and the policy name<br \/>\n\u6267\u884c\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\uff0c\u4f20\u5165\u7528\u6237\u3001\u8d44\u6e90\u548c\u7b56\u7565\u540d\u79f0<\/p>\n<p>\u277a If authorization failed, returns 403 Forbidden<br \/>\n\u5982\u679c\u6388\u6743\u5931\u8d25\uff0c\u5219\u8fd4\u56de 403 Forbidden<\/p>\n<p>\u277b If authorization succeeded, executes the endpoint as normal<br \/>\n\u5982\u679c\u6388\u6743\u6210\u529f\uff0c\u5219\u7167\u5e38\u6267\u884c\u7aef\u70b9<\/p>\n<p>As is common when you start adding functionality, the logic at the heart of the endpoint has become a bit muddled as the endpoint has grown. There are several possible approaches you could take now:<br \/>\n\u5f53\u60a8\u5f00\u59cb\u6dfb\u52a0\u529f\u80fd\u65f6\uff0c\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u968f\u7740\u7ec8\u7aef\u8282\u70b9\u7684\u589e\u957f\uff0c\u7ec8\u7aef\u8282\u70b9\u6838\u5fc3\u7684\u903b\u8f91\u53d8\u5f97\u6709\u70b9\u6df7\u4e71\u3002\u60a8\u73b0\u5728\u53ef\u4ee5\u91c7\u53d6\u51e0\u79cd\u53ef\u80fd\u7684\u65b9\u6cd5\uff1a<\/p>\n<p>\u2022  Do nothing. The logic isn\u2019t that confusing, and this is only one endpoint. This may be a good approach initially but can become problematic if the logic is duplicated across multiple endpoints.<br \/>\n\u4ec0\u4e48\u90fd\u4e0d\u505a\u3002\u903b\u8f91\u5e76\u4e0d\u90a3\u4e48\u4ee4\u4eba\u56f0\u60d1\uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7aef\u70b9\u3002\u8fd9\u5728\u6700\u521d\u53ef\u80fd\u662f\u4e00\u79cd\u5f88\u597d\u7684\u65b9\u6cd5\uff0c\u4f46\u5982\u679c logic \u5728\u591a\u4e2a endpoints \u4e4b\u95f4\u91cd\u590d\uff0c\u5219\u53ef\u80fd\u4f1a\u4ea7\u751f\u95ee\u9898\u3002<\/p>\n<p>\u2022  Pull the authorization out into a filter. As you saw in chapters 5 and 7, endpoint filters can be useful for extracting common cross-cutting concerns, such as validation and authorization. You may find that endpoint filters help reduce the duplication in your endpoint handlers, though this often comes at the expense of additional complexity in the filter itself, as well as a layer of indirection in your handlers. You can see this approach in the source code accompanying this chapter.<br \/>\n\u5c06\u6388\u6743\u62c9\u51fa\u5230\u8fc7\u6ee4\u5668\u4e2d\u3002\u6b63\u5982\u60a8\u5728\u7b2c 5 \u7ae0\u548c\u7b2c 7 \u7ae0\u4e2d\u770b\u5230\u7684\u90a3\u6837\uff0c\u7aef\u70b9\u8fc7\u6ee4\u5668\u53ef\u7528\u4e8e\u63d0\u53d6\u5e38\u89c1\u7684\u6a2a\u5207\u5173\u6ce8\u70b9\uff0c\u4f8b\u5982\u9a8c\u8bc1\u548c\u6388\u6743\u3002\u60a8\u53ef\u80fd\u4f1a\u53d1\u73b0\u7ec8\u7aef\u8282\u70b9\u7b5b\u9009\u6761\u4ef6\u6709\u52a9\u4e8e\u51cf\u5c11\u7ec8\u7aef\u8282\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u7684\u91cd\u590d\uff0c\u5c3d\u7ba1\u8fd9\u901a\u5e38\u662f\u4ee5\u7b5b\u9009\u6761\u4ef6\u672c\u8eab\u7684\u989d\u5916\u590d\u6742\u6027\u4ee5\u53ca\u5904\u7406\u7a0b\u5e8f\u4e2d\u7684\u95f4\u63a5\u5c42\u4e3a\u4ee3\u4ef7\u7684\u3002\u60a8\u53ef\u4ee5\u5728\u672c\u7ae0\u968f\u9644\u7684\u6e90\u4ee3\u7801\u4e2d\u770b\u5230\u8fd9\u79cd\u65b9\u6cd5\u3002<\/p>\n<p>\u2022  Push the authorization responsibilities down into the domain. Instead of performing the resource-based authorization in your endpoint handlers, you could run the checks inside the domain instead, in the RecipeService in this case. This has advantages, in that it often reduces duplication, keeps your endpoints simpler, and ensures that authorization checks are always applied regardless of how you call the domain methods.<br \/>\n\u5c06\u6388\u6743\u8d23\u4efb\u5411\u4e0b\u63a8\u9001\u5230\u57df\u4e2d\u3002\u60a8\u53ef\u4ee5\u5728\u57df\u5185\u8fd0\u884c\u68c0\u67e5\uff0c\u800c\u4e0d\u662f\u5728\u7ec8\u7aef\u8282\u70b9\u5904\u7406\u7a0b\u5e8f\u4e2d\u6267\u884c\u57fa\u4e8e\u8d44\u6e90\u7684\u6388\u6743\uff0c\u5728\u672c\u4f8b\u4e2d\u4e3a RecipeService\u3002\u8fd9\u6837\u505a\u7684\u597d\u5904\u662f\uff0c\u5b83\u901a\u5e38\u53ef\u4ee5\u51cf\u5c11\u91cd\u590d\uff0c\u4f7f\u60a8\u7684\u7aef\u70b9\u66f4\u7b80\u5355\uff0c\u5e76\u786e\u4fdd\u65e0\u8bba\u60a8\u5982\u4f55\u8c03\u7528\u57df\u65b9\u6cd5\uff0c\u90fd\u59cb\u7ec8\u5e94\u7528\u6388\u6743\u68c0\u67e5\u3002<\/p>\n<p>\u2022  The downside to this approach is that it may cause your domain\/application model to depend directly on ASP.NET Core-specific constructs such as IAuthorizationService. You can work around this by creating a wrapper fa\u00e7ade around the IAuthorizationService, but this may also add some complexity. Even if you take this approach, you typically want to apply declarative authorization policies to your endpoints as well to ensure that the endpoint executes only for users who could possibly be authorized.<br \/>\n\u6b64\u65b9\u6cd5\u7684\u7f3a\u70b9\u662f\uff0c\u5b83\u53ef\u80fd\u4f1a\u5bfc\u81f4\u57df\/\u5e94\u7528\u7a0b\u5e8f\u6a21\u578b\u76f4\u63a5\u4f9d\u8d56\u4e8e\u7279\u5b9a\u4e8e ASP.NET Core \u7684\u6784\u9020\uff0c\u4f8b\u5982 IAuthorizationService\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u56f4\u7ed5 IAuthorizationService \u521b\u5efa\u5305\u88c5\u5668\u5916\u89c2\u6765\u89e3\u51b3\u6b64\u95ee\u9898\uff0c\u4f46\u8fd9\u4e5f\u53ef\u80fd\u589e\u52a0\u4e00\u4e9b\u590d\u6742\u6027\u3002\u5373\u4f7f\u60a8\u91c7\u7528\u6b64\u65b9\u6cd5\uff0c\u60a8\u901a\u5e38\u4e5f\u5e0c\u671b\u5c06\u58f0\u660e\u5f0f\u6388\u6743\u7b56\u7565\u5e94\u7528\u4e8e\u7ec8\u7aef\u8282\u70b9\uff0c\u4ee5\u786e\u4fdd\u7ec8\u7aef\u8282\u70b9\u4ec5\u5bf9\u53ef\u80fd\u83b7\u5f97\u6388\u6743\u7684\u7528\u6237\u6267\u884c\u3002<\/p>\n<p>There\u2019s no single best answer on which approach to take; it will vary depending on what works best for your application. Authentication and authorization are inevitably tricky subjects, so it\u2019s important to consider them early and design your application with security in mind.<br \/>\n\u5173\u4e8e\u91c7\u53d6\u54ea\u79cd\u65b9\u6cd5\uff0c\u6ca1\u6709\u5355\u4e00\u7684\u6700\u4f73\u7b54\u6848;\u5b83\u4f1a\u6839\u636e\u6700\u9002\u5408\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u65b9\u6cd5\u800c\u6709\u6240\u4e0d\u540c\u3002\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u4e0d\u53ef\u907f\u514d\u5730\u662f\u68d8\u624b\u7684\u4e3b\u9898\uff0c\u56e0\u6b64\u5c3d\u65e9\u8003\u8651\u5b83\u4eec\u5e76\u5728\u8bbe\u8ba1\u5e94\u7528\u7a0b\u5e8f\u65f6\u8003\u8651\u5b89\u5168\u6027\u975e\u5e38\u91cd\u8981\u3002<\/p>\n<blockquote>\n<p>Scope-based authorization policies<br \/>\n\u57fa\u4e8e\u8303\u56f4\u7684\u6388\u6743\u7b56\u7565<\/p>\n<p>In section 15.2 I described the role of scopes in the authentication process. When you obtain a bearer token from an identity provider\u2014whether you\u2019re using OpenID Connect or OAuth 2.0\u2014you define the scopes that you wish to retrieve. The user can then choose to grant or deny some or all of those requested scopes. Additionally, the identity provider might allow certain client applications access only to specific scopes. The final access token you receive from the identity provider, which is sent to the API, may have some or none of the requested scopes.<br \/>\n\u5728 Section 15.2 \u4e2d\uff0c\u6211\u63cf\u8ff0\u4e86\u8303\u56f4\u5728\u8eab\u4efd\u9a8c\u8bc1\u8fc7\u7a0b\u4e2d\u7684\u4f5c\u7528\u3002\u5f53\u60a8\u4ece\u8eab\u4efd\u63d0\u4f9b\u5546\u5904\u83b7\u53d6\u4e0d\u8bb0\u540d\u4ee4\u724c\u65f6\uff08\u65e0\u8bba\u60a8\u4f7f\u7528\u7684\u662f OpenID Connect \u8fd8\u662f OAuth 2.0\uff09\uff0c\u60a8\u90fd\u53ef\u4ee5\u5b9a\u4e49\u8981\u68c0\u7d22\u7684\u8303\u56f4\u3002\u7136\u540e\uff0c\u7528\u6237\u53ef\u4ee5\u9009\u62e9\u6388\u4e88\u6216\u62d2\u7edd\u90e8\u5206\u6216\u5168\u90e8\u8bf7\u6c42\u7684\u8303\u56f4\u3002\u6b64\u5916\uff0c\u8eab\u4efd\u63d0\u4f9b\u5546\u53ef\u80fd\u4ec5\u5141\u8bb8\u67d0\u4e9b\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee\u7279\u5b9a\u8303\u56f4\u3002\u60a8\u4ece\u8eab\u4efd\u63d0\u4f9b\u5546\u5904\u6536\u5230\u7684\u6700\u7ec8\u8bbf\u95ee\u4ee4\u724c\uff08\u53d1\u9001\u5230 API\uff09\u53ef\u80fd\u5177\u6709\u90e8\u5206\u6216\u6ca1\u6709\u8bf7\u6c42\u7684\u8303\u56f4\u3002<\/p>\n<p>It\u2019s up to the API itself to decide what each scope means and how it should be used to enforce authorization policies. Scopes have no inherent functionality on their own, much like claims, but you can build functionality on top. For example, you can create authorization polices that require a token has the scope &quot;recipe.edit&quot; using<br \/>\n\u7531 API \u672c\u8eab\u51b3\u5b9a\u6bcf\u4e2a\u8303\u56f4\u7684\u542b\u4e49\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u6765\u5b9e\u65bd\u6388\u6743\u7b56\u7565\u3002\u8303\u56f4\u672c\u8eab\u6ca1\u6709\u56fa\u6709\u7684\u529f\u80fd\uff0c\u5c31\u50cf\u58f0\u660e\u4e00\u6837\uff0c\u4f46\u4f60\u53ef\u4ee5\u5728\u5176\u4e0a\u6784\u5efa\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528<\/p>\n<\/blockquote>\n<pre><code>builder.Services.AddAuthorizationBuilder()\n.AddPolicy(&quot;RecipeEditScope&quot;, policy =&gt;\npolicy.RequireClaim(&quot;scope&quot;, &quot; recipe.edit &quot;));<\/code><\/pre>\n<blockquote>\n<p>This policy could then be applied to any endpoints that edit a recipe.<br \/>\n\u7136\u540e\uff0c\u6b64\u7b56\u7565\u53ef\u5e94\u7528\u4e8e\u7f16\u8f91\u914d\u65b9\u7684\u4efb\u4f55\u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n<p>Another common pattern is to require a specific scope for you to be authorized to make any requests to a given ASP.NET Core app, such as a &quot;receipeApi&quot; scope. This approach can often replace audience validation in bearer token authorization and may be more flexible, as it doesn\u2019t require your identity provider to know the domain at which your API app will be hosted.<br \/>\n\u53e6\u4e00\u79cd\u5e38\u89c1\u6a21\u5f0f\u662f\u8981\u6c42\u7279\u5b9a\u8303\u56f4\uff0c\u4ee5\u4fbf\u60a8\u6709\u6743\u5411\u7ed9\u5b9a\u7684 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u53d1\u51fa\u4efb\u4f55\u8bf7\u6c42\uff0c\u4f8b\u5982\u201creceipeApi\u201d\u8303\u56f4\u3002\u8fd9\u79cd\u65b9\u6cd5\u901a\u5e38\u53ef\u4ee5\u53d6\u4ee3\u4e0d\u8bb0\u540d\u4ee4\u724c\u6388\u6743\u4e2d\u7684\u53d7\u4f17\u9a8c\u8bc1\uff0c\u5e76\u4e14\u53ef\u80fd\u66f4\u7075\u6d3b\uff0c\u56e0\u4e3a\u5b83\u4e0d\u9700\u8981\u60a8\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\u77e5\u9053\u5c06\u6258\u7ba1\u60a8\u7684 API \u5e94\u7528\u7a0b\u5e8f\u7684\u57df\u3002<\/p>\n<p>Alternatively, you can use scopes to partition your APIs into groups that can only be accessed by certain types of clients. For example, you might have one set of APIs that can be accessed only by internal machine-to-machine clients, another set that can be accessed only by admin users, and another set that can be accessed only by nonadmin users.<br \/>\n\u6216\u8005\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8303\u56f4\u5c06 API \u5212\u5206\u4e3a\u53ea\u80fd\u7531\u67d0\u4e9b\u7c7b\u578b\u7684\u5ba2\u6237\u7aef\u8bbf\u95ee\u7684\u7ec4\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u6709\u4e00\u7ec4\u53ea\u80fd\u7531\u5185\u90e8\u8ba1\u7b97\u673a\u5230\u8ba1\u7b97\u673a\u5ba2\u6237\u7aef\u8bbf\u95ee\u7684 API\uff0c\u53e6\u4e00\u7ec4\u53ea\u80fd\u7531\u7ba1\u7406\u5458\u7528\u6237\u8bbf\u95ee\uff0c\u53e6\u4e00\u7ec4\u53ea\u80fd\u7531\u975e\u7ba1\u7406\u5458\u7528\u6237\u8bbf\u95ee\u3002<\/p>\n<p>Duende has many practical examples of approaches to authorization and authentication using OpenID Connect at <a href=\"http:\/\/mng.bz\/o1Jp\">http:\/\/mng.bz\/o1Jp<\/a>. The examples are geared to IdentityServer users but show many best practices and patterns you can use with identity provider services as well.<br \/>\nDuende \u5728 <a href=\"http:\/\/mng.bz\/o1Jp\">http:\/\/mng.bz\/o1Jp<\/a> \u4e0a\u63d0\u4f9b\u4e86\u8bb8\u591a\u4f7f\u7528 OpenID Connect \u8fdb\u884c\u6388\u6743\u548c\u8eab\u4efd\u9a8c\u8bc1\u7684\u65b9\u6cd5\u7684\u5b9e\u9645\u793a\u4f8b\u3002\u8fd9\u4e9b\u793a\u4f8b\u9762\u5411 IdentityServer \u7528\u6237\uff0c\u4f46\u4e5f\u5c55\u793a\u4e86\u8bb8\u591a\u53ef\u7528\u4e8e\u8eab\u4efd\u63d0\u4f9b\u5546\u670d\u52a1\u7684\u6700\u4f73\u5b9e\u8df5\u548c\u6a21\u5f0f\u3002<\/p>\n<\/blockquote>\n<p>That brings us to the end of this chapter on authentication and authorization. We\u2019re not completely done with security, though; in chapter 27 we look at potential security threats and how to mitigate them. But first, in chapter 26 you\u2019ll learn about the logging abstractions in ASP.NET Core and how you can use them to keep tabs on exactly what your app\u2019s up to.<br \/>\n\u8fd9\u5c06\u6211\u4eec\u5e26\u5230\u4e86\u672c\u7ae0\u5173\u4e8e\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7684\u7ed3\u5c3e\u3002\u4e0d\u8fc7\uff0c\u6211\u4eec\u8fd8\u6ca1\u6709\u5b8c\u5168\u5b8c\u6210\u5b89\u5168\u6027;\u5728\u7b2c 27 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u6f5c\u5728\u7684\u5b89\u5168\u5a01\u80c1\u4ee5\u53ca\u5982\u4f55\u7f13\u89e3\u8fd9\u4e9b\u5a01\u80c1\u3002\u4f46\u9996\u5148\uff0c\u5728\u7b2c 26 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 ASP.NET Core \u4e2d\u7684\u65e5\u5fd7\u8bb0\u5f55\u62bd\u8c61\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u4eec\u6765\u5bc6\u5207\u5173\u6ce8\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u786e\u5207\u52a8\u6001\u3002<\/p>\n<h2>25.7 Summary<\/h2>\n<p>25.7 \u603b\u7ed3<\/p>\n<p>In large systems with multiple applications or APIs, you can use an identity provider to centralize authentication and user management. This often reduces the authentication responsibilities of apps, reducing duplication and making it easier to add new user management features.<br \/>\n\u5728\u5177\u6709\u591a\u4e2a\u5e94\u7528\u7a0b\u5e8f\u6216 API \u7684\u5927\u578b\u7cfb\u7edf\u4e2d\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8eab\u4efd\u63d0\u4f9b\u5546\u6765\u96c6\u4e2d\u8eab\u4efd\u9a8c\u8bc1\u548c\u7528\u6237\u7ba1\u7406\u3002\u8fd9\u901a\u5e38\u53ef\u4ee5\u51cf\u5c11\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\u8d23\u4efb\uff0c\u51cf\u5c11\u91cd\u590d\uff0c\u5e76\u66f4\u8f7b\u677e\u5730\u6dfb\u52a0\u65b0\u7684\u7528\u6237\u7ba1\u7406\u529f\u80fd\u3002<\/p>\n<p>You should strongly consider using a third-party identity provider service instead of building your own. User management is rarely core to your business, and by delegating responsibility to a third-party you can leave protecting your most vulnerable assets to the experts.<br \/>\n\u60a8\u5e94\u8be5\u5f3a\u70c8\u8003\u8651\u4f7f\u7528\u7b2c\u4e09\u65b9\u8eab\u4efd\u63d0\u4f9b\u5546\u670d\u52a1\uff0c\u800c\u4e0d\u662f\u6784\u5efa\u81ea\u5df1\u7684\u670d\u52a1\u3002\u7528\u6237\u7ba1\u7406\u5f88\u5c11\u662f\u60a8\u7684\u4e1a\u52a1\u6838\u5fc3\uff0c\u901a\u8fc7\u5c06\u8d23\u4efb\u59d4\u6258\u7ed9\u7b2c\u4e09\u65b9\uff0c\u60a8\u53ef\u4ee5\u5c06\u4fdd\u62a4\u6700\u8106\u5f31\u7684\u8d44\u4ea7\u7684\u5de5\u4f5c\u7559\u7ed9\u4e13\u5bb6\u3002<\/p>\n<p>If you do need to build your own identity provider, you can use the IdentityServer or OpenIddict library. These libraries implement the OpenID Connect protocol, adding token generation to a standard ASP.NET Core application. You must build the user management and UI components yourself.<br \/>\n\u5982\u679c\u60a8\u786e\u5b9e\u9700\u8981\u6784\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 IdentityServer \u6216 OpenIddict \u5e93\u3002\u8fd9\u4e9b\u5e93\u5b9e\u73b0 OpenID Connect \u534f\u8bae\uff0c\u5c06\u4ee4\u724c\u751f\u6210\u6dfb\u52a0\u5230\u6807\u51c6 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002\u60a8\u5fc5\u987b\u81ea\u5df1\u6784\u5efa\u7528\u6237\u7ba1\u7406\u548c UI \u7ec4\u4ef6\u3002<\/p>\n<p>OAuth 2.0 is an authorization protocol that allows a user to delegate authorization for accessing a resource to another application. This standard allows applications to interoperate without compromising on security.<br \/>\nOAuth 2.0 \u662f\u4e00\u79cd\u6388\u6743\u534f\u8bae\uff0c\u5141\u8bb8\u7528\u6237\u5c06\u8bbf\u95ee\u8d44\u6e90\u7684\u6388\u6743\u59d4\u6258\u7ed9\u53e6\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u3002\u6b64\u6807\u51c6\u5141\u8bb8\u5e94\u7528\u7a0b\u5e8f\u5728\u4e0d\u5f71\u54cd\u5b89\u5168\u6027\u7684\u60c5\u51b5\u4e0b\u8fdb\u884c\u4e92\u4f5c\u3002<\/p>\n<p>OAuth 2.0 has multiple grant types representing common authorization flows. The authorization code flow with PKCE is the most common interactive grant type when a user initiates an interaction. For machine-only workflows, such as an API calling another API, you can use the client credentials grant type.<br \/>\nOAuth 2.0 \u5177\u6709\u591a\u79cd\u6388\u6743\u7c7b\u578b\uff0c\u4ee3\u8868\u5e38\u89c1\u7684\u6388\u6743\u6d41\u7a0b\u3002\u5f53\u7528\u6237\u53d1\u8d77\u4ea4\u4e92\u65f6\uff0c\u4f7f\u7528 PKCE \u7684\u6388\u6743\u4ee3\u7801\u6d41\u662f\u6700\u5e38\u89c1\u7684\u4ea4\u4e92\u5f0f\u6388\u6743\u7c7b\u578b\u3002\u5bf9\u4e8e\u4ec5\u9650\u8ba1\u7b97\u673a\u7684\u5de5\u4f5c\u6d41\uff0c\u4f8b\u5982\u8c03\u7528\u5176\u4ed6 API \u7684 API\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u5ba2\u6237\u7aef\u51ed\u8bc1\u6388\u6743\u7c7b\u578b\u3002<\/p>\n<p>OpenID Connect is built on top of OAuth 2.0. It adds conventions, discoverability, and authentication to OAuth 2.0, making it easier to interact with third-party providers and retrieve identity information about a user.<br \/>\nOpenID Connect \u57fa\u4e8e OAuth 2.0 \u6784\u5efa\u3002\u5b83\u4e3a OAuth 2.0 \u6dfb\u52a0\u4e86\u7ea6\u5b9a\u3001\u53ef\u53d1\u73b0\u6027\u548c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4ece\u800c\u53ef\u4ee5\u66f4\u8f7b\u677e\u5730\u4e0e\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u4ea4\u4e92\u5e76\u68c0\u7d22\u6709\u5173\u7528\u6237\u7684\u8eab\u4efd\u4fe1\u606f\u3002<\/p>\n<p>JWTs are the most common bearer token format. They consist of a header, a payload, and a signature, and are base64-encoded. When receiving a JWT you must always verify the signature to ensure that it hasn\u2019t been tampered with.<br \/>\nJWT \u662f\u6700\u5e38\u89c1\u7684\u4e0d\u8bb0\u540d\u4ee4\u724c\u683c\u5f0f\u3002\u5b83\u4eec\u7531\u6807\u5934\u3001\u6709\u6548\u8d1f\u8f7d\u548c\u7b7e\u540d\u7ec4\u6210\uff0c\u5e76\u4e14\u91c7\u7528 base64 \u7f16\u7801\u3002\u6536\u5230 JWT \u65f6\uff0c\u60a8\u5fc5\u987b\u59cb\u7ec8\u9a8c\u8bc1\u7b7e\u540d\u4ee5\u786e\u4fdd\u5b83\u672a\u88ab\u7be1\u6539\u3002<\/p>\n<p>JWTs are not encrypted, so anyone can read them by default. JWE is a standard that wraps the JWT and encrypts it, protecting the contents. Many identity providers support generating JWEs, and ASP.NET Core supports decoding JWEs automatically.<br \/>\nJWT \u672a\u52a0\u5bc6\uff0c\u56e0\u6b64\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u8bfb\u53d6\u5b83\u4eec\u3002JWE \u662f\u4e00\u79cd\u5305\u88c5 JWT \u5e76\u5bf9\u5176\u8fdb\u884c\u52a0\u5bc6\u7684\u6807\u51c6\uff0c\u53ef\u4fdd\u62a4\u5176\u5185\u5bb9\u3002\u8bb8\u591a\u8eab\u4efd\u63d0\u4f9b\u5546\u652f\u6301\u751f\u6210 JWE\uff0c\u800c ASP.NET Core \u652f\u6301\u81ea\u52a8\u89e3\u7801 JWE\u3002<\/p>\n<p>Bearer token authentication in ASP.NET Core is similar to cookie authentication with traditional web apps. The authentication middleware deserializes the token and validates it. If the token is valid, the middleware creates a ClaimsPrincipal and sets HttpContext.User.<br \/>\nASP.NET Core \u4e2d\u7684\u6301\u6709\u8005\u4ee4\u724c\u8eab\u4efd\u9a8c\u8bc1\u7c7b\u4f3c\u4e8e\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u7684 Cookie \u8eab\u4efd\u9a8c\u8bc1\u3002\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u53cd\u5e8f\u5217\u5316\u4ee4\u724c\u5e76\u5bf9\u5176\u8fdb\u884c\u9a8c\u8bc1\u3002\u5982\u679c\u4ee4\u724c\u6709\u6548\uff0c\u4e2d\u95f4\u4ef6\u5c06\u521b\u5efa\u4e00\u4e2a ClaimsPrincipal \u5e76\u8bbe\u7f6e HttpContext.User\u3002<\/p>\n<p>Configure JWT bearer authentication by adding the Microsoft.AspNetCore.Authentication.JwtBearer NuGet Package and calling AddAuthentication().AddJwtBearer() to add the required services to your app.<br \/>\n\u901a\u8fc7\u6dfb\u52a0 Microsoft.AspNetCore.Authentication.JwtBearer NuGet \u5305\u5e76\u8c03\u7528 AddAuthentication\uff08\uff09 \u6765\u914d\u7f6e JWT \u4e0d\u8bb0\u540d\u8eab\u4efd\u9a8c\u8bc1\u3002AddJwtBearer\uff08\uff09 \u5c06\u6240\u9700\u7684\u670d\u52a1\u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002<\/p>\n<p>To generate a JWT for local testing, run dotnet user-jwts create. This configures your API to support JWTs created by the tool and prints a token to the terminal, which you can use for local testing of your API. Add the token to requests in the Authorization header, using the format &quot;Bearer <code>&lt;token&gt;<\/code>&quot;.<br \/>\n\u8981\u751f\u6210\u7528\u4e8e\u672c\u5730\u6d4b\u8bd5\u7684 JWT\uff0c\u8bf7\u8fd0\u884c dotnet user-jwts create\u3002\u8fd9\u4f1a\u5c06\u60a8\u7684 API \u914d\u7f6e\u4e3a\u652f\u6301\u8be5\u5de5\u5177\u521b\u5efa\u7684 JWT\uff0c\u5e76\u5c06\u4ee4\u724c\u6253\u5370\u5230\u7ec8\u7aef\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8be5\u4ee4\u724c\u5bf9 API \u8fdb\u884c\u672c\u5730\u6d4b\u8bd5\u3002\u4f7f\u7528 \u201cBearer <code>&lt;token&gt;<\/code>\u201d \u683c\u5f0f\u5c06\u4ee4\u724c\u6dfb\u52a0\u5230 Authorization \u6807\u5934\u4e2d\u7684\u8bf7\u6c42\u3002<\/p>\n<p>Pass additional options to the dotnet user-jwts create command to customize the generated JWT. Add extra claims to the generated JWT using the --claim option, change the sub claim name using --name, or add scope claims to the JWT using --scope.<br \/>\n\u5c06\u5176\u4ed6\u9009\u9879\u4f20\u9012\u7ed9 dotnet user-jwts create \u547d\u4ee4\u4ee5\u81ea\u5b9a\u4e49\u751f\u6210\u7684 JWT\u3002\u4f7f\u7528 --claim \u9009\u9879\u5411\u751f\u6210\u7684 JWT \u6dfb\u52a0\u989d\u5916\u7684\u58f0\u660e\uff0c\u4f7f\u7528 --name \u66f4\u6539\u5b50\u58f0\u660e\u540d\u79f0\uff0c\u6216\u4f7f\u7528 --scope \u5411 JWT \u6dfb\u52a0\u8303\u56f4\u58f0\u660e\u3002<\/p>\n<p>To enable authorization in Swagger UI, you should add a security scheme to your OpenAPI document. Create an OpenApiSecurityScheme object, and register it with the OpenAPI document by calling AddSecurityDefinition(). Apply it to all the APIs in your app by calling AddSecurityRequirement(), passing in the scheme object.<br \/>\n\u8981\u5728 Swagger UI \u4e2d\u542f\u7528\u6388\u6743\uff0c\u60a8\u5e94\u8be5\u5411 OpenAPI \u6587\u6863\u6dfb\u52a0\u5b89\u5168\u65b9\u6848\u3002\u521b\u5efa\u4e00\u4e2a OpenApiSecurityScheme \u5bf9\u8c61\uff0c\u5e76\u901a\u8fc7\u8c03\u7528 AddSecurityDefinition\uff08\uff09 \u5c06\u5176\u6ce8\u518c\u5230 OpenAPI \u6587\u6863\u4e2d\u3002\u901a\u8fc7\u8c03\u7528 AddSecurityRequirement\uff08\uff09 \u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u5e94\u7528\u4e2d\u7684\u6240\u6709 API\uff0c\u5e76\u4f20\u5165 scheme \u5bf9\u8c61\u3002<\/p>\n<p>To add authorization to minimal API endpoints, call RequireAuthorization() or add the [Authorize] attribute to your endpoint handler. This optionally takes the name of an authorization policy to apply, n the same way as you would apply policies to Razor Pages and MVC controllers. You can call RequireAuthorization() on route groups to apply authorization to multiple APIs at the same time.<br \/>\n\u82e5\u8981\u5411\u6700\u5c0f API \u7ec8\u7ed3\u70b9\u6dfb\u52a0\u6388\u6743\uff0c\u8bf7\u8c03\u7528 RequireAuthorization\uff08\uff09 \u6216\u5c06 [Authorize] \u5c5e\u6027\u6dfb\u52a0\u5230\u7ec8\u7ed3\u70b9\u5904\u7406\u7a0b\u5e8f\u3002\u8fd9\u53ef\u4ee5\u9009\u62e9\u91c7\u7528\u8981\u5e94\u7528\u7684\u6388\u6743\u7b56\u7565\u7684\u540d\u79f0\uff0c\u5176\u65b9\u5f0f\u4e0e\u5c06\u7b56\u7565\u5e94\u7528\u4e8e Razor Pages \u548c MVC \u63a7\u5236\u5668\u7684\u65b9\u5f0f\u76f8\u540c\u3002\u60a8\u53ef\u4ee5\u5728\u8def\u7531\u7ec4\u4e0a\u8c03\u7528 RequireAuthorization\uff08\uff09 \u4ee5\u540c\u65f6\u5c06\u6388\u6743\u5e94\u7528\u4e8e\u591a\u4e2a API\u3002<\/p>\n<p>Override an authorization requirement on an endpoint by calling AllowAnonymous() or by adding the [AllowAnonymous] attribute to an endpoint handler. This removes any authentication requirements from the endpoint, so users can call the endpoint without a bearer token in the request.<br \/>\n\u901a\u8fc7\u8c03\u7528 AllowAnonymous\uff08\uff09 \u6216\u5c06 [AllowAnonymous] \u5c5e\u6027\u6dfb\u52a0\u5230\u7ec8\u7ed3\u70b9\u5904\u7406\u7a0b\u5e8f\u6765\u66ff\u4ee3\u7ec8\u7ed3\u70b9\u4e0a\u7684\u6388\u6743\u8981\u6c42\u3002\u8fd9\u5c06\u5220\u9664\u7ec8\u7aef\u8282\u70b9\u4e2d\u7684\u4efb\u4f55\u8eab\u4efd\u9a8c\u8bc1\u8981\u6c42\uff0c\u56e0\u6b64\u7528\u6237\u53ef\u4ee5\u5728\u8bf7\u6c42\u4e2d\u6ca1\u6709\u6301\u6709\u8005\u4ee4\u724c\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\u7ec8\u7aef\u8282\u70b9\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>25 Authentication and authorization for APIs 25 API \u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743 This chapter covers \u672c\u7ae0\u6db5\u76d6 \u2022 Seeing how authentication works for APIs in ASP.NET Core \u4e86\u89e3 ASP.NET Core\u4e2d API \u7684\u8eab\u4efd\u9a8c\u8bc1\u5de5\u4f5c\u539f\u7406 \u2022 Using bearer tokens for authentication \u4f7f\u7528\u4e0d\u8bb0\u540d\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1 \u2022 Testing APIs locally with JSON Web Tokens \u4f7f\u7528 JSON Web \u4ee4\u724c\u5728\u672c\u5730\u6d4b\u8bd5 API \u2022 Applying authorization policies to minimal APIs [&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-621","post","type-post","status-publish","format-standard","hentry","category-csharp"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/621","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=621"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/621\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=621"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=621"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=621"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}