{"id":617,"date":"2025-04-05T11:42:36","date_gmt":"2025-04-05T03:42:36","guid":{"rendered":"https:\/\/www.hyy.net\/?p=617"},"modified":"2025-04-05T11:42:36","modified_gmt":"2025-04-05T03:42:36","slug":"asp-net-core-in-action-23-authentication-adding-users-to-your-application-with-identity","status":"publish","type":"post","link":"https:\/\/diji.net\/?p=617","title":{"rendered":"ASP.NET Core in Action 23 Authentication: Adding users to your application with Identity"},"content":{"rendered":"<p>Part 4 Securing and deploying your applications<br \/>\n\u7b2c 4 \u90e8\u5206\uff1a\u4fdd\u62a4\u548c\u90e8\u7f72\u5e94\u7528\u7a0b\u5e8f<\/p>\n<p>So far in the book you\u2019ve learned how to use minimal APIs,Razor Pages, and Model-View-Controller (MVC) controllers to build both server-rendered applications and APIs. You know how to dynamically generate JavaScript Object Notation (JSON) and HTML code based on incoming requests, and how to use configuration and dependency injection to customize your app\u2019s behavior at runtime. In part 4 you\u2019ll learn how to add users and profiles to your app and how to publish and secure your apps.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u5728\u672c\u4e66\u4e2d\uff0c\u60a8\u5df2\u7ecf\u5b66\u4e60\u4e86\u5982\u4f55\u4f7f\u7528\u6700\u5c11\u7684 API\u3001Razor Pages \u548c\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u63a7\u5236\u5668\u6765\u6784\u5efa\u670d\u52a1\u5668\u6e32\u67d3\u7684\u5e94\u7528\u7a0b\u5e8f\u548c API\u3002\u60a8\u77e5\u9053\u5982\u4f55\u6839\u636e\u4f20\u5165\u8bf7\u6c42\u52a8\u6001\u751f\u6210 JavaScript \u5bf9\u8c61\u8868\u793a\u6cd5 \uff08JSON\uff09 \u548c HTML \u4ee3\u7801\uff0c\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u914d\u7f6e\u548c\u4f9d\u8d56\u9879\u6ce8\u5165\u6765\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u7684\u884c\u4e3a\u3002\u5728\u7b2c 4 \u90e8\u5206\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5c06\u7528\u6237\u548c\u914d\u7f6e\u6587\u4ef6\u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u53ca\u5982\u4f55\u53d1\u5e03\u548c\u4fdd\u62a4\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>In chapters 23 through 25 you\u2019ll learn how to protect your applications with authentication and authorization. In chapter 23 you\u2019ll see how you can add ASP.NET Core Identity to your apps so that users can log in and enjoy a customized experience. You\u2019ll learn how to protect your Razor Pages apps using authorization in chapter 24 so that only some users can access certain pages in your app. In chapter 25 you\u2019ll learn how to apply the same protections to your minimal API and web API applications.<br \/>\n\u5728\u7b2c 23 \u7ae0\u5230\u7b2c 25 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u4fdd\u62a4\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u5728\u7b2c 23 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5c06 ASP.NET Core Identity \u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\uff0c\u4ee5\u4fbf\u7528\u6237\u53ef\u4ee5\u767b\u5f55\u5e76\u4eab\u53d7\u81ea\u5b9a\u4e49\u4f53\u9a8c\u3002\u60a8\u5c06\u5728\u7b2c 24 \u7ae0\u4e2d\u4e86\u89e3\u5982\u4f55\u4f7f\u7528\u6388\u6743\u4fdd\u62a4 Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff0c\u4ee5\u4fbf\u53ea\u6709\u90e8\u5206\u7528\u6237\u53ef\u4ee5\u8bbf\u95ee\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u67d0\u4e9b\u9875\u9762\u3002\u5728\u7b2c 25 \u7ae0\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u5c06\u76f8\u540c\u7684\u4fdd\u62a4\u5e94\u7528\u4e8e\u60a8\u7684\u6700\u5c0f API \u548c Web API \u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>Adding logging to your application is one of those activities that\u2019s often left until after you discover a problem in production. Adding sensible logging from the get-go will help you quickly diagnose and fix errors as they arise. Chapter 26 introduces the logging framework built into ASP.NET Core. You\u2019ll see how you can use it to write log  messages to a wide variety of locations, whether it\u2019s the console, a file, or a third-party remote-logging service.<br \/>\n\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u65e5\u5fd7\u8bb0\u5f55\u662f\u901a\u5e38\u8981\u7b49\u5230\u60a8\u5728\u751f\u4ea7\u4e2d\u53d1\u73b0\u95ee\u9898\u540e\u624d\u8fdb\u884c\u7684\u6d3b\u52a8\u4e4b\u4e00\u3002\u4ece\u4e00\u5f00\u59cb\u5c31\u6dfb\u52a0\u5408\u7406\u7684\u65e5\u5fd7\u8bb0\u5f55\u5c06\u5e2e\u52a9\u60a8\u5feb\u901f\u8bca\u65ad\u548c\u4fee\u590d\u51fa\u73b0\u7684\u9519\u8bef\u3002\u7b2c 26 \u7ae0\u4ecb\u7ecd\u4e86 ASP.NET Core \u4e2d\u5185\u7f6e\u7684\u65e5\u5fd7\u8bb0\u5f55\u6846\u67b6\u3002\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u4f7f\u7528\u5b83\u5c06\u65e5\u5fd7\u6d88\u606f\u5199\u5165\u5404\u79cd\u4f4d\u7f6e\uff0c\u65e0\u8bba\u662f\u63a7\u5236\u53f0\u3001\u6587\u4ef6\u8fd8\u662f\u7b2c\u4e09\u65b9\u8fdc\u7a0b\u65e5\u5fd7\u8bb0\u5f55\u670d\u52a1\u3002<\/p>\n<p>By this point you\u2019ll have all the fundamentals to build a production application with ASP.NET Core. In chapter 27 I cover the steps required to make your app live, including how to publish an app to Internet Information Services (IIS) and how to configure the URLs your app listens on.<br \/>\n\u6b64\u65f6\uff0c\u60a8\u5c06\u62e5\u6709\u4f7f\u7528 ASP.NET Core \u6784\u5efa\u751f\u4ea7\u5e94\u7528\u7a0b\u5e8f\u7684\u6240\u6709\u57fa\u7840\u77e5\u8bc6\u3002\u5728\u7b2c 27 \u7ae0\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u4f7f\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e0a\u7ebf\u6240\u9700\u7684\u6b65\u9aa4\uff0c\u5305\u62ec\u5982\u4f55\u5c06\u5e94\u7528\u7a0b\u5e8f\u53d1\u5e03\u5230 Internet Information Services \uff08IIS\uff09 \u4ee5\u53ca\u5982\u4f55\u914d\u7f6e\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4fa6\u542c\u7684 URL\u3002<\/p>\n<p>Before you expose your application to the world, an important part of web development is securing your app correctly. Even if you don\u2019t feel you have any sensitive data in your application, you must make sure to protect your users from attacks by adhering to security best practices. You\u2019ll learn how to configure HTTPS for your application in chapter 28 and why this is a vital step for modern web development. Similarly, in chapter 29 I describe some common security vulnerabilities, how attackers can exploit them, and what you can do to protect your applications.<br \/>\n\u5728\u5411\u5168\u4e16\u754c\u516c\u5f00\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e4b\u524d\uff0cWeb \u5f00\u53d1\u7684\u4e00\u4e2a\u91cd\u8981\u90e8\u5206\u662f\u6b63\u786e\u4fdd\u62a4\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u5373\u4f7f\u60a8\u8ba4\u4e3a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u6ca1\u6709\u4efb\u4f55\u654f\u611f\u6570\u636e\uff0c\u4e5f\u5fc5\u987b\u786e\u4fdd\u901a\u8fc7\u9075\u5b88\u5b89\u5168\u6700\u4f73\u5b9e\u8df5\u6765\u4fdd\u62a4\u60a8\u7684\u7528\u6237\u514d\u53d7\u653b\u51fb\u3002\u60a8\u5c06\u5728\u7b2c 28 \u7ae0\u4e2d\u5b66\u4e60\u5982\u4f55\u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e HTTPS\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u8fd9\u662f\u73b0\u4ee3 Web \u5f00\u53d1\u7684\u5173\u952e\u6b65\u9aa4\u3002\u540c\u6837\uff0c\u5728\u7b2c 29 \u7ae0\u4e2d\uff0c\u6211\u63cf\u8ff0\u4e86\u4e00\u4e9b\u5e38\u89c1\u7684\u5b89\u5168\u6f0f\u6d1e\uff0c\u653b\u51fb\u8005\u5982\u4f55\u5229\u7528\u5b83\u4eec\uff0c\u4ee5\u53ca\u60a8\u53ef\u4ee5\u91c7\u53d6\u54ea\u4e9b\u63aa\u65bd\u6765\u4fdd\u62a4\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p>23 Authentication: Adding users to your application with Identity<br \/>\n23 \u8eab\u4efd\u9a8c\u8bc1\uff1a\u4f7f\u7528 Identity \u5c06\u7528\u6237\u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f<\/p>\n<p>This chapter covers<br \/>\n\u672c\u7ae0\u4ecb\u7ecd<\/p>\n<p>\u2022  Seeing how authentication works in web apps in ASP.NET Core<br \/>\n\u4e86\u89e3\u8eab\u4efd\u9a8c\u8bc1\u5728 ASP.NET Core\u4e2d\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5de5\u4f5c\u539f\u7406<br \/>\n\u2022  Creating a project using the ASP.NET Core Identity system<br \/>\n\u4f7f\u7528 ASP.NET Core Identity \u7cfb\u7edf\u521b\u5efa\u9879\u76ee<br \/>\n\u2022  Adding user functionality to an existing web app<br \/>\n\u5411\u73b0\u6709 Web \u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u529f\u80fd<br \/>\n\u2022  Customizing the default ASP.NET Core Identity UI<br \/>\n\u81ea\u5b9a\u4e49\u9ed8\u8ba4 ASP.NET Core Identity UI<\/p>\n<p>One of the selling points of a web framework like ASP.NET Core is the ability to provide a dynamic app, customized to individual users. Many apps have the concept of an \u201caccount\u201d with the service, which you can \u201csign in\u201d to and get a different experience.<br \/>\n\u50cf ASP.NET Core \u8fd9\u6837\u7684 Web \u6846\u67b6\u7684\u5356\u70b9\u4e4b\u4e00\u662f\u80fd\u591f\u63d0\u4f9b\u9488\u5bf9\u4e2a\u4eba\u7528\u6237\u5b9a\u5236\u7684\u52a8\u6001\u5e94\u7528\u7a0b\u5e8f\u3002\u8bb8\u591a\u5e94\u7528\u7a0b\u5e8f\u90fd\u5177\u6709\u8be5\u670d\u52a1\u7684\u201c\u5e10\u6237\u201d\u6982\u5ff5\uff0c\u60a8\u53ef\u4ee5\u201c\u767b\u5f55\u201d\u8be5\u5e10\u6237\u5e76\u83b7\u5f97\u4e0d\u540c\u7684\u4f53\u9a8c\u3002<\/p>\n<p>Depending on the service, an account gives you varying things. On some apps you may have to sign in to get access to additional features, and on others you might see suggested articles. On an e-commerce app, you\u2019d be able to place orders and view your past orders; on Stack Overflow you can post questions and answers; on a news site you might get a customized experience based on previous articles you\u2019ve viewed.<br \/>\n\u6839\u636e\u670d\u52a1\u7684\u4e0d\u540c\uff0c\u8d26\u6237\u4f1a\u4e3a\u60a8\u63d0\u4f9b\u4e0d\u540c\u7684\u5185\u5bb9\u3002\u5728\u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u4e0a\uff0c\u60a8\u53ef\u80fd\u5fc5\u987b\u767b\u5f55\u624d\u80fd\u8bbf\u95ee\u5176\u4ed6\u529f\u80fd\uff0c\u800c\u5728\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\u4e0a\uff0c\u60a8\u53ef\u80fd\u4f1a\u770b\u5230\u63a8\u8350\u7684\u6587\u7ae0\u3002\u5728\u7535\u5b50\u5546\u52a1\u5e94\u7528\u7a0b\u5e8f\u4e0a\uff0c\u60a8\u5c06\u80fd\u591f\u4e0b\u8ba2\u5355\u5e76\u67e5\u770b\u60a8\u8fc7\u53bb\u7684\u8ba2\u5355;\u5728 Stack Overflow \u4e0a\uff0c\u60a8\u53ef\u4ee5\u53d1\u5e03\u95ee\u9898\u548c\u7b54\u6848;\u5728\u65b0\u95fb\u7f51\u7ad9\u4e0a\uff0c\u60a8\u53ef\u80fd\u4f1a\u6839\u636e\u60a8\u4ee5\u524d\u67e5\u770b\u8fc7\u7684\u6587\u7ae0\u83b7\u5f97\u81ea\u5b9a\u4e49\u4f53\u9a8c\u3002<\/p>\n<p>When you think about adding users to your application, you typically have two aspects to consider:<br \/>\n\u5f53\u60a8\u8003\u8651\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u65f6\uff0c\u901a\u5e38\u9700\u8981\u8003\u8651\u4e24\u4e2a\u65b9\u9762\uff1a<\/p>\n<p>\u2022  Authentication\u2014The process of creating users and letting them log in to your app<br \/>\n\u8eab\u4efd\u9a8c\u8bc1 - \u521b\u5efa\u7528\u6237\u5e76\u5141\u8bb8\u5176\u767b\u5f55\u5e94\u7528\u7a0b\u5e8f\u7684\u8fc7\u7a0b<br \/>\n\u2022  Authorization\u2014Customizing the experience and controlling what users can do, based on the current logged-in user<br \/>\n\u6388\u6743 - \u6839\u636e\u5f53\u524d\u767b\u5f55\u7684\u7528\u6237\u81ea\u5b9a\u4e49\u4f53\u9a8c\u5e76\u63a7\u5236\u7528\u6237\u53ef\u4ee5\u6267\u884c\u7684\u4f5c<\/p>\n<p>In this chapter I\u2019m going to be discussing the first of these points, authentication and membership. In the next chapter I\u2019ll tackle the second point, authorization. In section 23.1 I discuss the difference between authentication and authorization, how authentication works in a traditional ASP.NET Core web app, and ways you can architect your system to provide sign-in functionality. I don\u2019t discuss API applications in detail in this chapter, though many of the authentication principles apply to both styles of app. I discuss API applications chapter 25.<br \/>\n\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba\u7b2c\u4e00\u70b9\uff0c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6210\u5458\u8d44\u683c\u3002\u5728\u4e0b\u4e00\u7ae0\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba\u7b2c\u4e8c\u70b9\uff0c\u6388\u6743\u3002\u5728\u7b2c 23.1 \u8282\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u4e4b\u95f4\u7684\u533a\u522b\u3001\u8eab\u4efd\u9a8c\u8bc1\u5728\u4f20\u7edf ASP.NET Core Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u4ee5\u53ca\u6784\u5efa\u7cfb\u7edf\u4ee5\u63d0\u4f9b\u767b\u5f55\u529f\u80fd\u7684\u65b9\u6cd5\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u4e0d\u4f1a\u8be6\u7ec6\u8ba8\u8bba API \u5e94\u7528\u7a0b\u5e8f\uff0c\u5c3d\u7ba1\u8bb8\u591a\u8eab\u4efd\u9a8c\u8bc1\u539f\u5219\u9002\u7528\u4e8e\u8fd9\u4e24\u79cd\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u6211\u5c06\u8ba8\u8bba API \u5e94\u7528\u7a0b\u5e8f\u7b2c 25 \u7ae0\u3002<\/p>\n<p>In section 23.2 I introduce a user-management system called ASP.NET Core Identity (Identity for short). Identity integrates with Entity Framework Core (EF Core) and provides services for creating and managing users, storing and validating passwords, and signing users in and out of your app.<br \/>\n\u5728 Section 23.2 \u4e2d\uff0c\u6211\u4ecb\u7ecd\u4e86\u4e00\u4e2a\u540d\u4e3a ASP.NET Core Identity\uff08\u7b80\u79f0 Identity\uff09\u7684\u7528\u6237\u7ba1\u7406\u7cfb\u7edf\u3002Identity \u4e0e Entity Framework Core \uff08EF Core\uff09 \u96c6\u6210\uff0c\u5e76\u63d0\u4f9b\u7528\u4e8e\u521b\u5efa\u548c\u7ba1\u7406\u7528\u6237\u3001\u5b58\u50a8\u548c\u9a8c\u8bc1\u5bc6\u7801\u4ee5\u53ca\u8ba9\u7528\u6237\u767b\u5f55\u548c\u6ce8\u9500\u5e94\u7528\u7a0b\u5e8f\u7684\u670d\u52a1\u3002<\/p>\n<p>In section 23.3 you\u2019ll create an app using a default template that includes ASP.NET Core Identity out of the box. This gives you an app to explore and see the features Identity provides, as well as everything it doesn\u2019t.<br \/>\n\u5728 Section 23.3 \u4e2d\uff0c\u60a8\u5c06\u4f7f\u7528\u9ed8\u8ba4\u6a21\u677f\u521b\u5efa\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\uff0c\u8be5\u6a21\u677f\u5305\u542b\u5f00\u7bb1\u5373\u7528 ASP.NET Core Identity\u3002\u8fd9\u4e3a\u60a8\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u6765\u63a2\u7d22\u548c\u67e5\u770b Identity \u63d0\u4f9b\u7684\u529f\u80fd\uff0c\u4ee5\u53ca\u5b83\u4e0d\u63d0\u4f9b\u7684\u6240\u6709\u5185\u5bb9\u3002<\/p>\n<p>Creating an app is great for seeing how the pieces fit together, but you\u2019ll often need to add users and authentication to an existing app. In section 23.4 you\u2019ll see the steps required to add ASP.NET Core Identity to an existing app.<br \/>\n\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\u975e\u5e38\u9002\u5408\u67e5\u770b\u5404\u4e2a\u90e8\u5206\u5982\u4f55\u7ec4\u5408\u5728\u4e00\u8d77\uff0c\u4f46\u60a8\u901a\u5e38\u9700\u8981\u5411\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u548c\u8eab\u4efd\u9a8c\u8bc1\u3002\u5728 Section 23.4 \u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5c06 ASP.NET Core Identity \u6dfb\u52a0\u5230\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u6240\u9700\u7684\u6b65\u9aa4\u3002<\/p>\n<p>In sections 23.5 and 23.6 you\u2019ll learn how to replace pages from the default Identity UI by scaffolding individual pages. In section 23.5 you\u2019ll see how to customize the Razor templates to generate different HTML on the user registration page, and in section 23.6 you\u2019ll learn how to customize the logic associated with a Razor Page. You\u2019ll see how to store additional information about a user (such as their name or date of birth) and how to provide them permissions that you can later use to customize the app\u2019s behavior (if the user is a VIP, for example).<br \/>\n\u5728\u7b2c 23.5 \u8282\u548c\u7b2c 23.6 \u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u901a\u8fc7\u642d\u5efa\u5355\u4e2a\u9875\u9762\u7684\u57fa\u67b6\u6765\u66ff\u6362\u9ed8\u8ba4 Identity UI \u4e2d\u7684\u9875\u9762\u3002\u5728\u7b2c 23.5 \u8282\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u81ea\u5b9a\u4e49 Razor \u6a21\u677f\u4ee5\u5728\u7528\u6237\u6ce8\u518c\u9875\u4e0a\u751f\u6210\u4e0d\u540c\u7684 HTML\uff0c\u5728\u7b2c 23.6 \u8282\u4e2d\uff0c\u4f60\u5c06\u4e86\u89e3\u5982\u4f55\u81ea\u5b9a\u4e49\u4e0e Razor \u9875\u9762\u5173\u8054\u7684\u903b\u8f91\u3002\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5b58\u50a8\u6709\u5173\u7528\u6237\u7684\u5176\u4ed6\u4fe1\u606f\uff08\u4f8b\u5982\u4ed6\u4eec\u7684\u59d3\u540d\u6216\u51fa\u751f\u65e5\u671f\uff09\uff0c\u4ee5\u53ca\u5982\u4f55\u4e3a\u4ed6\u4eec\u63d0\u4f9b\u7a0d\u540e\u53ef\u7528\u4e8e\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u884c\u4e3a\u7684\u6743\u9650\uff08\u4f8b\u5982\uff0c\u5982\u679c\u7528\u6237\u662f VIP\uff09\u3002<\/p>\n<p>Before we look at the ASP.NET Core Identity system specifically, let\u2019s take a look at authentication and authorization in ASP.NET Core\u2014what\u2019s happening when you sign in to a website and how you can design your apps to provide this functionality.<br \/>\n\u5728\u6211\u4eec\u5177\u4f53\u7814\u7a76 ASP.NET Core Identity \u7cfb\u7edf\u4e4b\u524d\uff0c\u8ba9\u6211\u4eec\u5148\u770b\u4e00\u4e0b ASP.NET Core \u4e2d\u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743 - \u5f53\u60a8\u767b\u5f55\u7f51\u7ad9\u65f6\u4f1a\u53d1\u751f\u4ec0\u4e48\uff0c\u4ee5\u53ca\u5982\u4f55\u8bbe\u8ba1\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u6765\u63d0\u4f9b\u6b64\u529f\u80fd\u3002<\/p>\n<h2>23.1 Introducing authentication and authorization<\/h2>\n<p>23.1 \u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7b80\u4ecb<\/p>\n<p>When you add sign-in functionality to your app and control access to certain functions based on the currently signed-in user, you\u2019re using two distinct aspects of security:<br \/>\n\u5f53\u60a8\u5411\u5e94\u7528\u6dfb\u52a0\u767b\u5f55\u529f\u80fd\u5e76\u6839\u636e\u5f53\u524d\u767b\u5f55\u7684\u7528\u6237\u63a7\u5236\u5bf9\u67d0\u4e9b\u529f\u80fd\u7684\u8bbf\u95ee\u65f6\uff0c\u60a8\u5c06\u4f7f\u7528\u4e24\u4e2a\u4e0d\u540c\u7684\u5b89\u5168\u6027\u65b9\u9762\uff1a<\/p>\n<p>\u2022  Authentication\u2014The process of determining who you are<br \/>\n\u8eab\u4efd\u9a8c\u8bc1 - \u786e\u5b9a\u60a8\u662f\u8c01\u7684\u8fc7\u7a0b<br \/>\n\u2022  Authorization\u2014The process of determining what you\u2019re allowed to do<br \/>\n\u6388\u6743 - \u786e\u5b9a\u5141\u8bb8\u60a8\u6267\u884c\u7684\u4f5c\u7684\u8fc7\u7a0b<\/p>\n<p>Generally you need to know who the user is before you can determine what they\u2019re allowed to do, so authentication always comes first, followed by authorization. In this chapter we\u2019re looking only at authentication; we\u2019ll cover authorization in chapter 24.<br \/>\n\u901a\u5e38\uff0c\u60a8\u9700\u8981\u5148\u77e5\u9053\u7528\u6237\u662f\u8c01\uff0c\u7136\u540e\u624d\u80fd\u786e\u5b9a\u5141\u8bb8\u4ed6\u4eec\u505a\u4ec0\u4e48\uff0c\u56e0\u6b64\u8eab\u4efd\u9a8c\u8bc1\u59cb\u7ec8\u6392\u5728\u7b2c\u4e00\u4f4d\uff0c\u7136\u540e\u662f\u6388\u6743\u3002\u5728\u672c\u7ae0\u4e2d\uff0c\u6211\u4eec\u53ea\u5173\u6ce8\u8eab\u4efd\u9a8c\u8bc1;\u6211\u4eec\u5c06\u5728\u7b2c 24 \u7ae0\u4e2d\u4ecb\u7ecd\u6388\u6743\u3002<\/p>\n<p>In this section I start by discussing how ASP.NET Core thinks about users, and I cover some of the terminology and concepts that are central to authentication. I found this to be the hardest part to grasp when I learned about authentication, so I\u2019ll take it slow.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u9996\u5148\u8ba8\u8bba ASP.NET Core \u5982\u4f55\u770b\u5f85\u7528\u6237\uff0c\u5e76\u4ecb\u7ecd\u4e00\u4e9b\u5bf9\u8eab\u4efd\u9a8c\u8bc1\u81f3\u5173\u91cd\u8981\u7684\u672f\u8bed\u548c\u6982\u5ff5\u3002\u5f53\u6211\u4e86\u89e3\u8eab\u4efd\u9a8c\u8bc1\u65f6\uff0c\u6211\u53d1\u73b0\u8fd9\u662f\u6700\u96be\u638c\u63e1\u7684\u90e8\u5206\uff0c\u56e0\u6b64\u6211\u4f1a\u6162\u6162\u6765\u3002<\/p>\n<p>Next, we\u2019ll look at what it means to sign in to a traditional web app. After all, you only provide your password and sign into an app on a single page; how does the app know the request came from you for subsequent requests?<br \/>\n\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u767b\u5f55\u5230\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u610f\u5473\u7740\u4ec0\u4e48\u3002\u6bd5\u7adf\uff0c\u60a8\u53ea\u9700\u5728\u5355\u4e2a\u9875\u9762\u4e0a\u63d0\u4f9b\u5bc6\u7801\u5e76\u767b\u5f55\u5e94\u7528\u7a0b\u5e8f;\u5e94\u7528\u7a0b\u5e8f\u5982\u4f55\u77e5\u9053\u60a8\u7684\u540e\u7eed\u8bf7\u6c42\u6765\u81ea\u60a8\uff1f<\/p>\n<h3>23.1.1 Understanding users and claims in ASP.NET Core<\/h3>\n<p>23.1.1 \u4e86\u89e3 ASP.NET Core \u4e2d\u7684\u7528\u6237\u548c\u58f0\u660e<\/p>\n<p>The concept of a user is baked into ASP.NET Core. In chapter 3 you learned that the HTTP server, Kestrel, creates an HttpContext object for every request it receives. This object is responsible for storing all the details related to that request, such as the request URL, any headers sent, and the body of the request.<br \/>\n\u7528\u6237\u7684\u6982\u5ff5\u5df2\u878d\u5165 ASP.NET Core\u3002\u5728\u7b2c 3 \u7ae0\u4e2d\uff0c\u60a8\u4e86\u89e3\u4e86 HTTP \u670d\u52a1\u5668 Kestrel \u4e3a\u5b83\u6536\u5230\u7684\u6bcf\u4e2a\u8bf7\u6c42\u521b\u5efa\u4e00\u4e2a HttpContext \u5bf9\u8c61\u3002\u6b64\u5bf9\u8c61\u8d1f\u8d23\u5b58\u50a8\u4e0e\u8be5\u8bf7\u6c42\u76f8\u5173\u7684\u6240\u6709\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f8b\u5982\u8bf7\u6c42 URL\u3001\u53d1\u9001\u7684\u4efb\u4f55\u6807\u5934\u4ee5\u53ca\u8bf7\u6c42\u6b63\u6587\u3002<\/p>\n<p>The HttpContext object also exposes the current principal for a request as the User property. This is ASP.NET Core\u2019s view of which user made the request. Any time your app needs to know who the current user is or what they\u2019re allowed to do, it can look at the HttpContext.User principal.<br \/>\nHttpContext \u5bf9\u8c61\u8fd8\u5c06\u8bf7\u6c42\u7684\u5f53\u524d\u4e3b\u4f53\u516c\u5f00\u4e3a User \u5c5e\u6027\u3002\u8fd9\u662f ASP.NET Core \u5bf9\u54ea\u4e2a\u7528\u6237\u53d1\u51fa\u8bf7\u6c42\u7684\u89c6\u56fe\u3002\u6bcf\u5f53\u4f60\u7684\u5e94\u7528\u7a0b\u5e8f\u9700\u8981\u77e5\u9053\u5f53\u524d\u7528\u6237\u662f\u8c01\u6216\u5141\u8bb8\u4ed6\u4eec\u505a\u4ec0\u4e48\u65f6\uff0c\u5b83\u90fd\u53ef\u4ee5\u67e5\u770b HttpContext.User \u4e3b\u4f53\u3002<\/p>\n<p><b>DEFINITION<\/b> You can think of the principal as the user of your app.<br \/>\n\u5b9a\u4e49\uff1a\u60a8\u53ef\u4ee5\u5c06\u4e3b\u4f53\u89c6\u4e3a\u5e94\u7528\u7a0b\u5e8f\u7684\u7528\u6237\u3002<\/p>\n<p>In ASP.NET Core, principals are implemented using the ClaimsPrincipal class, which has a collection of claims associated with it, as shown in figure 23.1.<br \/>\n\u5728 ASP.NET Core \u4e2d\uff0c\u4e3b\u4f53\u662f\u4f7f\u7528 ClaimsPrincipal \u7c7b\u5b9e\u73b0\u7684\uff0c\u8be5\u7c7b\u5177\u6709\u4e0e\u4e4b\u5173\u8054\u7684\u58f0\u660e\u96c6\u5408\uff0c\u5982\u56fe 23.1 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2301.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.1 The principal is the current user, implemented as ClaimsPrincipal. It contains a collection of Claims that describe the user.<br \/>\n\u56fe 23.1 \u4e3b\u4f53\u662f\u5f53\u524d\u7528\u6237\uff0c\u5b9e\u73b0\u4e3a ClaimsPrincipal\u3002\u5b83\u5305\u542b\u63cf\u8ff0\u7528\u6237\u7684 Claims \u96c6\u5408\u3002<\/p>\n<p>You can think about claims as properties of the current user. For example, you could have claims for things like email, name, and date of birth.<br \/>\n\u60a8\u53ef\u4ee5\u5c06\u58f0\u660e\u89c6\u4e3a\u5f53\u524d\u7528\u6237\u7684\u5c5e\u6027\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u5bf9\u7535\u5b50\u90ae\u4ef6\u3001\u59d3\u540d\u548c\u51fa\u751f\u65e5\u671f\u7b49\u5185\u5bb9\u63d0\u51fa\u7d22\u8d54\u3002<\/p>\n<p><b>DEFINITION<\/b> A claim is a single piece of information about a principal; it consists of a claim type and an optional value.<br \/>\n\u5b9a\u4e49:\u7d22\u8d54\u662f\u6709\u5173\u59d4\u6258\u4eba\u7684\u5355\u4e2a\u4fe1\u606f;\u5b83\u7531 Claim \u7c7b\u578b\u548c Optional Value \u7ec4\u6210\u3002<\/p>\n<p>Claims can also be indirectly related to permissions and authorization, so you could have a claim called HasAdminAccess or IsVipCustomer. These would be stored in the same way\u2014as claims associated with the user principal.<br \/>\n\u58f0\u660e\u4e5f\u53ef\u4ee5\u4e0e\u6743\u9650\u548c\u6388\u6743\u95f4\u63a5\u76f8\u5173\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u6709\u4e00\u4e2a\u540d\u4e3a HasAdminAccess \u6216 IsVipCustomer \u7684\u58f0\u660e\u3002\u8fd9\u4e9b\u8bf7\u6c42\u7684\u5b58\u50a8\u65b9\u5f0f\u4e0e\u4e0e\u7528\u6237\u4e3b\u4f53\u5173\u8054\u7684\u58f0\u660e\u76f8\u540c\u3002<\/p>\n<p><b>NOTE<\/b> Earlier versions of ASP.NET used a role-based approach to security rather than a claims-based approach. The ClaimsPrincipal used in ASP.NET Core is compatible with this approach for legacy reasons, but you should use the claims-based approach for new apps.<br \/>\n\u6ce8\u610f:\u65e9\u671f\u7248\u672c\u7684 ASP.NET \u4f7f\u7528\u57fa\u4e8e\u89d2\u8272\u7684\u5b89\u5168\u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e\u58f0\u660e\u7684\u65b9\u6cd5\u3002\u7531\u4e8e\u9057\u7559\u539f\u56e0\uff0cASP.NET Core \u4e2d\u4f7f\u7528\u7684 ClaimsPrincipal \u4e0e\u6b64\u65b9\u6cd5\u517c\u5bb9\uff0c\u4f46\u5bf9\u4e8e\u65b0\u5e94\u7528\uff0c\u5e94\u4f7f\u7528\u57fa\u4e8e\u58f0\u660e\u7684\u65b9\u6cd5\u3002<\/p>\n<p>Kestrel assigns a user principal to every request that arrives at your app. Initially, that principal is a generic, anonymous, unauthenticated principal with no claims. How do you log in, and how does ASP.NET Core know that you\u2019ve logged in on subsequent requests?<br \/>\nKestrel \u4e3a\u5230\u8fbe\u5e94\u7528\u7a0b\u5e8f\u7684\u6bcf\u4e2a\u8bf7\u6c42\u5206\u914d\u4e00\u4e2a\u7528\u6237\u4e3b\u4f53\u3002\u6700\u521d\uff0c\u8be5\u59d4\u6258\u4eba\u662f\u901a\u7528\u7684\u3001\u533f\u540d\u7684\u3001\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u59d4\u6258\u4eba\uff0c\u6ca1\u6709\u58f0\u660e\u3002\u60a8\u5982\u4f55\u767b\u5f55\uff0cASP.NET Core \u5982\u4f55\u77e5\u9053\u60a8\u5df2\u767b\u5f55\u540e\u7eed\u8bf7\u6c42\uff1f<\/p>\n<p>In the next section we\u2019ll look at how authentication works in a traditional web app using ASP.NET Core and the process of signing into a user account.<br \/>\n\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u4f7f\u7528 ASP.NET Core \u5728\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u4ee5\u53ca\u767b\u5f55\u7528\u6237\u5e10\u6237\u7684\u8fc7\u7a0b\u3002<\/p>\n<h3>23.1.2 Authentication in ASP.NET Core: Services and middleware<\/h3>\n<p>23.1.2 ASP.NET Core \u4e2d\u7684\u8eab\u4efd\u9a8c\u8bc1\uff1a\u670d\u52a1\u548c\u4e2d\u95f4\u4ef6<\/p>\n<p>Adding authentication to any web app involves a few moving parts. The same general process applies whether you\u2019re building a traditional web app or a client-side app (though there are often differences in the latter, as I discuss in chapter 25):<br \/>\n\u5411\u4efb\u4f55 Web \u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u90fd\u6d89\u53ca\u4e00\u4e9b\u79fb\u52a8\u90e8\u4ef6\u3002\u65e0\u8bba\u60a8\u662f\u6784\u5efa\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u8fd8\u662f\u5ba2\u6237\u7aef\u5e94\u7528\u7a0b\u5e8f\uff0c\u76f8\u540c\u7684\u4e00\u822c\u8fc7\u7a0b\u90fd\u9002\u7528\uff08\u5c3d\u7ba1\u540e\u8005\u7ecf\u5e38\u5b58\u5728\u5dee\u5f02\uff0c\u6b63\u5982\u6211\u5728\u7b2c 25 \u7ae0\u4e2d\u8ba8\u8bba\u7684\u90a3\u6837\uff09\uff1a<\/p>\n<ol>\n<li>\n<p>The client sends an identifier and a secret to the app to identify the current user. For example, you could send an email address (identifier) and a password (secret).<br \/>\n\u5ba2\u6237\u7aef\u5411\u5e94\u7528\u7a0b\u5e8f\u53d1\u9001\u6807\u8bc6\u7b26\u548c\u5bc6\u94a5\u4ee5\u8bc6\u522b\u5f53\u524d\u7528\u6237\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u53d1\u9001\u7535\u5b50\u90ae\u4ef6\u5730\u5740 \uff08identifier\uff09 \u548c\u5bc6\u7801 \uff08secret\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>The app verifies that the identifier corresponds to a user known by the app and that the corresponding secret is correct.<br \/>\n\u5e94\u7528\u7a0b\u5e8f\u9a8c\u8bc1\u6807\u8bc6\u7b26\u662f\u5426\u5bf9\u5e94\u4e8e\u5e94\u7528\u7a0b\u5e8f\u5df2\u77e5\u7684\u7528\u6237\uff0c\u4ee5\u53ca\u76f8\u5e94\u7684\u5bc6\u94a5\u662f\u5426\u6b63\u786e\u3002<\/p>\n<\/li>\n<li>\n<p>If the identifier and secret are valid, the app can set the principal for the current request, but it also needs a way of storing these details for subsequent requests. For traditional web apps, this is typically achieved by storing an encrypted version of the user principal in a cookie.<br \/>\n\u5982\u679c\u6807\u8bc6\u7b26\u548c\u5bc6\u94a5\u6709\u6548\uff0c\u5219\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u4e3a\u5f53\u524d\u8bf7\u6c42\u8bbe\u7f6e\u4e3b\u4f53\uff0c\u4f46\u5b83\u8fd8\u9700\u8981\u4e00\u79cd\u65b9\u6cd5\u6765\u5b58\u50a8\u8fd9\u4e9b\u8be6\u7ec6\u4fe1\u606f\u4ee5\u4f9b\u540e\u7eed\u8bf7\u6c42\u4f7f\u7528\u3002\u5bf9\u4e8e\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\uff0c\u8fd9\u901a\u5e38\u662f\u901a\u8fc7\u5c06\u7528\u6237\u4e3b\u4f53\u7684\u52a0\u5bc6\u7248\u672c\u5b58\u50a8\u5728 Cookie \u4e2d\u6765\u5b9e\u73b0\u7684\u3002<\/p>\n<\/li>\n<\/ol>\n<p>This is the typical flow for most web apps, but in this section I\u2019m going to look at how it works in ASP.NET Core. The overall process is the same, but it\u2019s good to see how this pattern fits into the services, middleware, and Model-View-Controller (MVC) aspects of an ASP.NET Core application. We\u2019ll step through the various pieces at play in a typical app when you sign in as a user, what that means, and how you can make subsequent requests as that user.<br \/>\n\u8fd9\u662f\u5927\u591a\u6570 Web \u5e94\u7528\u7a0b\u5e8f\u7684\u5178\u578b\u6d41\u7a0b\uff0c\u4f46\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u4ecb\u7ecd\u5b83\u5728 ASP.NET Core \u4e2d\u7684\u5de5\u4f5c\u539f\u7406\u3002\u6574\u4e2a\u8fc7\u7a0b\u662f\u76f8\u540c\u7684\uff0c\u4f46\u5f88\u9ad8\u5174\u770b\u5230\u6b64\u6a21\u5f0f\u5982\u4f55\u9002\u5e94 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u7684\u670d\u52a1\u3001\u4e2d\u95f4\u4ef6\u548c\u6a21\u578b-\u89c6\u56fe-\u63a7\u5236\u5668 \uff08MVC\uff09 \u65b9\u9762\u3002\u6211\u4eec\u5c06\u9010\u6b65\u4ecb\u7ecd\u5f53\u60a8\u4ee5\u7528\u6237\u8eab\u4efd\u767b\u5f55\u65f6\uff0c\u5178\u578b\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5404\u4e2a\u90e8\u5206\u3001\u8fd9\u610f\u5473\u7740\u4ec0\u4e48\uff0c\u4ee5\u53ca\u60a8\u5982\u4f55\u4ee5\u8be5\u7528\u6237\u8eab\u4efd\u53d1\u51fa\u540e\u7eed\u8bf7\u6c42\u3002<\/p>\n<blockquote>\n<p>Signing in to an ASP.NET Core application<br \/>\n\u767b\u5f55\u5230 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f<\/p>\n<\/blockquote>\n<p>When you first arrive on a site and sign in to a traditional web app, the app will send you to a sign-in page and ask you to enter your username and password. After you submit the form to the server, the app redirects you to a new page, and you\u2019re magically logged in! Figure 23.2 shows what\u2019s happening behind the scenes in an ASP.NET Core app when you submit the form.<br \/>\n\u5f53\u60a8\u9996\u6b21\u8bbf\u95ee\u7ad9\u70b9\u5e76\u767b\u5f55\u5230\u4f20\u7edf\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u8be5\u5e94\u7528\u7a0b\u5e8f\u4f1a\u5c06\u60a8\u8f6c\u5230\u767b\u5f55\u9875\u9762\uff0c\u5e76\u8981\u6c42\u60a8\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002\u5c06\u8868\u5355\u63d0\u4ea4\u5230\u670d\u52a1\u5668\u540e\uff0c\u5e94\u7528\u7a0b\u5e8f\u4f1a\u5c06\u60a8\u91cd\u5b9a\u5411\u5230\u65b0\u9875\u9762\uff0c\u7136\u540e\u60a8\u795e\u5947\u5730\u767b\u5f55\u4e86\uff01\u56fe 23.2 \u663e\u793a\u4e86\u5f53\u60a8\u63d0\u4ea4\u8868\u5355\u65f6 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u5e55\u540e\u60c5\u51b5\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2302.png\" alt=\"alt text\" \/><br \/>\nFigure 23.2 Signing in to an ASP.NET Core application. SignInManager is responsible for setting HttpContext.User to the new principal and serializing the principal to the encrypted cookie.<br \/>\n\u56fe 23.2 \u767b\u5f55\u5230 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u3002SignInManager \u8d1f\u8d23\u5c06 HttpContext.User \u8bbe\u7f6e\u4e3a\u65b0\u4e3b\u4f53\uff0c\u5e76\u5c06\u4e3b\u4f53\u5e8f\u5217\u5316\u4e3a\u52a0\u5bc6\u7684 Cookie\u3002<\/p>\n<p>This figure shows the series of steps from the moment you submit the login form on a Razor Page to the point the redirect is returned to the browser. When the request first arrives, Kestrel creates an anonymous user principal and assigns it to the HttpContext.User property. The request is then routed to the Login.cshtml Razor Page, which reads the email and password from the request using model binding.<br \/>\n\u6b64\u56fe\u663e\u793a\u4e86\u4ece\u60a8\u5728 Razor \u9875\u9762\u4e0a\u63d0\u4ea4\u767b\u5f55\u8868\u5355\u5230\u5c06\u91cd\u5b9a\u5411\u8fd4\u56de\u5230\u6d4f\u89c8\u5668\u7684\u4e00\u7cfb\u5217\u6b65\u9aa4\u3002\u5f53\u8bf7\u6c42\u9996\u6b21\u5230\u8fbe\u65f6\uff0cKestrel \u4f1a\u521b\u5efa\u4e00\u4e2a\u533f\u540d\u7528\u6237\u4e3b\u4f53\uff0c\u5e76\u5c06\u5176\u5206\u914d\u7ed9 HttpContext.User \u5c5e\u6027\u3002\u7136\u540e\uff0c\u8be5\u8bf7\u6c42\u5c06\u8def\u7531\u5230 Login.cshtml Razor \u9875\u9762\uff0c\u8be5\u9875\u9762\u4f7f\u7528\u6a21\u578b\u7ed1\u5b9a\u4ece\u8bf7\u6c42\u4e2d\u8bfb\u53d6\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\u3002<\/p>\n<p>The meaty work happens inside the SignInManager service. This is responsible for loading a user entity with the provided username from the database and validating that the password they provided is correct.<br \/>\n\u7e41\u91cd\u7684\u5de5\u4f5c\u53d1\u751f\u5728 SignInManager \u670d\u52a1\u5185\u90e8\u3002\u8fd9\u8d1f\u8d23\u4f7f\u7528\u4ece\u6570\u636e\u5e93\u4e2d\u63d0\u4f9b\u7684\u7528\u6237\u540d\u52a0\u8f7d\u7528\u6237\u5b9e\u4f53\uff0c\u5e76\u9a8c\u8bc1\u4ed6\u4eec\u63d0\u4f9b\u7684\u5bc6\u7801\u662f\u5426\u6b63\u786e\u3002<\/p>\n<p><b>Warning<\/b> Never store passwords in the database directly. They should be hashed using a strong one-way algorithm. The ASP.NET Core Identity system does this for you, but it\u2019s always wise to reiterate this point!<br \/>\n\u8b66\u544a:\u5207\u52ff\u5c06\u5bc6\u7801\u76f4\u63a5\u5b58\u50a8\u5728\u6570\u636e\u5e93\u4e2d\u3002\u5b83\u4eec\u5e94\u8be5\u4f7f\u7528\u5f3a\u5927\u7684\u5355\u5411\u7b97\u6cd5\u8fdb\u884c\u54c8\u5e0c\u5904\u7406\u3002ASP.NET Core Identity \u7cfb\u7edf\u4e3a\u60a8\u6267\u884c\u6b64\u4f5c\uff0c\u4f46\u91cd\u7533\u8fd9\u4e00\u70b9\u59cb\u7ec8\u662f\u660e\u667a\u7684\uff01<\/p>\n<p>If the password is correct, SignInManager creates a new ClaimsPrincipal from the user entity it loaded from the database and adds the appropriate claims, such as the email address. It then replaces the old, anonymous HttpContext.User principal with the new, authenticated principal.<br \/>\n\u5982\u679c\u5bc6\u7801\u6b63\u786e\uff0cSignInManager \u5c06\u4ece\u5b83\u4ece\u6570\u636e\u5e93\u4e2d\u52a0\u8f7d\u7684\u7528\u6237\u5b9e\u4f53\u521b\u5efa\u65b0\u7684 ClaimsPrincipal\uff0c\u5e76\u6dfb\u52a0\u76f8\u5e94\u7684\u58f0\u660e\uff0c\u4f8b\u5982\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002\u7136\u540e\uff0c\u5b83\u5c06\u65e7\u7684\u533f\u540d HttpContext.User \u4e3b\u4f53\u66ff\u6362\u4e3a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u65b0\u4e3b\u4f53\u3002<\/p>\n<p>Finally, SignInManager serializes the principal, encrypts it, and stores it as a cookie. A cookie is a small piece of text that\u2019s sent back and forth between the browser and your app along with each request, consisting of a name and a value.<br \/>\n\u6700\u540e\uff0cSignInManager \u5e8f\u5217\u5316\u4e3b\u4f53\uff0c\u5bf9\u5176\u8fdb\u884c\u52a0\u5bc6\uff0c\u5e76\u5c06\u5176\u5b58\u50a8\u4e3a Cookie\u3002Cookie \u662f\u4e00\u5c0f\u6bb5\u6587\u672c\uff0c\u5b83\u4e0e\u6bcf\u4e2a\u8bf7\u6c42\u4e00\u8d77\u5728\u6d4f\u89c8\u5668\u548c\u5e94\u7528\u7a0b\u5e8f\u4e4b\u95f4\u6765\u56de\u53d1\u9001\uff0c\u7531\u540d\u79f0\u548c\u503c\u7ec4\u6210\u3002<\/p>\n<p>This authentication process explains how you can set the user for a request when they first log in to your app, but what about subsequent requests? You send your password only when you first log in to an app, so how does the app know that it\u2019s the same user making the request?<br \/>\n\u6b64\u8eab\u4efd\u9a8c\u8bc1\u8fc7\u7a0b\u8bf4\u660e\u4e86\u5982\u4f55\u5728\u7528\u6237\u9996\u6b21\u767b\u5f55\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u65f6\u4e3a\u7528\u6237\u8bbe\u7f6e\u8bf7\u6c42\uff0c\u4f46\u540e\u7eed\u8bf7\u6c42\u5462\uff1f\u60a8\u4ec5\u5728\u9996\u6b21\u767b\u5f55\u5e94\u7528\u7a0b\u5e8f\u65f6\u53d1\u9001\u5bc6\u7801\uff0c\u90a3\u4e48\u8be5\u5e94\u7528\u7a0b\u5e8f\u5982\u4f55\u77e5\u9053\u5b83\u662f\u53d1\u51fa\u8bf7\u6c42\u7684\u540c\u4e00\u7528\u6237\uff1f<\/p>\n<blockquote>\n<p>Authenticating users for subsequent requests<br \/>\n\u4e3a\u540e\u7eed\u8bf7\u6c42\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1<\/p>\n<p>The key to persisting your identity across multiple requests lies in the final step of figure 23.2, where you serialized the principal in a cookie. Browsers automatically send this cookie with all requests made to your app, so you don\u2019t need to provide your password with every request.<br \/>\n\u5728\u591a\u4e2a\u8bf7\u6c42\u4e2d\u4fdd\u7559\u8eab\u4efd\u7684\u5173\u952e\u5728\u4e8e\u56fe 23.2 \u7684\u6700\u540e\u4e00\u6b65\uff0c\u5728\u8be5\u6b65\u9aa4\u4e2d\uff0c\u60a8\u5728 cookie \u4e2d\u5e8f\u5217\u5316\u4e86\u4e3b\u4f53\u3002\u6d4f\u89c8\u5668\u4f1a\u81ea\u52a8\u5c06\u6b64 Cookie \u4e0e\u5411\u60a8\u7684\u5e94\u7528\u53d1\u51fa\u7684\u6240\u6709\u8bf7\u6c42\u4e00\u8d77\u53d1\u9001\uff0c\u56e0\u6b64\u60a8\u65e0\u9700\u4e3a\u6bcf\u4e2a\u8bf7\u6c42\u63d0\u4f9b\u5bc6\u7801\u3002<\/p>\n<\/blockquote>\n<p>ASP.NET Core uses the authentication cookie sent with the requests to rehydrate a ClaimsPrincipal and set the HttpContext.User principal for the request, as shown in figure 23.3. The important thing to note is when this process happens\u2014in the AuthenticationMiddleware.<br \/>\nASP.NET Core \u4f7f\u7528\u968f\u8bf7\u6c42\u53d1\u9001\u7684\u8eab\u4efd\u9a8c\u8bc1 Cookie \u6765\u89e3\u9664\u51bb\u7ed3 ClaimsPrincipal \u5e76\u4e3a\u8bf7\u6c42\u8bbe\u7f6e HttpContext.User \u4e3b\u4f53\uff0c\u5982\u56fe 23.3 \u6240\u793a\u3002\u9700\u8981\u6ce8\u610f\u7684\u91cd\u8981\u4e00\u70b9\u662f\u6b64\u8fc7\u7a0b\u4f55\u65f6\u53d1\u751f \u2014 \u5728 AuthenticationMiddleware \u4e2d\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2303.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.3 A subsequent request after signing in to an application. The cookie sent with the request contains the user principal, which is validated and used to authenticate the request.<br \/>\n\u56fe 23.3 \u767b\u5f55\u5e94\u7528\u7a0b\u5e8f\u540e\u7684\u540e\u7eed\u8bf7\u6c42\u3002\u968f\u8bf7\u6c42\u53d1\u9001\u7684 Cookie \u5305\u542b\u7528\u6237\u4e3b\u4f53\uff0c\u8be5\u4e3b\u4f53\u7ecf\u8fc7\u9a8c\u8bc1\u5e76\u7528\u4e8e\u5bf9\u8bf7\u6c42\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>When a request containing the authentication cookie is received, Kestrel creates the default, unauthenticated, anonymous principal and assigns it to the HttpContext.User principal. Any middleware that runs before the AuthenticationMiddleware sees the request as unauthenticated, even if there\u2019s a valid cookie.<br \/>\n\u6536\u5230\u5305\u542b\u8eab\u4efd\u9a8c\u8bc1 Cookie \u7684\u8bf7\u6c42\u65f6\uff0cKestrel \u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u3001\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u533f\u540d\u4e3b\u4f53\uff0c\u5e76\u5c06\u5176\u5206\u914d\u7ed9 HttpContext.User \u4e3b\u4f53\u3002\u5728 AuthenticationMiddleware \u4e4b\u524d\u8fd0\u884c\u7684\u4efb\u4f55\u4e2d\u95f4\u4ef6\u90fd\u4f1a\u5c06\u8bf7\u6c42\u89c6\u4e3a\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5373\u4f7f\u5b58\u5728\u6709\u6548\u7684 cookie\u3002<\/p>\n<p><b>Tip<\/b> If it looks like your authentication system isn\u2019t working, double-check your middleware pipeline. Only middleware that runs after AuthenticationMiddleware will see the request as authenticated.<br \/>\n\u63d0\u793a:\u5982\u679c\u60a8\u7684\u8eab\u4efd\u9a8c\u8bc1\u7cfb\u7edf\u770b\u8d77\u6765\u65e0\u6cd5\u6b63\u5e38\u5de5\u4f5c\uff0c\u8bf7\u4ed4\u7ec6\u68c0\u67e5\u60a8\u7684\u4e2d\u95f4\u4ef6\u7ba1\u9053\u3002\u53ea\u6709\u5728 AuthenticationMiddleware \u4e4b\u540e\u8fd0\u884c\u7684\u4e2d\u95f4\u4ef6\u624d\u4f1a\u770b\u5230\u8bf7\u6c42\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p>The AuthenticationMiddleware is responsible for setting the current user for a request. The middleware calls the authentication services, which reads the cookie from the request, decrypts it, and deserializes it to obtain the ClaimsPrincipal created when the user logged in.<br \/>\nAuthenticationMiddleware \u8d1f\u8d23\u4e3a\u8bf7\u6c42\u8bbe\u7f6e\u5f53\u524d\u7528\u6237\u3002\u4e2d\u95f4\u4ef6\u8c03\u7528\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\uff0c\u8be5\u670d\u52a1\u4ece\u8bf7\u6c42\u4e2d\u8bfb\u53d6 Cookie\uff0c\u5bf9\u5176\u8fdb\u884c\u89e3\u5bc6\uff0c\u7136\u540e\u5bf9\u5176\u8fdb\u884c\u53cd\u5e8f\u5217\u5316\uff0c\u4ee5\u83b7\u53d6\u5728\u7528\u6237\u767b\u5f55\u65f6\u521b\u5efa\u7684 ClaimsPrincipal\u3002<\/p>\n<p>The AuthenticationMiddleware sets the HttpContext.User principal to the new, authenticated principal. All subsequent middleware now knows the user principal for the request and can adjust its behavior accordingly (for example, displaying the user\u2019s name on the home page or restricting access to some areas of the app).<br \/>\nAuthenticationMiddleware \u5c06 HttpContext.User \u4e3b\u4f53\u8bbe\u7f6e\u4e3a\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u65b0\u4e3b\u4f53\u3002\u73b0\u5728\uff0c\u6240\u6709\u540e\u7eed\u4e2d\u95f4\u4ef6\u90fd\u77e5\u9053\u8bf7\u6c42\u7684\u7528\u6237\u4e3b\u4f53\uff0c\u5e76\u53ef\u4ee5\u76f8\u5e94\u5730\u8c03\u6574\u5176\u884c\u4e3a\uff08\u4f8b\u5982\uff0c\u5728\u4e3b\u9875\u4e0a\u663e\u793a\u7528\u6237\u540d\u6216\u9650\u5236\u5bf9\u5e94\u7528\u7a0b\u5e8f\u67d0\u4e9b\u533a\u57df\u7684\u8bbf\u95ee\uff09\u3002<\/p>\n<p><b>NOTE<\/b> The AuthenticationMiddleware is responsible only for authenticating incoming requests and setting the ClaimsPrincipal if the request contains an authentication cookie. It is not responsible for redirecting unauthenticated requests to the login page or rejecting unauthorized requests; that is handled by the AuthorizationMiddleware, as you\u2019ll see in chapter 24.<br \/>\n\u6ce8\u610f:AuthenticationMiddleware \u53ea\u8d1f\u8d23\u5bf9\u4f20\u5165\u8bf7\u6c42\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5e76\u5728\u8bf7\u6c42\u5305\u542b\u8eab\u4efd\u9a8c\u8bc1 Cookie \u65f6\u8bbe\u7f6e ClaimsPrincipal\u3002\u5b83\u4e0d\u8d1f\u8d23\u5c06\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u8bf7\u6c42\u91cd\u5b9a\u5411\u5230\u767b\u5f55\u9875\u9762\u6216\u62d2\u7edd\u672a\u7ecf\u6388\u6743\u7684\u8bf7\u6c42;\u5b83\u7531 AuthorizationMiddleware \u5904\u7406\uff0c\u60a8\u5c06\u5728\u7b2c 24 \u7ae0\u4e2d\u770b\u5230\u3002<\/p>\n<p>The process described so far, in which a single app authenticates the user when they log in and sets a cookie that\u2019s read on subsequent requests, is common with traditional web apps, but it isn\u2019t the only possibility. In chapter 25 we\u2019ll take a look at authentication for web API applications, used by client-side and mobile apps and at how the authentication system changes for those scenarios.<br \/>\n\u5230\u76ee\u524d\u4e3a\u6b62\u63cf\u8ff0\u7684\u8fc7\u7a0b\uff0c\u5373\u5355\u4e2a\u5e94\u7528\u7a0b\u5e8f\u5728\u7528\u6237\u767b\u5f55\u65f6\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5e76\u8bbe\u7f6e\u5728\u540e\u7eed\u8bf7\u6c42\u4e2d\u8bfb\u53d6\u7684 cookie\uff0c\u8fd9\u5728\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\u4e2d\u5f88\u5e38\u89c1\uff0c\u4f46\u5e76\u4e0d\u662f\u552f\u4e00\u7684\u53ef\u80fd\u6027\u3002\u5728\u7b2c 25 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u4ecb\u7ecd\u5ba2\u6237\u7aef\u548c\u79fb\u52a8\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684 Web API \u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u9a8c\u8bc1\uff0c\u4ee5\u53ca\u8fd9\u4e9b\u573a\u666f\u7684\u8eab\u4efd\u9a8c\u8bc1\u7cfb\u7edf\u5982\u4f55\u53d8\u5316\u3002<\/p>\n<p>Another thing to consider is where you store the authentication details for users of your app. In figure 23.2 I showed the authentication services loading the user authentication details from your app\u2019s database, but that\u2019s only one option.<br \/>\n\u8981\u8003\u8651\u7684\u53e6\u4e00\u4ef6\u4e8b\u662f\u5b58\u50a8\u5e94\u7528\u7a0b\u5e8f\u7528\u6237\u7684\u8eab\u4efd\u9a8c\u8bc1\u8be6\u7ec6\u4fe1\u606f\u7684\u4f4d\u7f6e\u3002\u5728\u56fe 23.2 \u4e2d\uff0c\u6211\u5c55\u793a\u4e86\u4ece\u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u5e93\u4e2d\u52a0\u8f7d\u7528\u6237\u8eab\u4efd\u9a8c\u8bc1\u8be6\u7ec6\u4fe1\u606f\u7684\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\uff0c\u4f46\u8fd9\u53ea\u662f\u4e00\u4e2a\u9009\u9879\u3002<\/p>\n<p>Another option is to delegate the authentication responsibilities to a third-party identity provider, such as Okta, Auth0, Azure Active Directory B2B\/B2C, or even Facebook. These manage users for you, so user information and passwords are stored in their database rather than your own. The biggest advantage of this approach is that you don\u2019t have to worry about making sure your customer data is safe; you can be pretty sure that a third party will protect it, as it\u2019s their whole business.<br \/>\n\u53e6\u4e00\u79cd\u9009\u62e9\u662f\u5c06\u8eab\u4efd\u9a8c\u8bc1\u8d23\u4efb\u59d4\u6258\u7ed9\u7b2c\u4e09\u65b9\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u4f8b\u5982 Okta\u3001Auth0\u3001Azure Active Directory B2B\/B2C \u751a\u81f3 Facebook\u3002\u8fd9\u4e9b Bug \u4f1a\u4e3a\u60a8\u7ba1\u7406\u7528\u6237\uff0c\u56e0\u6b64\u7528\u6237\u4fe1\u606f\u548c\u5bc6\u7801\u5b58\u50a8\u5728\u4ed6\u4eec\u7684\u6570\u636e\u5e93\u4e2d\uff0c\u800c\u4e0d\u662f\u60a8\u81ea\u5df1\u7684\u6570\u636e\u5e93\u4e2d\u3002\u8fd9\u79cd\u65b9\u6cd5\u7684\u6700\u5927\u4f18\u70b9\u662f\u60a8\u4e0d\u5fc5\u62c5\u5fc3\u786e\u4fdd\u5ba2\u6237\u6570\u636e\u7684\u5b89\u5168;\u60a8\u53ef\u4ee5\u975e\u5e38\u786e\u5b9a\u7b2c\u4e09\u65b9\u4f1a\u4fdd\u62a4\u5b83\uff0c\u56e0\u4e3a\u8fd9\u662f\u4ed6\u4eec\u7684\u5168\u90e8\u4e1a\u52a1\u3002<\/p>\n<p><b>Tip<\/b> Wherever possible, I recommend this approach, as it delegates security responsibilities to someone else. You can\u2019t lose your users\u2019 details if you never had them! Make sure to understand the differences in providers, however. With a provider like Auth0, you would own the profiles created, whereas with a provider like Facebook, you don\u2019t!<br \/>\n\u63d0\u793a\uff1a\u6211\u5c3d\u53ef\u80fd\u63a8\u8350\u8fd9\u79cd\u65b9\u6cd5\uff0c\u56e0\u4e3a\u5b83\u5c06\u5b89\u5168\u8d23\u4efb\u59d4\u6258\u7ed9\u5176\u4ed6\u4eba\u3002\u5982\u679c\u60a8\u4ece\u672a\u62e5\u6709\u7528\u6237\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u60a8\u5c31\u4e0d\u4f1a\u4e22\u5931\u5b83\u4eec\uff01\u4f46\u662f\uff0c\u8bf7\u52a1\u5fc5\u4e86\u89e3\u63d0\u4f9b\u7a0b\u5e8f\u4e4b\u95f4\u7684\u5dee\u5f02\u3002\u4f7f\u7528\u50cf Auth0 \u8fd9\u6837\u7684\u63d0\u4f9b\u5546\uff0c\u60a8\u5c06\u62e5\u6709\u521b\u5efa\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u800c\u4f7f\u7528\u50cf Facebook \u8fd9\u6837\u7684\u63d0\u4f9b\u5546\uff0c\u60a8\u5c06\u4e0d\u62e5\u6709\uff01<\/p>\n<p>Each provider provides instructions on how to integrate with their identity services, ideally using the OpenID Connect (OIDC) specification. This typically involves configuring some authentication services in your application, adding some configuration, and delegating the authentication process itself to the external provider. These providers can be used with your API apps too, as I discuss in chapter 25.<br \/>\n\u6bcf\u4e2a\u63d0\u4f9b\u5546\u90fd\u63d0\u4f9b\u4e86\u6709\u5173\u5982\u4f55\u4e0e\u5176\u8eab\u4efd\u670d\u52a1\u96c6\u6210\u7684\u8bf4\u660e\uff0c\u6700\u597d\u4f7f\u7528 OpenID Connect \uff08OIDC\uff09 \u89c4\u8303\u3002\u8fd9\u901a\u5e38\u6d89\u53ca\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u914d\u7f6e\u4e00\u4e9b\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u3001\u6dfb\u52a0\u4e00\u4e9b\u914d\u7f6e\u4ee5\u53ca\u5c06\u8eab\u4efd\u9a8c\u8bc1\u8fc7\u7a0b\u672c\u8eab\u59d4\u6258\u7ed9\u5916\u90e8\u63d0\u4f9b\u5546\u3002\u8fd9\u4e9b\u63d0\u4f9b\u7a0b\u5e8f\u4e5f\u53ef\u4ee5\u7528\u4e8e\u60a8\u7684 API \u5e94\u7528\u7a0b\u5e8f\uff0c\u6b63\u5982\u6211\u5728\u7b2c 25 \u7ae0\u4e2d\u8ba8\u8bba\u7684\u90a3\u6837\u3002<\/p>\n<p><b>NOTE<\/b> Hooking up your apps and APIs to use an identity provider can require a fair amount of tedious configuration, both in the app and the identity provider, but if you follow the provider\u2019s documentation you should have plain sailing. For example, you can follow the documentation for adding authentication to a traditional web app using Microsoft\u2019s Identity Platform here: <a href=\"http:\/\/mng.bz\/4D9w\">http:\/\/mng.bz\/4D9w<\/a>.<br \/>\n\u6ce8\u610f:\u5c06\u5e94\u7528\u7a0b\u5e8f\u548c API \u6302\u63a5\u4ee5\u4f7f\u7528\u8eab\u4efd\u63d0\u4f9b\u5546\u53ef\u80fd\u9700\u8981\u5728\u5e94\u7528\u7a0b\u5e8f\u548c\u8eab\u4efd\u63d0\u4f9b\u5546\u4e2d\u8fdb\u884c\u5927\u91cf\u7e41\u7410\u7684\u914d\u7f6e\uff0c\u4f46\u5982\u679c\u60a8\u9075\u5faa\u63d0\u4f9b\u5546\u7684\u6587\u6863\uff0c\u60a8\u5e94\u8be5\u4f1a\u4e00\u5e06\u98ce\u987a\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u6309\u7167\u4ee5\u4e0b\u6587\u6863\u4f7f\u7528 Microsoft \u7684 Identity Platform \u5c06\u8eab\u4efd\u9a8c\u8bc1\u6dfb\u52a0\u5230\u4f20\u7edf Web \u5e94\u7528\u7a0b\u5e8f\uff1a<a href=\"http:\/\/mng.bz\/4D9w\">http:\/\/mng.bz\/4D9w<\/a>\u3002<\/p>\n<p>While I recommend using an external identity provider where possible, sometimes you really want to store all the authentication details of your users directly in your app. That\u2019s the approach I describe in this chapter.<br \/>\n\u867d\u7136\u6211\u5efa\u8bae\u5c3d\u53ef\u80fd\u4f7f\u7528\u5916\u90e8\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u4f46\u6709\u65f6\u60a8\u786e\u5b9e\u5e0c\u671b\u5c06\u7528\u6237\u7684\u6240\u6709\u8eab\u4efd\u9a8c\u8bc1\u8be6\u7ec6\u4fe1\u606f\u76f4\u63a5\u5b58\u50a8\u5728\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u3002\u8fd9\u5c31\u662f\u6211\u5728\u672c\u7ae0\u4e2d\u63cf\u8ff0\u7684\u65b9\u6cd5\u3002<\/p>\n<p>ASP.NET Core Identity (hereafter shortened to Identity) is a system that makes building the user-management aspect of your app. It handles all the boilerplate for saving and loading users to a database, as well as best practices for security, such as user lockout, password hashing, and multifactor authentication.<br \/>\nASP.NET Core Identity\uff08\u4ee5\u4e0b\u7b80\u79f0 Identity\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u6784\u5efa\u5e94\u7528\u7a0b\u5e8f\u7684\u7528\u6237\u7ba1\u7406\u65b9\u9762\u7684\u7cfb\u7edf\u3002\u5b83\u5904\u7406\u5c06\u7528\u6237\u4fdd\u5b58\u548c\u52a0\u8f7d\u5230\u6570\u636e\u5e93\u7684\u6240\u6709\u6837\u677f\uff0c\u4ee5\u53ca\u5b89\u5168\u6027\u6700\u4f73\u5b9e\u8df5\uff0c\u4f8b\u5982\u7528\u6237\u9501\u5b9a\u3001\u5bc6\u7801\u54c8\u5e0c\u548c\u591a\u91cd\u8eab\u4efd\u9a8c\u8bc1\u3002<\/p>\n<p><b>DEFINITION<\/b> Multifactor authentication (MFA), and the subset two-factor authentication (2FA) require both a password and an extra piece of information to sign in. This could involve sending a code to a user\u2019s phone by Short Message Service (SMS) or using a mobile app to generate a code, for example.<br \/>\n\u5b9a\u4e49:\u591a\u91cd\u8eab\u4efd\u9a8c\u8bc1 \uff08MFA\uff09 \u548c\u5b50\u96c6\u53cc\u91cd\u8eab\u4efd\u9a8c\u8bc1 \uff082FA\uff09 \u9700\u8981\u5bc6\u7801\u548c\u989d\u5916\u7684\u4fe1\u606f\u624d\u80fd\u767b\u5f55\u3002\u4f8b\u5982\uff0c\u8fd9\u53ef\u80fd\u6d89\u53ca\u901a\u8fc7\u77ed\u4fe1\u670d\u52a1 \uff08SMS\uff09 \u5411\u7528\u6237\u7684\u624b\u673a\u53d1\u9001\u9a8c\u8bc1\u7801\uff0c\u6216\u4f7f\u7528\u79fb\u52a8\u5e94\u7528\u751f\u6210\u9a8c\u8bc1\u7801\u3002<\/p>\n<p>In the next section I\u2019m going to talk about the ASP.NET Core Identity system, the problems it solves, when you\u2019d want to use it, and when you might not want to use it. In section 23.3 we take a look at some code and see ASP.NET Core Identity in action.<br \/>\n\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u8ba8\u8bba ASP.NET Core Identity \u7cfb\u7edf\u3001\u5b83\u89e3\u51b3\u7684\u95ee\u9898\u3001\u4f55\u65f6\u8981\u4f7f\u7528\u5b83\u4ee5\u53ca\u4f55\u65f6\u53ef\u80fd\u4e0d\u60f3\u4f7f\u7528\u5b83\u3002\u5728 Section 23.3 \u4e2d\uff0c\u6211\u4eec\u770b\u4e86\u4e00\u4e9b\u4ee3\u7801\uff0c\u5e76\u770b\u5230\u4e86 Core Identity ASP.NET \u5b9e\u9645\u5e94\u7528\u3002<\/p>\n<h2>23.2 What is ASP.NET Core Identity?<\/h2>\n<p>23.2 \u4ec0\u4e48\u662f ASP.NET Core Identity\uff1f<\/p>\n<p>Whenever you need to add nontrivial behaviors to your application, you typically need to add users and authentication. That means you\u2019ll need a way of persisting details about your users, such as their usernames and passwords.<br \/>\n\u6bcf\u5f53\u9700\u8981\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u91cd\u8981\u884c\u4e3a\u65f6\uff0c\u901a\u5e38\u9700\u8981\u6dfb\u52a0\u7528\u6237\u548c\u8eab\u4efd\u9a8c\u8bc1\u3002\u8fd9\u610f\u5473\u7740\u60a8\u9700\u8981\u4e00\u79cd\u65b9\u6cd5\u6765\u4fdd\u7559\u6709\u5173\u7528\u6237\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f8b\u5982\u4ed6\u4eec\u7684\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002<\/p>\n<p>This might seem like a relatively simple requirement, but given that this is related to security and people\u2019s personal details, it\u2019s important you get it right. As well as storing the claims for each user, it\u2019s important to store passwords using a strong hashing algorithm to allow users to use MFA where possible and to protect against brute-force attacks, to name a few of the many requirements. Although it\u2019s perfectly possible to write all the code to do this manually and to build your own authentication and membership system, I highly recommend you don\u2019t.<br \/>\n\u8fd9\u4f3c\u4e4e\u662f\u4e00\u4e2a\u76f8\u5bf9\u7b80\u5355\u7684\u8981\u6c42\uff0c\u4f46\u8003\u8651\u5230\u8fd9\u4e0e\u5b89\u5168\u548c\u4eba\u4eec\u7684\u4e2a\u4eba\u8be6\u7ec6\u4fe1\u606f\u6709\u5173\uff0c\u56e0\u6b64\u8bf7\u52a1\u5fc5\u6b63\u786e\u5904\u7406\u3002\u9664\u4e86\u5b58\u50a8\u6bcf\u4e2a\u7528\u6237\u7684\u58f0\u660e\u5916\uff0c\u4f7f\u7528\u5f3a\u5927\u7684\u54c8\u5e0c\u7b97\u6cd5\u5b58\u50a8\u5bc6\u7801\u4e5f\u5f88\u91cd\u8981\uff0c\u8fd9\u6837\u7528\u6237\u5c31\u53ef\u4ee5\u5c3d\u53ef\u80fd\u4f7f\u7528 MFA \u5e76\u9632\u6b62\u66b4\u529b\u653b\u51fb\uff0c\u4ec5\u4e3e\u51e0\u4f8b\u3002\u5c3d\u7ba1\u5b8c\u5168\u53ef\u4ee5\u7f16\u5199\u6240\u6709\u4ee3\u7801\u6765\u624b\u52a8\u6267\u884c\u6b64\u4f5c\u5e76\u6784\u5efa\u60a8\u81ea\u5df1\u7684\u8eab\u4efd\u9a8c\u8bc1\u548c\u6210\u5458\u8d44\u683c\u7cfb\u7edf\uff0c\u4f46\u6211\u5f3a\u70c8\u5efa\u8bae\u60a8\u4e0d\u8981\u8fd9\u6837\u505a\u3002<\/p>\n<p>I\u2019ve already mentioned third-party identity providers such as Auth0 and Azure Active Directory. These Software as a Service (SaaS) solutions take care of the user-management and authentication aspects of your app for you. If you\u2019re in the process of moving apps to the cloud generally, solutions like these can make a lot of sense.<br \/>\n\u6211\u5df2\u7ecf\u63d0\u5230\u4e86\u7b2c\u4e09\u65b9\u8eab\u4efd\u63d0\u4f9b\u5546\uff0c\u4f8b\u5982 Auth0 \u548c Azure Active Directory\u3002\u8fd9\u4e9b\u8f6f\u4ef6\u5373\u670d\u52a1 \uff08SaaS\uff09 \u89e3\u51b3\u65b9\u6848\u4e3a\u60a8\u5904\u7406\u5e94\u7528\u7a0b\u5e8f\u7684\u7528\u6237\u7ba1\u7406\u548c\u8eab\u4efd\u9a8c\u8bc1\u65b9\u9762\u3002\u5982\u679c\u60a8\u901a\u5e38\u6b63\u5728\u5c06\u5e94\u7528\u7a0b\u5e8f\u8fc1\u79fb\u5230\u4e91\uff0c\u90a3\u4e48\u50cf\u8fd9\u6837\u7684\u89e3\u51b3\u65b9\u6848\u53ef\u80fd\u975e\u5e38\u6709\u610f\u4e49\u3002<\/p>\n<p>If you can\u2019t or don\u2019t want to use these third-party solutions, I recommend you consider using the ASP.NET Core Identity system to store and manage user details in your database. ASP.NET Core Identity takes care of most of the boilerplate associated with authentication, but it remains flexible and lets you control the login process for users if you need to.<br \/>\n\u5982\u679c\u60a8\u4e0d\u80fd\u6216\u4e0d\u60f3\u4f7f\u7528\u8fd9\u4e9b\u7b2c\u4e09\u65b9\u89e3\u51b3\u65b9\u6848\uff0c\u6211\u5efa\u8bae\u60a8\u8003\u8651\u4f7f\u7528 ASP.NET Core Identity \u7cfb\u7edf\u5728\u60a8\u7684\u6570\u636e\u5e93\u4e2d\u5b58\u50a8\u548c\u7ba1\u7406\u7528\u6237\u8be6\u7ec6\u4fe1\u606f\u3002ASP.NET Core Identity \u8d1f\u8d23\u4e0e\u8eab\u4efd\u9a8c\u8bc1\u76f8\u5173\u7684\u5927\u90e8\u5206\u6837\u677f\uff0c\u4f46\u5b83\u4ecd\u7136\u4fdd\u6301\u7075\u6d3b\u6027\uff0c\u5e76\u5141\u8bb8\u60a8\u6839\u636e\u9700\u8981\u63a7\u5236\u7528\u6237\u7684\u767b\u5f55\u8fc7\u7a0b\u3002<\/p>\n<p><b>NOTE<\/b> ASP.NET Core Identity is an evolution of the legacy .NET Framework ASP.NET Identity system, with some design improvements and update to work with ASP.NET Core.<br \/>\n\u6ce8\u610f\uff1a ASP.NET Core Identity \u662f\u65e7\u7248 .NET Framework ASP.NET Identity \u7cfb\u7edf\u7684\u6f14\u53d8\uff0c\u7ecf\u8fc7\u4e00\u4e9b\u8bbe\u8ba1\u6539\u8fdb\u548c\u66f4\u65b0\u4ee5\u4e0e ASP.NET Core \u914d\u5408\u4f7f\u7528\u3002<\/p>\n<p>By default, ASP.NET Core Identity uses EF Core to store user details in the database. If you\u2019re already using EF Core in your project, this is a perfect fit. Alternatively, it\u2019s possible to write your own stores for loading and saving user details in another way.<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cASP.NET Core Identity \u4f7f\u7528 EF Core \u5c06\u7528\u6237\u8be6\u7ec6\u4fe1\u606f\u5b58\u50a8\u5728\u6570\u636e\u5e93\u4e2d\u3002\u5982\u679c\u4f60\u5df2\u5728\u9879\u76ee\u4e2d\u4f7f\u7528 EF Core\uff0c\u5219\u8fd9\u662f\u4e00\u4e2a\u5b8c\u7f8e\u7684\u9009\u62e9\u3002\u6216\u8005\uff0c\u53ef\u4ee5\u7f16\u5199\u81ea\u5df1\u7684 store \u4ee5\u53e6\u4e00\u79cd\u65b9\u5f0f\u52a0\u8f7d\u548c\u4fdd\u5b58\u7528\u6237\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>Identity takes care of the low-level parts of user management, as shown in table 23.1. As you can see from this list, Identity gives you a lot, but not everything\u2014by a long shot!<br \/>\nIdentity \u8d1f\u8d23\u7528\u6237 Management \u7684\u4f4e\u7ea7\u90e8\u5206\uff0c\u5982 Table 23.1 \u6240\u793a\u3002\u4ece\u8fd9\u4e2a\u5217\u8868\u4e2d\u53ef\u4ee5\u770b\u51fa\uff0cIdentity \u80fd\u7ed9\u4f60\u5f88\u591a\uff0c\u4f46\u4e0d\u662f\u5168\u90e8\u2014\u2014\u5f88\u957f\u4e00\u6bb5\u65f6\u95f4\uff01<\/p>\n<p>Table 23.1 Which services are and aren\u2019t handled by ASP.NET Core Identity<br \/>\n\u8868 23.1 \u54ea\u4e9b\u670d\u52a1\u7531 ASP.NET Core Identity \u5904\u7406\uff0c\u54ea\u4e9b\u670d\u52a1\u4e0d\u7531 Core Identity \u5904\u7406<\/p>\n<table>\n<thead>\n<tr>\n<th>Managed by ASP.NET Core Identity<\/th>\n<th>Requires implementing by the developer<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Database schema for storing users and claims<\/td>\n<td>UI for logging in, creating, and managing users (Razor Pages or controllers); included in an optional package that provides a default UI<\/td>\n<\/tr>\n<tr>\n<td>Creating a user in the database<\/td>\n<td>Sending email messages<\/td>\n<\/tr>\n<tr>\n<td>Password validation and rules<\/td>\n<td>Customizing claims for users (adding new claims)<\/td>\n<\/tr>\n<tr>\n<td>Handling user account lockout (to prevent brute-force attacks)<\/td>\n<td>Configuring third-party identity providers<\/td>\n<\/tr>\n<tr>\n<td>Managing and generating MFA\/2FA codes<\/td>\n<td>Integration into MFA such as sending SMS messages, time-based one-time password (TOTP) authenticator apps, or hardware keys<\/td>\n<\/tr>\n<tr>\n<td>Generating password-reset tokens<\/td>\n<td>-<\/td>\n<\/tr>\n<tr>\n<td>Saving additional claims to the database<\/td>\n<td>-<\/td>\n<\/tr>\n<tr>\n<td>Managing third-party identity providers (for example, Facebook, Google, and Twitter)<\/td>\n<td>-<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The biggest missing piece is the fact that you need to provide all the UI for the application, as well as tying all the individual Identity services together to create a functioning sign-in process. That\u2019s a big missing piece, but it makes the Identity system extremely flexible.<br \/>\n\u6700\u5927\u7684\u7f3a\u5931\u90e8\u5206\u662f\u60a8\u9700\u8981\u4e3a\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u6240\u6709 UI\uff0c\u4ee5\u53ca\u5c06\u6240\u6709\u5355\u72ec\u7684 Identity \u670d\u52a1\u6346\u7ed1\u5728\u4e00\u8d77\u4ee5\u521b\u5efa\u6709\u6548\u7684\u767b\u5f55\u8fc7\u7a0b\u3002\u8fd9\u662f\u4e00\u4e2a\u5f88\u5927\u7684\u7f3a\u5931\u90e8\u5206\uff0c\u4f46\u5b83\u4f7f Identity \u7cfb\u7edf\u975e\u5e38\u7075\u6d3b\u3002<\/p>\n<p>Luckily, ASP.NET Core includes a helper NuGet library, Microsoft.AspNetCore.Identity.UI, that gives you the whole of the UI boilerplate for free. That\u2019s over 30 Razor Pages with functionality for logging in, registering users, using 2FA, and using external login providers, among other features. You can still customize these pages if you need to, but having a whole login process working out of the box, with no code required on your part, is a huge win. We\u2019ll look at this library and how you use it in sections 23.3 and 23.4.<br \/>\n\u5e78\u8fd0\u7684\u662f\uff0cASP.NET Core \u5305\u542b\u4e00\u4e2a\u5e2e\u52a9\u7a0b\u5e8f NuGet \u5e93 Microsoft.AspNetCore.Identity.UI\uff0c\u5b83\u514d\u8d39\u4e3a\u60a8\u63d0\u4f9b\u6574\u4e2a UI \u6837\u677f\u3002\u8fd9\u662f 30 \u591a\u4e2a Razor \u9875\u9762\uff0c\u5177\u6709\u767b\u5f55\u3001\u6ce8\u518c\u7528\u6237\u3001\u4f7f\u7528 2FA \u548c\u4f7f\u7528\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u7b49\u529f\u80fd\u3002\u5982\u679c\u9700\u8981\uff0c\u60a8\u4ecd\u7136\u53ef\u4ee5\u81ea\u5b9a\u4e49\u8fd9\u4e9b\u9875\u9762\uff0c\u4f46\u662f\u62e5\u6709\u4e00\u4e2a\u5f00\u7bb1\u5373\u7528\u7684\u6574\u4e2a\u767b\u5f55\u8fc7\u7a0b\uff0c\u800c\u65e0\u9700\u60a8\u7f16\u5199\u4efb\u4f55\u4ee3\u7801\uff0c\u8fd9\u662f\u4e00\u4e2a\u5de8\u5927\u7684\u80dc\u5229\u3002\u6211\u4eec\u5c06\u5728 23.3 \u548c 23.4 \u8282\u4e2d\u4ecb\u7ecd\u8fd9\u4e2a\u5e93\u4ee5\u53ca\u4f60\u5982\u4f55\u4f7f\u7528\u5b83\u3002<\/p>\n<p>For that reason, I strongly recommend using the default UI as a starting point, whether you\u2019re creating an app or adding user management to an existing app. But the question remains as to when you should use Identity and when you should consider rolling your own.<br \/>\n\u56e0\u6b64\uff0c\u6211\u5f3a\u70c8\u5efa\u8bae\u4f7f\u7528\u9ed8\u8ba4 UI \u4f5c\u4e3a\u8d77\u70b9\uff0c\u65e0\u8bba\u60a8\u662f\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\u8fd8\u662f\u5411\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u7ba1\u7406\u3002\u4f46\u95ee\u9898\u4ecd\u7136\u5b58\u5728\uff0c\u4f55\u65f6\u5e94\u8be5\u4f7f\u7528 Identity \u4ee5\u53ca\u4f55\u65f6\u5e94\u8be5\u8003\u8651\u63a8\u51fa\u81ea\u5df1\u7684 Identity\u3002<\/p>\n<p>I\u2019m a big fan of Identity when you need to store your own users, so I tend to suggest it in most situations, as it handles a lot of security-related things for you that are easy to mess up. I\u2019ve heard several arguments against it, some valid and others less so:<br \/>\n\u5f53\u60a8\u9700\u8981\u5b58\u50a8\u81ea\u5df1\u7684\u7528\u6237\u65f6\uff0c\u6211\u662f Identity \u7684\u5fe0\u5b9e\u7c89\u4e1d\uff0c\u56e0\u6b64\u6211\u503e\u5411\u4e8e\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u5efa\u8bae\u4f7f\u7528\u5b83\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u4e3a\u60a8\u5904\u7406\u5f88\u591a\u4e0e\u5b89\u5168\u76f8\u5173\u7684\u4e8b\u60c5\uff0c\u8fd9\u4e9b\u4e8b\u60c5\u5f88\u5bb9\u6613\u641e\u7838\u3002\u6211\u542c\u5230\u4e86\u51e0\u4e2a\u53cd\u5bf9\u5b83\u7684\u8bba\u70b9\uff0c\u6709\u4e9b\u662f\u6709\u6548\u7684\uff0c\u6709\u4e9b\u5219\u4e0d\u592a\u6709\u6548\uff1a<\/p>\n<p>\u2022  I already have user authentication in my app. Great! In that case, you\u2019re probably right, Identity may not be necessary. But does your custom implementation use MFA? Do you have account lockout? If not, and if you need to add them, considering Identity may be worthwhile.<br \/>\n\u6211\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5df2\u7ecf\u6709\u7528\u6237\u8eab\u4efd\u9a8c\u8bc1\u3002\u592a\u597d\u4e86\uff01\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u60a8\u53ef\u80fd\u662f\u5bf9\u7684\uff0cIdentity \u53ef\u80fd\u4e0d\u662f\u5fc5\u9700\u7684\u3002\u4f46\u662f\u60a8\u7684\u81ea\u5b9a\u4e49\u5b9e\u65bd\u662f\u5426\u4f7f\u7528 MFA\uff1f\u60a8\u662f\u5426\u6709\u5e10\u6237\u9501\u5b9a\uff1f\u5982\u679c\u6ca1\u6709\uff0c\u5e76\u4e14\u60a8\u9700\u8981\u6dfb\u52a0\u5b83\u4eec\uff0c\u8003\u8651 Identity \u53ef\u80fd\u662f\u503c\u5f97\u7684\u3002<\/p>\n<p>\u2022  I don\u2019t want to use EF Core. That\u2019s a reasonable stance. You could be using Dapper, some other object-relational mapper (ORM), or even a document database for your database access. Luckily, the database integration in Identity is pluggable, so you could swap out the EF Core integration and use your own database integration libraries instead.<br \/>\n\u6211\u4e0d\u60f3\u4f7f\u7528 EF Core\u3002\u8fd9\u662f\u4e00\u4e2a\u5408\u7406\u7684\u7acb\u573a\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 Dapper\u3001\u5176\u4ed6\u4e00\u4e9b\u5bf9\u8c61\u5173\u7cfb\u6620\u5c04\u5668 \uff08ORM\uff09\uff0c\u751a\u81f3\u662f\u6587\u6863\u6570\u636e\u5e93\u6765\u8bbf\u95ee\u6570\u636e\u5e93\u3002\u5e78\u8fd0\u7684\u662f\uff0cIdentity \u4e2d\u7684\u6570\u636e\u5e93\u96c6\u6210\u662f\u53ef\u63d2\u62d4\u7684\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u6362\u6389 EF Core \u96c6\u6210\u5e76\u6539\u7528\u81ea\u5df1\u7684\u6570\u636e\u5e93\u96c6\u6210\u5e93\u3002<\/p>\n<p>\u2022  My use case is too complex for Identity. Identity provides lower-level services for authentication, so you can compose the pieces however you like. It\u2019s also extensible, so if you need to, for example, transform claims before creating a principal, you can.<br \/>\n\u6211\u7684\u7528\u4f8b\u5bf9\u4e8e Identity \u6765\u8bf4\u592a\u590d\u6742\u4e86\u3002Identity \u63d0\u4f9b\u8f83\u4f4e\u7ea7\u522b\u7684\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u6839\u636e\u81ea\u5df1\u7684\u559c\u597d\u7ec4\u5408\u5404\u4e2a\u90e8\u5206\u3002\u5b83\u4e5f\u662f\u53ef\u6269\u5c55\u7684\uff0c\u56e0\u6b64\uff0c\u5982\u679c\u9700\u8981\u5728\u521b\u5efa\u4e3b\u4f53\u4e4b\u524d\u8f6c\u6362\u58f0\u660e\uff0c\u5219\u53ef\u4ee5\u3002<\/p>\n<p>\u2022  I don\u2019t like the default Razor Pages UI. The default UI for Identity is entirely optional. You can still use the Identity services and user management but provide your own UI for logging in and registering users. However, be aware that although doing this gives you a lot of flexibility, it\u2019s also easy to introduce a security flaw in your user-management system\u2014the last place you want security flaws!<br \/>\n\u6211\u4e0d\u559c\u6b22\u9ed8\u8ba4\u7684 Razor Pages UI\u3002Identity \u7684\u9ed8\u8ba4 UI \u5b8c\u5168\u662f\u53ef\u9009\u7684\u3002\u60a8\u4ecd\u7136\u53ef\u4ee5\u4f7f\u7528 Identity \u670d\u52a1\u548c\u7528\u6237\u7ba1\u7406\uff0c\u4f46\u63d0\u4f9b\u81ea\u5df1\u7684 UI \u6765\u767b\u5f55\u548c\u6ce8\u518c\u7528\u6237\u3002\u4f46\u662f\uff0c\u8bf7\u6ce8\u610f\uff0c\u5c3d\u7ba1\u8fd9\u6837\u505a\u53ef\u4ee5\u4e3a\u60a8\u63d0\u4f9b\u5f88\u5927\u7684\u7075\u6d3b\u6027\uff0c\u4f46\u4e5f\u5f88\u5bb9\u6613\u5728\u7528\u6237\u7ba1\u7406\u7cfb\u7edf\u4e2d\u5f15\u5165\u5b89\u5168\u6f0f\u6d1e - \u8fd9\u662f\u60a8\u6700\u4e0d\u5e0c\u671b\u51fa\u73b0\u5b89\u5168\u6f0f\u6d1e\u7684\u5730\u65b9\uff01<\/p>\n<p>\u2022  I\u2019m not using Bootstrap to style my application. The default Identity UI uses Bootstrap as a styling framework, the same as the default ASP.NET Core templates. Unfortunately, you can\u2019t easily change that, so if you\u2019re using a different framework or need to customize the HTML generated, you can still use Identity, but you\u2019ll need to provide your own UI.<br \/>\n\u6211\u6ca1\u6709\u4f7f\u7528 Bootstrap \u6765\u8bbe\u7f6e\u5e94\u7528\u7a0b\u5e8f\u7684\u6837\u5f0f\u3002\u9ed8\u8ba4\u8eab\u4efd UI \u4f7f\u7528 Bootstrap \u4f5c\u4e3a\u6837\u5f0f\u6846\u67b6\uff0c\u4e0e\u9ed8\u8ba4\u7684 ASP.NET Core \u6a21\u677f\u76f8\u540c\u3002\u9057\u61be\u7684\u662f\uff0c\u60a8\u65e0\u6cd5\u8f7b\u677e\u66f4\u6539\u6b64\u8bbe\u7f6e\uff0c\u56e0\u6b64\uff0c\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f\u5176\u4ed6\u6846\u67b6\u6216\u9700\u8981\u81ea\u5b9a\u4e49\u751f\u6210\u7684 HTML\uff0c\u60a8\u4ecd\u7136\u53ef\u4ee5\u4f7f\u7528 Identity\uff0c\u4f46\u9700\u8981\u63d0\u4f9b\u81ea\u5df1\u7684 UI\u3002<\/p>\n<p>\u2022  I don\u2019t want to build my own identity system. I\u2019m glad to hear it. Using an external identity provider like Azure Active Directory or Auth0 is a great way of shifting the responsibility and risk associated with storing users\u2019 personal information to a third party.<br \/>\n\u6211\u4e0d\u60f3\u6784\u5efa\u81ea\u5df1\u7684\u8eab\u4efd\u7cfb\u7edf\u3002\u6211\u5f88\u9ad8\u5174\u542c\u5230\u8fd9\u4e2a\u6d88\u606f\u3002\u4f7f\u7528 Azure Active Directory \u6216 Auth0 \u7b49\u5916\u90e8\u8eab\u4efd\u63d0\u4f9b\u5546\u662f\u5c06\u4e0e\u5b58\u50a8\u7528\u6237\u4e2a\u4eba\u4fe1\u606f\u76f8\u5173\u7684\u8d23\u4efb\u548c\u98ce\u9669\u8f6c\u79fb\u7ed9\u7b2c\u4e09\u65b9\u7684\u597d\u65b9\u6cd5\u3002<\/p>\n<p>Any time you\u2019re considering adding user management to your ASP.NET Core application, I\u2019d recommend looking at Identity as a great option for doing so. In the next section I\u2019ll demonstrate what Identity provides by creating a new Razor Pages application using the default Identity UI. In section 23.4 we\u2019ll take that template and apply it to an existing app instead, and in sections 23.5 and 23.6 you\u2019ll see how to override the default pages.<br \/>\n\u6bcf\u5f53\u4f60\u8003\u8651\u5411 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u7ba1\u7406\u65f6\uff0c\u6211\u5efa\u8bae\u5c06 Identity \u89c6\u4e3a\u4e00\u4e2a\u4e0d\u9519\u7684\u9009\u62e9\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u901a\u8fc7\u4f7f\u7528\u9ed8\u8ba4\u6807\u8bc6 UI \u521b\u5efa\u65b0\u7684 Razor Pages \u5e94\u7528\u7a0b\u5e8f\u6765\u6f14\u793a\u6807\u8bc6\u63d0\u4f9b\u7684\u529f\u80fd\u3002\u5728 23.4 \u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u83b7\u53d6\u8be5\u6a21\u677f\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\uff0c\u5728 23.5 \u548c 23.6 \u8282\u4e2d\uff0c\u60a8\u5c06\u770b\u5230\u5982\u4f55\u8986\u76d6\u9ed8\u8ba4\u9875\u9762\u3002<\/p>\n<h2>23.3 Creating a project that uses ASP.NET Core Identity<\/h2>\n<p>23.3 \u521b\u5efa\u4f7f\u7528 ASP.NET Core Identity \u7684\u9879\u76ee<\/p>\n<p>I\u2019ve covered authentication and Identity in general terms, but the best way to get a feel for it is to see some working code. In this section we\u2019re going to look at the default code generated by the ASP.NET Core templates with Identity, how the project works, and where Identity fits in.<br \/>\n\u6211\u5df2\u7ecf\u5927\u81f4\u4ecb\u7ecd\u4e86\u8eab\u4efd\u9a8c\u8bc1\u548c\u6807\u8bc6\uff0c\u4f46\u4e86\u89e3\u5b83\u7684\u6700\u4f73\u65b9\u6cd5\u662f\u67e5\u770b\u4e00\u4e9b\u5de5\u4f5c\u4ee3\u7801\u3002\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u4f7f\u7528 Identity \u7684 ASP.NET Core \u6a21\u677f\u751f\u6210\u7684\u9ed8\u8ba4\u4ee3\u7801\u3001\u9879\u76ee\u7684\u5de5\u4f5c\u539f\u7406\u4ee5\u53ca Identity \u7684\u9002\u7528\u8303\u56f4\u3002<\/p>\n<h3>23.3.1 Creating the project from a template<\/h3>\n<p>23.3.1 \u4ece\u6a21\u677f\u521b\u5efa\u9879\u76ee<\/p>\n<p>You\u2019ll start by using the Visual Studio templates to generate a simple Razor Pages application that uses Identity for storing individual user accounts in a database.<br \/>\n\u9996\u5148\uff0c\u4f7f\u7528 Visual Studio \u6a21\u677f\u751f\u6210\u4e00\u4e2a\u7b80\u5355\u7684 Razor Pages \u5e94\u7528\u7a0b\u5e8f\uff0c\u8be5\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528 Identity \u5c06\u5404\u4e2a\u7528\u6237\u5e10\u6237\u5b58\u50a8\u5728\u6570\u636e\u5e93\u4e2d\u3002<\/p>\n<p><b>Tip<\/b> You can create a similar project using the .NET CLI by running dotnet new webapp -au Individual. The Visual Studio template uses a LocalDB database, but the dotnet new template uses SQLite by default. To use LocalDB instead, run dotnet new webapp -au Individual --use-local-db.<br \/>\n\u63d0\u793a\uff1a\u60a8\u53ef\u4ee5\u901a\u8fc7\u8fd0\u884c dotnet new webapp -au Individual \u6765\u4f7f\u7528 .NET CLI \u521b\u5efa\u7c7b\u4f3c\u7684\u9879\u76ee\u3002Visual Studio \u6a21\u677f\u4f7f\u7528 LocalDB \u6570\u636e\u5e93\uff0c\u4f46 dotnet \u65b0\u6a21\u677f\u9ed8\u8ba4\u4f7f\u7528 SQLite\u3002\u8981\u6539\u7528 LocalDB\uff0c\u8bf7\u8fd0\u884c dotnet new webapp -au Individual --use-local-db\u3002<\/p>\n<p>To create the template using Visual Studio, you must be using the 2022 version or later and have the .NET 7 software development kit (SDK) installed. Follow these steps:<br \/>\n\u8981\u4f7f\u7528 Visual Studio \u521b\u5efa\u6a21\u677f\uff0c\u60a8\u5fc5\u987b\u4f7f\u7528 2022 \u7248\u672c\u6216\u66f4\u9ad8\u7248\u672c\uff0c\u5e76\u5b89\u88c5 .NET 7 \u8f6f\u4ef6\u5f00\u53d1\u5de5\u5177\u5305 \uff08SDK\uff09\u3002\u8bf7\u6267\u884c\u4ee5\u4e0b\u6b65\u9aa4\uff1a<\/p>\n<ol>\n<li>\n<p>Choose <code>File &gt; New &gt; Project<\/code> or choose Create a New Project on the splash screen.<br \/>\n\u5728\u521d\u59cb\u5c4f\u5e55\u4e0a\u9009\u62e9<code>File &gt; New &gt; Project<\/code> \u521b\u5efa\u65b0\u9879\u76ee\u3002<\/p>\n<\/li>\n<li>\n<p>From the list of templates, choose ASP.NET Core Web Application, ensuring that you select the C# language template.<br \/>\n\u4ece\u6a21\u677f\u5217\u8868\u4e2d\uff0c\u9009\u62e9 ASP.NET Core Web Application\uff08\u6838\u5fc3 Web \u5e94\u7528\u7a0b\u5e8f\uff09\uff0c\u786e\u4fdd\u9009\u62e9 C# \u8bed\u8a00\u6a21\u677f\u3002<\/p>\n<\/li>\n<li>\n<p>On the next screen, enter a project name, location, and a solution name, and choose Create.<br \/>\n\u5728\u4e0b\u4e00\u4e2a\u5c4f\u5e55\u4e0a\uff0c\u8f93\u5165\u9879\u76ee\u540d\u79f0\u3001\u4f4d\u7f6e\u548c\u89e3\u51b3\u65b9\u6848\u540d\u79f0\uff0c\u7136\u540e\u9009\u62e9 Create \uff08\u521b\u5efa\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>On the Additional Information screen, change the Authentication type to Individual Accounts, as shown in figure 23.4. Leave the other settings at their defaults, and choose Create to create the application.<br \/>\n\u5728 Additional Information \u5c4f\u5e55\u4e0a\uff0c\u5c06 Authentication type \u66f4\u6539\u4e3a Individual Accounts\uff0c\u5982\u56fe 23.4 \u6240\u793a\u3002\u5c06\u5176\u4ed6\u8bbe\u7f6e\u4fdd\u7559\u4e3a\u9ed8\u8ba4\u503c\uff0c\u7136\u540e\u9009\u62e9 Create \uff08\u521b\u5efa\uff09 \u4ee5\u521b\u5efa\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<\/li>\n<\/ol>\n<p>Visual Studio automatically runs dotnet restore to restore all the necessary NuGet packages for the project.<br \/>\nVisual Studio \u4f1a\u81ea\u52a8\u8fd0\u884c dotnet restore \u6765\u8fd8\u539f\u9879\u76ee\u6240\u9700\u7684\u6240\u6709 NuGet \u5305\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2304.png\" alt=\"alt text\" \/><br \/>\nFigure 23.4 Choosing the authentication mode of the new ASP.NET Core application template in VS 2022<br \/>\n\u56fe 23.4 \u5728 VS 2022 \u4e2d\u9009\u62e9\u65b0 ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u6a21\u677f\u7684\u8eab\u4efd\u9a8c\u8bc1\u6a21\u5f0f<\/p>\n<ol start=\"5\">\n<li>Run the application to see the default app, as shown in figure 23.5.<br \/>\n\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u4ee5\u67e5\u770b\u9ed8\u8ba4\u5e94\u7528\u7a0b\u5e8f\uff0c\u5982\u56fe 23.5 \u6240\u793a\u3002<\/li>\n<\/ol>\n<p><b>NOTE<\/b> The Visual Studio template configures the application to use LocalDB and includes EF Core migrations for SQL Server. If you want to use a different database provider, you can replace the configuration and migrations with your database of choice, as described in chapter 12.<br \/>\n\u6ce8\u610f\uff1aVisual Studio \u6a21\u677f\u5c06\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e3a\u4f7f\u7528 LocalDB\uff0c\u5e76\u5305\u62ec SQL Server \u7684 EF Core \u8fc1\u79fb\u3002\u5982\u679c\u8981\u4f7f\u7528\u4e0d\u540c\u7684\u6570\u636e\u5e93\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u5c06\u914d\u7f6e\u548c\u8fc1\u79fb\u66ff\u6362\u4e3a\u60a8\u9009\u62e9\u7684\u6570\u636e\u5e93\uff0c\u5982\u7b2c 12 \u7ae0\u6240\u8ff0\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2305.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.5 The default template with individual account authentication looks similar to the no authentication template, with the addition of a Login widget at the top right of the page.<br \/>\n\u56fe 23.5 \u5177\u6709\u4e2a\u4eba\u5e10\u6237\u8eab\u4efd\u9a8c\u8bc1\u7684\u9ed8\u8ba4\u6a21\u677f\u770b\u8d77\u6765\u7c7b\u4f3c\u4e8e\u65e0\u8eab\u4efd\u9a8c\u8bc1\u6a21\u677f\uff0c\u53ea\u662f\u5728\u9875\u9762\u53f3\u4e0a\u89d2\u6dfb\u52a0\u4e86\u4e00\u4e2a Login \u5c0f\u90e8\u4ef6\u3002<\/p>\n<p>This template should look familiar, with one twist: you now have Register and Login buttons! Feel free to play with the template\u2014creating a user, logging in and out\u2014to get a feel for the app. Once you\u2019re happy, look at the code generated by the template and the boilerplate it saved you from writing.<br \/>\n\u8fd9\u4e2a\u6a21\u677f\u5e94\u8be5\u770b\u8d77\u6765\u5f88\u719f\u6089\uff0c\u4f46\u6709\u4e00\u4e2a\u53d8\u5316\uff1a\u60a8\u73b0\u5728\u6709 Register \u548c Login \u6309\u94ae\u4e86\uff01\u60a8\u53ef\u4ee5\u968f\u610f\u4f7f\u7528\u6a21\u677f \u2014 \u521b\u5efa\u7528\u6237\u3001\u767b\u5f55\u548c\u6ce8\u9500 \u2014 \u4ee5\u611f\u53d7\u5e94\u7528\u7a0b\u5e8f\u3002\u6ee1\u610f\u540e\uff0c\u8bf7\u67e5\u770b\u6a21\u677f\u751f\u6210\u7684\u4ee3\u7801\u4ee5\u53ca\u5b83\u4f7f\u60a8\u514d\u4e8e\u7f16\u5199\u7684\u6837\u677f\u3002<\/p>\n<p><b>Tip<\/b> Don\u2019t forget to run the included EF Core migrations before trying to create users. Run dotnet ef database update from the project folder.<br \/>\n\u63d0\u793a\uff1a\u5728\u5c1d\u8bd5\u521b\u5efa\u7528\u6237\u4e4b\u524d\uff0c\u8bf7\u4e0d\u8981\u5fd8\u8bb0\u8fd0\u884c\u5305\u542b\u7684 EF Core \u8fc1\u79fb\u3002\u4ece\u9879\u76ee\u6587\u4ef6\u5939\u8fd0\u884c dotnet ef database update\u3002<\/p>\n<h3>23.3.2 Exploring the template in Solution Explorer<\/h3>\n<p>23.3.2 \u5728\u89e3\u51b3\u65b9\u6848\u8d44\u6e90\u7ba1\u7406\u5668\u4e2d\u6d4f\u89c8\u6a21\u677f<\/p>\n<p>The project generated by the template, shown in figure 23.6, is similar to the default no-authentication template. That\u2019s largely due to the default UI library, which brings in a big chunk of functionality without exposing you to the nitty-gritty details.<br \/>\n\u8be5\u6a21\u677f\u751f\u6210\u7684\u9879\u76ee\uff08\u5982\u56fe 23.6 \u6240\u793a\uff09\u7c7b\u4f3c\u4e8e\u9ed8\u8ba4\u7684 no-authentication \u6a21\u677f\u3002\u8fd9\u4e3b\u8981\u662f\u7531\u4e8e\u9ed8\u8ba4\u7684 UI \u5e93\uff0c\u5b83\u5e26\u6765\u4e86\u5927\u91cf\u529f\u80fd\uff0c\u800c\u4e0d\u4f1a\u8ba9\u60a8\u4e86\u89e3\u7ec6\u8282\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2306.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.6 The project layout of the default template with individual authentication<br \/>\n\u56fe 23.6 \u4f7f\u7528\u5355\u72ec\u8eab\u4efd\u9a8c\u8bc1\u7684\u9ed8\u8ba4\u6a21\u677f\u7684\u9879\u76ee\u5e03\u5c40<\/p>\n<p>The biggest addition is the Areas folder in the root of your project, which contains an Identity subfolder. Areas are sometimes used for organizing sections of functionality. Each area can contain its own Pages folder, which is analogous to the main Pages folder in your application.<br \/>\n\u6700\u5927\u7684\u65b0\u589e\u529f\u80fd\u662f\u9879\u76ee\u6839\u76ee\u5f55\u4e2d\u7684 Areas \u6587\u4ef6\u5939\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a Identity \u5b50\u6587\u4ef6\u5939\u3002\u533a\u57df\u6709\u65f6\u7528\u4e8e\u7ec4\u7ec7\u529f\u80fd\u90e8\u5206\u3002\u6bcf\u4e2a\u533a\u57df\u90fd\u53ef\u4ee5\u5305\u542b\u81ea\u5df1\u7684 Pages \u6587\u4ef6\u5939\uff0c\u8be5\u6587\u4ef6\u5939\u7c7b\u4f3c\u4e8e\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u4e3b Pages \u6587\u4ef6\u5939\u3002<\/p>\n<p><b>DEFINITION<\/b> Areas are used to group Razor Pages into separate hierarchies for organizational purposes. I rarely use areas and prefer to create subfolders in the main Pages folder instead. The one exception is the Identity UI, which uses a separate Identity area by default. For more details on areas, see Microsoft\u2019s \u201cAreas in ASP.NET Core\u201d documentation: <a href=\"http:\/\/mng.bz\/7Vw9\">http:\/\/mng.bz\/7Vw9<\/a>.<br \/>\n\u5b9a\u4e49\uff1a\u533a\u57df\u7528\u4e8e\u5c06 Razor \u9875\u9762\u5206\u7ec4\u5230\u5355\u72ec\u7684\u5c42\u6b21\u7ed3\u6784\u4e2d\uff0c\u4ee5\u4fbf\u8fdb\u884c\u7ec4\u7ec7\u3002\u6211\u5f88\u5c11\u4f7f\u7528\u533a\u57df\uff0c\u66f4\u559c\u6b22\u5728\u4e3b Pages \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u5b50\u6587\u4ef6\u5939\u3002\u4e00\u4e2a\u4f8b\u5916\u662f Identity UI\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f7f\u7528\u5355\u72ec\u7684 Identity \u533a\u57df\u3002\u6709\u5173\u533a\u57df\u7684\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 Microsoft \u7684\u201cASP.NET Core \u4e2d\u7684\u533a\u57df\u201d\u6587\u6863\uff1a<a href=\"http:\/\/mng.bz\/7Vw9\">http:\/\/mng.bz\/7Vw9<\/a>\u3002<\/p>\n<p>The Microsoft.AspNetCore.Identity.UI package creates Razor Pages in the Identity area. You can override any page in this default UI by creating a corresponding page in the Areas\/Identity\/Pages folder in your application. In figure 23.6, the default template adds a _ViewStart.cshtml file that overrides the template that is included as part of the default UI. This file contains the following code, which sets the default Identity UI Razor Pages to use your project\u2019s default _Layout.cshtml file:<br \/>\nMicrosoft.AspNetCore.Identity.UI \u5305\u5728\u201c\u6807\u8bc6\u201d\u533a\u57df\u4e2d\u521b\u5efa Razor Pages\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u5728\u5e94\u7528\u7a0b\u5e8f\u7684 Areas\/Identity\/Pages \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u76f8\u5e94\u7684\u9875\u9762\u6765\u8986\u76d6\u6b64\u9ed8\u8ba4 UI \u4e2d\u7684\u4efb\u4f55\u9875\u9762\u3002\u5728\u56fe 23.6 \u4e2d\uff0c\u9ed8\u8ba4\u6a21\u677f\u6dfb\u52a0\u4e86\u4e00\u4e2a _ViewStart.cshtml \u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u5c06\u66ff\u4ee3\u4f5c\u4e3a\u9ed8\u8ba4 UI \u7684\u4e00\u90e8\u5206\u5305\u542b\u7684\u6a21\u677f\u3002\u6b64\u6587\u4ef6\u5305\u542b\u4ee5\u4e0b\u4ee3\u7801\uff0c\u8be5\u4ee3\u7801\u5c06\u9ed8\u8ba4\u6807\u8bc6 UI Razor \u9875\u9762\u8bbe\u7f6e\u4e3a\u4f7f\u7528\u9879\u76ee\u7684\u9ed8\u8ba4 _Layout.cshtml \u6587\u4ef6\uff1a<\/p>\n<pre><code>@{\n    Layout = &quot;\/Pages\/Shared\/_Layout.cshtml&quot;;\n}<\/code><\/pre>\n<p>Some obvious questions at this point are \u201cHow do you know what\u2019s included in the default UI?\u201d and \u201cWhich files can you override?\u201d You\u2019ll see the answers to both in section 23.5, but in general you should try to avoid overriding files where possible. After all, the goal with the default UI is to reduce the amount of code you have to write!<br \/>\n\u6b64\u65f6\uff0c\u4e00\u4e9b\u660e\u663e\u7684\u95ee\u9898\u662f\u201c\u60a8\u5982\u4f55\u77e5\u9053\u9ed8\u8ba4 UI \u4e2d\u5305\u542b\u54ea\u4e9b\u5185\u5bb9\u201d\u548c\u201c\u60a8\u53ef\u4ee5\u8986\u76d6\u54ea\u4e9b\u6587\u4ef6\uff1f\u60a8\u5c06\u5728 Section 23.5 \u4e2d\u770b\u5230\u8fd9\u4e24\u4e2a\u95ee\u9898\u7684\u7b54\u6848\uff0c\u4f46\u4e00\u822c\u6765\u8bf4\uff0c\u60a8\u5e94\u8be5\u5c3d\u53ef\u80fd\u907f\u514d\u8986\u76d6\u6587\u4ef6\u3002\u6bd5\u7adf\uff0c\u9ed8\u8ba4 UI \u7684\u76ee\u6807\u662f\u51cf\u5c11\u60a8\u5fc5\u987b\u7f16\u5199\u7684\u4ee3\u7801\u91cf\uff01<\/p>\n<p>The Data folder in your new project template contains your application\u2019s EF Core DbContext, called ApplicationDbContext, and the migrations for configuring the database schema to use Identity. I\u2019ll discuss this schema in more detail in section 23.3.3.<br \/>\n\u65b0\u9879\u76ee\u6a21\u677f\u4e2d\u7684 Data \u6587\u4ef6\u5939\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684 EF Core DbContext\uff08\u79f0\u4e3a ApplicationDbContext\uff09\u548c\u7528\u4e8e\u5c06\u6570\u636e\u5e93\u67b6\u6784\u914d\u7f6e\u4e3a\u4f7f\u7528 Identity \u7684\u8fc1\u79fb\u3002\u6211\u5c06\u5728 Section 23.3.3 \u4e2d\u66f4\u8be6\u7ec6\u5730\u8ba8\u8bba\u8fd9\u4e2a\u6a21\u5f0f\u3002<\/p>\n<p>The final additional file included in this template compared with the no-authentication version is the partial Razor view Pages\/Shared\/_LoginPartial.cshtml. This provides the Register and Login links you saw in figure 23.5, and it\u2019s rendered in the default Razor layout, _Layout.cshtml.<br \/>\n\u4e0e\u65e0\u8eab\u4efd\u9a8c\u8bc1\u7248\u672c\u76f8\u6bd4\uff0c\u6b64\u6a21\u677f\u4e2d\u5305\u542b\u7684\u6700\u540e\u4e00\u4e2a\u9644\u52a0\u6587\u4ef6\u662f\u90e8\u5206 Razor \u89c6\u56fe Pages\/Shared\/_LoginPartial.cshtml\u3002\u8fd9\u63d0\u4f9b\u4e86\u4f60\u5728\u56fe 23.5 \u4e2d\u770b\u5230\u7684 Register \u548c Login \u94fe\u63a5\uff0c\u5e76\u5448\u73b0\u5728\u9ed8\u8ba4\u7684 Razor \u5e03\u5c40 _Layout.cshtml \u4e2d\u3002<\/p>\n<p>If you look inside _LoginPartial.cshtml, you can see how routing works with areas by combining the Razor Page path with an {area} route parameter using Tag Helpers. For example, the Login link specifies that the Razor Page \/Account\/Login is in the Identity area using the asp-area attribute:<br \/>\n\u5982\u679c\u67e5\u770b _LoginPartial.cshtml\uff0c\u5219\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528\u6807\u8bb0\u5e2e\u52a9\u7a0b\u5e8f\u5c06 Razor Page \u8def\u5f84\u4e0e {area} \u8def\u7531\u53c2\u6570\u7ec4\u5408\u5728\u4e00\u8d77\uff0c\u4e86\u89e3\u8def\u7531\u5982\u4f55\u4e0e\u533a\u57df\u914d\u5408\u4f7f\u7528\u3002\u4f8b\u5982\uff0cLogin \u94fe\u63a5\u4f7f\u7528 asp-area \u5c5e\u6027\u6307\u5b9a Razor Page \/Account\/Login \u4f4d\u4e8e Identity \u533a\u57df\u4e2d\uff1a<\/p>\n<pre><code>&lt;a asp-area=&quot;Identity&quot; asp-page=&quot;\/Account\/Login&quot;&gt;Login&lt;\/a&gt;<\/code><\/pre>\n<p><b>Tip<\/b> You can reference Razor Pages in the Identity area by setting the area route value to Identity. You can use the asp-area attribute in Tag Helpers that generate links.<br \/>\n\u63d0\u793a\uff1a\u53ef\u4ee5\u901a\u8fc7\u5c06\u533a\u57df\u8def\u7531\u503c\u8bbe\u7f6e\u4e3a Identity \u6765\u5f15\u7528 Identity \u533a\u57df\u4e2d\u7684 Razor Pages\u3002\u60a8\u53ef\u4ee5\u5728\u751f\u6210\u94fe\u63a5\u7684\u6807\u8bb0\u5e2e\u52a9\u7a0b\u5e8f\u4e2d\u4f7f\u7528 asp-area \u5c5e\u6027\u3002<\/p>\n<p>In addition to viewing the new files included thanks to ASP.NET Core Identity, open Program.cs and look at the changes there. The most obvious change is the additional configuration, which adds all the services Identity requires, as shown in the following listing.<br \/>\n\u9664\u4e86\u67e5\u770b ASP.NET Core Identity \u5305\u542b\u7684\u65b0\u6587\u4ef6\u5916\uff0c\u8fd8\u53ef\u4ee5\u6253\u5f00 Program.cs \u5e76\u67e5\u770b\u5176\u4e2d\u7684\u66f4\u6539\u3002\u6700\u660e\u663e\u7684\u53d8\u5316\u662f\u989d\u5916\u7684\u914d\u7f6e\uff0c\u5b83\u6dfb\u52a0\u4e86 Identity \u6240\u9700\u7684\u6240\u6709\u670d\u52a1\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 23.1 Adding ASP.NET Core Identity services to ConfigureServices<br \/>\n\u6e05\u5355 23.1 \u5411 ConfigureServices \u6dfb\u52a0 ASP.NET Core Identity \u670d\u52a1<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nstring connectionString = builder.Configuration     #A\n    .GetConnectionString(&quot;DefaultConnection&quot;);    #A\nbuilder.Services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;  #A\n    options.UseSqlServer(connectionString));    #A\n\nbuilder.Services.AddDatabaseDeveloperPageExceptionFilter();   #B\n\nbuilder.Services.AddDefaultIdentity&lt;IdentityUser&gt;(options =&gt;    #C\n    options.SignIn.RequireConfirmedAccount = true)    #D\n        .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();    #E\nbuilder.Services.AddRazorPages();\n\n\/\/ remaining configuration not show\n<\/code><\/pre>\n<p>\u2776 ASP.NET Core Identity uses EF Core, so it includes the standard EF Core configuration.<br \/>\nASP.NET Core Identity \u4f7f\u7528 EF Core\uff0c\u56e0\u6b64\u5b83\u5305\u62ec\u6807\u51c6 EF Core \u914d\u7f6e\u3002<br \/>\n\u2777 Adds optional database services to enhance the DeveloperExceptionPage<br \/>\n\u6dfb\u52a0\u53ef\u9009\u7684\u6570\u636e\u5e93\u670d\u52a1\u4ee5\u589e\u5f3a DeveloperExceptionPage<br \/>\n\u2778 Adds the Identity system, including the default UI, and configures the user type as IdentityUser<br \/>\n\u6dfb\u52a0\u6807\u8bc6\u7cfb\u7edf\uff0c\u5305\u62ec\u9ed8\u8ba4 UI\uff0c\u5e76\u5c06\u7528\u6237\u7c7b\u578b\u914d\u7f6e\u4e3a IdentityUser<br \/>\n\u2779 Requires users to confirm their accounts (typically by email) before they log in<br \/>\n\u8981\u6c42\u7528\u6237\u5728\u767b\u5f55\u524d\u786e\u8ba4\u5176\u5e10\u6237\uff08\u901a\u5e38\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\uff09<br \/>\n\u277a Configures Identity to store its data in EF Core<br \/>\n\u914d\u7f6e\u6807\u8bc6\u4ee5\u5c06\u5176\u6570\u636e\u5b58\u50a8\u5728 EF Core \u4e2d<\/p>\n<p>The AddDefaultIdentity() extension method does several things:<br \/>\nAddDefaultIdentity\uff08\uff09 \u6269\u5c55\u65b9\u6cd5\u6267\u884c\u4ee5\u4e0b\u51e0\u9879\u4f5c\uff1a<\/p>\n<p>\u2022  Adds the core ASP.NET Core Identity services.<br \/>\n\u6dfb\u52a0\u6838\u5fc3 ASP.NET \u6838\u5fc3\u8eab\u4efd\u670d\u52a1\u3002<br \/>\n\u2022  Configures the application user type to be IdentityUser. This is the entity model that is stored in the database and represents a \u201cuser\u201d in your application. You can extend this type if you need to, but that\u2019s not always necessary, as you\u2019ll see in section 23.6.<br \/>\n\u5c06\u5e94\u7528\u7a0b\u5e8f\u7528\u6237\u7c7b\u578b\u914d\u7f6e\u4e3a IdentityUser\u3002\u8fd9\u662f\u5b58\u50a8\u5728\u6570\u636e\u5e93\u4e2d\u7684\u5b9e\u4f53\u6a21\u578b\uff0c\u8868\u793a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684 \u201c\u7528\u6237\u201d\u3002\u5982\u679c\u9700\u8981\uff0c\u60a8\u53ef\u4ee5\u6269\u5c55\u6b64\u7c7b\u578b\uff0c\u4f46\u8fd9\u5e76\u4e0d\u603b\u662f\u5fc5\u8981\u7684\uff0c\u5982\u7b2c 23.6 \u8282\u6240\u793a\u3002<br \/>\n\u2022  Adds the default UI Razor Pages for registering, logging in, and managing users.<br \/>\n\u6dfb\u52a0\u7528\u4e8e\u6ce8\u518c\u3001\u767b\u5f55\u548c\u7ba1\u7406\u7528\u6237\u7684\u9ed8\u8ba4 UI Razor Pages\u3002<br \/>\n\u2022  Configures token providers for generating MFA and email confirmation tokens.<br \/>\n\u914d\u7f6e\u7528\u4e8e\u751f\u6210 MFA \u548c\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\u4ee4\u724c\u7684\u4ee4\u724c\u63d0\u4f9b\u7a0b\u5e8f\u3002<\/p>\n<blockquote>\n<p>Where is the authentication middleware?<br \/>\n\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u5728\u54ea\u91cc\uff1f<\/p>\n<p>If you\u2019re already familiar with previous versions of ASP.NET Core, you might be surprised to notice the lack of any authentication middleware in the default template. Given everything you\u2019ve learned about how authentication works, that should be surprising!<br \/>\n\u5982\u679c\u60a8\u5df2\u7ecf\u719f\u6089 ASP.NET Core \u7684\u65e9\u671f\u7248\u672c\uff0c\u60a8\u53ef\u80fd\u4f1a\u60ca\u8bb6\u5730\u6ce8\u610f\u5230\u9ed8\u8ba4\u6a21\u677f\u4e2d\u7f3a\u5c11\u4efb\u4f55\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u3002\u9274\u4e8e\u60a8\u5b66\u5230\u7684\u6709\u5173\u8eab\u4efd\u9a8c\u8bc1\u5de5\u4f5c\u539f\u7406\u7684\u6240\u6709\u4fe1\u606f\uff0c\u8fd9\u5e94\u8be5\u4ee4\u4eba\u60ca\u8bb6\uff01<\/p>\n<p>The answer to this riddle is that the authentication middleware is in the pipeline, even though you can\u2019t see it. As I discussed in chapter 4, WebApplication automatically adds many middleware components to the pipeline for you, including the routing middleware, the endpoint middleware, and\u2014yes\u2014the authentication middleware. So the reason you don\u2019t see it in the pipeline is that it\u2019s already been added.<br \/>\n\u8fd9\u4e2a\u8c1c\u9898\u7684\u7b54\u6848\u662f\uff0c\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u6b63\u5728\u5f00\u53d1\u4e2d\uff0c\u5373\u4f7f\u60a8\u770b\u4e0d\u5230\u5b83\u3002\u6b63\u5982\u6211\u5728\u7b2c 4 \u7ae0\u4e2d\u6240\u8ba8\u8bba\u7684\uff0cWebApplication \u4f1a\u81ea\u52a8\u5c06\u8bb8\u591a\u4e2d\u95f4\u4ef6\u7ec4\u4ef6\u6dfb\u52a0\u5230\u7ba1\u9053\u4e2d\uff0c\u5305\u62ec\u8def\u7531\u4e2d\u95f4\u4ef6\u3001\u7aef\u70b9\u4e2d\u95f4\u4ef6\uff0c\u662f\u7684\uff0c\u8fd8\u6709\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u3002\u56e0\u6b64\uff0c\u60a8\u5728\u7ba1\u9053\u4e2d\u6ca1\u6709\u770b\u5230\u5b83\u7684\u539f\u56e0\u662f\u5b83\u5df2\u88ab\u6dfb\u52a0\u3002<\/p>\n<p>In fact, WebApplication also automatically adds the authorization middleware to the pipeline, but in this case the template still calls UseAuthorization(). Why? For the same reason that the template also calls UseRouting(): to control exactly where in the pipeline the middleware is added.<br \/>\n\u4e8b\u5b9e\u4e0a\uff0cWebApplication \u8fd8\u4f1a\u81ea\u52a8\u5c06\u6388\u6743\u4e2d\u95f4\u4ef6\u6dfb\u52a0\u5230\u7ba1\u9053\u4e2d\uff0c\u4f46\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6a21\u677f\u4ecd\u7136\u8c03\u7528 UseAuthorization\uff08\uff09\u3002\u4e3a\u4ec0\u4e48\uff1f\u51fa\u4e8e\u4e0e\u6a21\u677f\u8fd8\u8c03\u7528 UseRouting\uff08\uff09 \u76f8\u540c\u7684\u539f\u56e0\uff1a\u4ee5\u51c6\u786e\u63a7\u5236\u4e2d\u95f4\u4ef6\u5728\u7ba1\u9053\u4e2d\u7684\u6dfb\u52a0\u4f4d\u7f6e\u3002<\/p>\n<p>As I mentioned in chapter 4, you can override the automatically added middleware by adding it yourself manually. It\u2019s crucial that the authorization middleware be placed after the routing middleware, and as mentioned in chapter 4, you typically want to place your routing middleware after the static file middleware. As the routing middleware needs to move, so does the authorization middleware!<br \/>\n\u6b63\u5982\u6211\u5728\u7b2c 4 \u7ae0\u4e2d\u63d0\u5230\u7684\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7\u81ea\u5df1\u624b\u52a8\u6dfb\u52a0\u6765\u8986\u76d6\u81ea\u52a8\u6dfb\u52a0\u7684\u4e2d\u95f4\u4ef6\u3002\u5c06\u6388\u6743\u4e2d\u95f4\u4ef6\u653e\u5728\u8def\u7531\u4e2d\u95f4\u4ef6\u4e4b\u540e\u81f3\u5173\u91cd\u8981\uff0c\u5982\u7b2c 4 \u7ae0\u6240\u8ff0\uff0c\u60a8\u901a\u5e38\u5e0c\u671b\u5c06\u8def\u7531\u4e2d\u95f4\u4ef6\u653e\u5728\u9759\u6001\u6587\u4ef6\u4e2d\u95f4\u4ef6\u4e4b\u540e\u3002\u7531\u4e8e\u8def\u7531\u4e2d\u95f4\u4ef6\u9700\u8981\u79fb\u52a8\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u4e5f\u9700\u8981\u79fb\u52a8\uff01<\/p>\n<p>Traditionally, the authentication middleware is also placed after the routing middleware, before the authorization middleware, but this isn\u2019t crucial. The only requirement is that it\u2019s placed before any middleware that requires an authenticated user, such as the authorization middleware.<br \/>\n\u4f20\u7edf\u4e0a\uff0c\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u4e5f\u653e\u5728\u8def\u7531\u4e2d\u95f4\u4ef6\u4e4b\u540e\uff0c\u6388\u6743\u4e2d\u95f4\u4ef6\u4e4b\u524d\uff0c\u4f46\u8fd9\u5e76\u4e0d\u91cd\u8981\u3002\u552f\u4e00\u7684\u8981\u6c42\u662f\uff0c\u5b83\u4f4d\u4e8e\u4efb\u4f55\u9700\u8981\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\u7684\u4e2d\u95f4\u4ef6\uff08\u4f8b\u5982\u6388\u6743\u4e2d\u95f4\u4ef6\uff09\u4e4b\u524d\u3002<\/p>\n<\/blockquote>\n<p>\u300bIf you wish, you can move the location of the authentication middleware by calling UseAuthentication() at the appropriate point. I prefer to limit the work done on requests where possible, so I typically take this approach, moving it between the call to UseRouting() and UseAuthorization():<br \/>\n\u5982\u679c\u9700\u8981\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728\u9002\u5f53\u7684\u4f4d\u7f6e\u8c03\u7528 UseAuthentication\uff08\uff09 \u6765\u79fb\u52a8\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u7684\u4f4d\u7f6e\u3002\u6211\u66f4\u559c\u6b22\u5c3d\u53ef\u80fd\u9650\u5236\u5bf9\u8bf7\u6c42\u6240\u505a\u7684\u5de5\u4f5c\uff0c\u56e0\u6b64\u6211\u901a\u5e38\u91c7\u7528\u8fd9\u79cd\u65b9\u6cd5\uff0c\u5728\u5bf9 UseRouting\uff08\uff09 \u548c UseAuthorization\uff08\uff09 \u7684\u8c03\u7528\u4e4b\u95f4\u79fb\u52a8\u5b83\uff1a<\/p>\n<pre><code>app.UseRouting();\napp.UseAuthentication();\napp.UseAuthorization();\napp.MapRazorPages();\napp.Run();<\/code><\/pre>\n<blockquote>\n<p>If you don\u2019t place the authentication middleware at the correct point in the pipeline, you can run into strange bugs where users aren\u2019t authenticated correctly or authorization policies aren\u2019t applied correctly. The templates work out of the box, but you need to take care if you\u2019re working with an existing application or moving middleware around.<br \/>\n\u5982\u679c\u60a8\u6ca1\u6709\u5c06\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u653e\u7f6e\u5728\u7ba1\u9053\u4e2d\u7684\u6b63\u786e\u4f4d\u7f6e\uff0c\u5219\u53ef\u80fd\u4f1a\u9047\u5230\u5947\u602a\u7684\u9519\u8bef\uff0c\u5373\u7528\u6237\u672a\u6b63\u786e\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u6216\u6388\u6743\u7b56\u7565\u672a\u6b63\u786e\u5e94\u7528\u3002\u8fd9\u4e9b\u6a21\u677f\u5f00\u7bb1\u5373\u7528\uff0c\u4f46\u5982\u679c\u60a8\u6b63\u5728\u4f7f\u7528\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u6216\u79fb\u52a8\u4e2d\u95f4\u4ef6\uff0c\u5219\u9700\u8981\u5c0f\u5fc3\u3002<\/p>\n<\/blockquote>\n<p>Now that you\u2019ve got an overview of the additions made by Identity, we\u2019ll look in a bit more detail at the database schema and how Identity stores users in the database.<br \/>\n\u73b0\u5728\uff0c\u60a8\u5df2\u7ecf\u5927\u81f4\u4e86\u89e3\u4e86 Identity \u6240\u505a\u7684\u6dfb\u52a0\uff0c\u6211\u4eec\u5c06\u66f4\u8be6\u7ec6\u5730\u4e86\u89e3\u6570\u636e\u5e93\u67b6\u6784\u4ee5\u53ca Identity \u5982\u4f55\u5728\u6570\u636e\u5e93\u4e2d\u5b58\u50a8\u7528\u6237\u3002<\/p>\n<h3>23.3.3 The ASP.NET Core Identity data model<\/h3>\n<p>23.3.3 ASP.NET Core Identity \u6570\u636e\u6a21\u578b<\/p>\n<p>Out of the box, and in the default templates, Identity uses EF Core to store user accounts. It provides a base DbContext that you can inherit from, called IdentityDbContext, which uses an IdentityUser as the user entity for your application.<br \/>\n\u5728\u9ed8\u8ba4\u6a21\u677f\u4e2d\uff0cIdentity \u4f7f\u7528 EF Core \u6765\u5b58\u50a8\u7528\u6237\u5e10\u6237\u3002\u5b83\u63d0\u4f9b\u4e86\u4e00\u4e2a\u53ef\u4ee5\u4ece\u4e2d\u7ee7\u627f\u7684\u57fa\u672c DbContext\uff0c\u79f0\u4e3a IdentityDbContext\uff0c\u5b83\u4f7f\u7528 IdentityUser \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u7684\u7528\u6237\u5b9e\u4f53\u3002<\/p>\n<p>In the template, the app\u2019s DbContext is called ApplicationDbContext. If you open this file, you\u2019ll see it\u2019s sparse; it inherits from the IdentityDbContext base class I described earlier, and that\u2019s it. What does this base class give you? The easiest way to see is to update a database with the migrations and take a look.<br \/>\n\u5728\u6a21\u677f\u4e2d\uff0c\u5e94\u7528\u7684 DbContext \u79f0\u4e3a ApplicationDbContext\u3002\u5982\u679c\u6253\u5f00\u6b64\u6587\u4ef6\uff0c\u60a8\u5c06\u770b\u5230\u5b83\u662f\u7a00\u758f\u7684;\u5b83\u7ee7\u627f\u81ea\u6211\u524d\u9762\u4ecb\u7ecd\u7684 IdentityDbContext \u57fa\u7c7b\uff0c\u4ec5\u6b64\u800c\u5df2\u3002\u8fd9\u4e2a\u57fa\u7c7b\u4e3a\u60a8\u63d0\u4f9b\u4e86\u4ec0\u4e48\uff1f\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u662f\u4f7f\u7528\u8fc1\u79fb\u66f4\u65b0\u6570\u636e\u5e93\u5e76\u67e5\u770b\u3002<\/p>\n<p>Applying the migrations is the same process as in chapter 12. Ensure that the connection string points to where you want to create the database, open a command prompt in your project folder, and run this command to update the database with the migrations:<br \/>\n\u5e94\u7528\u8fc1\u79fb\u7684\u8fc7\u7a0b\u4e0e\u7b2c 12 \u7ae0\u4e2d\u7684\u8fc7\u7a0b\u76f8\u540c\u3002\u786e\u4fdd\u8fde\u63a5\u5b57\u7b26\u4e32\u6307\u5411\u8981\u521b\u5efa\u6570\u636e\u5e93\u7684\u4f4d\u7f6e\uff0c\u5728\u9879\u76ee\u6587\u4ef6\u5939\u4e2d\u6253\u5f00\u547d\u4ee4\u63d0\u793a\u7b26\uff0c\u7136\u540e\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\u4ee5\u4f7f\u7528\u8fc1\u79fb\u66f4\u65b0\u6570\u636e\u5e93\uff1a<\/p>\n<pre><code>dotnet ef database update<\/code><\/pre>\n<p><b>Tip<\/b> If you see an error after running the dotnet ef command, ensure that you have the .NET tool installed by following the instructions provided in section 12.3.1. Also make sure that you run the command from the project folder, not the solution folder.<br \/>\n\u63d0\u793a\uff1a\u5982\u679c\u5728\u8fd0\u884c dotnet ef \u547d\u4ee4\u540e\u770b\u5230\u9519\u8bef\uff0c\u8bf7\u786e\u4fdd\u6309\u7167\u7b2c 12.3.1 \u8282\u4e2d\u63d0\u4f9b\u7684\u8bf4\u660e\u5b89\u88c5\u4e86 .NET \u5de5\u5177\u3002\u6b64\u5916\uff0c\u8bf7\u786e\u4fdd\u4ece\u9879\u76ee\u6587\u4ef6\u5939\uff08\u800c\u4e0d\u662f\u89e3\u51b3\u65b9\u6848\u6587\u4ef6\u5939\uff09\u8fd0\u884c\u547d\u4ee4\u3002<\/p>\n<p>If the database doesn\u2019t exist, the command-line interface (CLI) creates it. Figure 23.7 shows what the database looks like for the default template.<br \/>\n\u5982\u679c\u6570\u636e\u5e93\u4e0d\u5b58\u5728\uff0c\u5219\u547d\u4ee4\u884c\u754c\u9762 \uff08CLI\uff09 \u4f1a\u521b\u5efa\u8be5\u6570\u636e\u5e93\u3002\u56fe 23.7 \u663e\u793a\u4e86\u9ed8\u8ba4\u6a21\u677f\u7684\u6570\u636e\u5e93\u5916\u89c2\u3002<\/p>\n<p><b>Tip<\/b> If you\u2019re using MS SQL Server (or LocalDB), you can use the SQL Server Object Explorer in Visual Studio to browse tables and objects in your database. See Microsoft\u2019s \u201cHow to: Connect to a Database and Browse Existing Objects\u201d article for details: <a href=\"http:\/\/mng.bz\/mg8r\">http:\/\/mng.bz\/mg8r<\/a>.<br \/>\n\u63d0\u793a\uff1a\u5982\u679c\u60a8\u4f7f\u7528\u7684\u662f MS SQL Server\uff08\u6216 LocalDB\uff09\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528 Visual Studio \u4e2d\u7684 SQL Server \u5bf9\u8c61\u8d44\u6e90\u7ba1\u7406\u5668\u6d4f\u89c8\u6570\u636e\u5e93\u4e2d\u7684\u8868\u548c\u5bf9\u8c61\u3002\u6709\u5173\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u9605 Microsoft \u7684\u201c\u5982\u4f55\uff1a\u8fde\u63a5\u5230\u6570\u636e\u5e93\u5e76\u6d4f\u89c8\u73b0\u6709\u5bf9\u8c61\u201d\u4e00\u6587\uff1a<a href=\"http:\/\/mng.bz\/mg8r\">http:\/\/mng.bz\/mg8r<\/a>\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2307.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.7 The database schema used by ASP.NET Core Identity<br \/>\n\u56fe 23.7 ASP.NET Core Identity \u4f7f\u7528\u7684\u6570\u636e\u5e93\u67b6\u6784<\/p>\n<p>That\u2019s a lot of tables! You shouldn\u2019t need to interact with these tables directly (Identity handles that for you), but it doesn\u2019t hurt to have a basic grasp of what they\u2019re for:<br \/>\n\u597d\u591a\u8868\u554a\uff01\u60a8\u4e0d\u9700\u8981\u76f4\u63a5\u4e0e\u8fd9\u4e9b\u8868\u4ea4\u4e92\uff08Identity \u4f1a\u4e3a\u60a8\u5904\u7406\uff09\uff0c\u4f46\u5bf9\u5b83\u4eec\u7684\u7528\u9014\u6709\u57fa\u672c\u7684\u4e86\u89e3\u5e76\u6ca1\u6709\u4ec0\u4e48\u574f\u5904\uff1a<\/p>\n<p>\u2022  <strong>EFMigrationsHistory\u2014The standard EF Core migrations table that records which migrations have been applied.<br \/>\n<\/strong>EFMigrationsHistory - \u6807\u51c6 EF Core \u8fc1\u79fb\u8868\uff0c\u7528\u4e8e\u8bb0\u5f55\u5df2\u5e94\u7528\u7684\u8fc1\u79fb\u3002<\/p>\n<p>\u2022  AspNetUsers\u2014The user profile table itself. This is where IdentityUser is serialized to. We\u2019ll take a closer look at this table shortly.<br \/>\nAspNetUsers \u2014 \u7528\u6237\u914d\u7f6e\u6587\u4ef6\u8868\u672c\u8eab\u3002\u8fd9\u662f IdentityUser \u5e8f\u5217\u5316\u5230\u7684\u4f4d\u7f6e\u3002\u6211\u4eec\u7a0d\u540e\u4f1a\u4ed4\u7ec6\u770b\u770b\u8fd9\u4e2a\u8868\u683c\u3002<\/p>\n<p>\u2022  AspNetUserClaims\u2014The claims associated with a given user. A user can have many claims, so it\u2019s modeled as a many-to-one relationship.<br \/>\nAspNetUserClaims - \u4e0e\u7ed9\u5b9a\u7528\u6237\u5173\u8054\u7684\u58f0\u660e\u3002\u4e00\u4e2a\u7528\u6237\u53ef\u4ee5\u6709\u591a\u4e2a\u58f0\u660e\uff0c\u56e0\u6b64\u5b83\u88ab\u5efa\u6a21\u4e3a\u591a\u5bf9\u4e00\u5173\u7cfb\u3002<\/p>\n<p>\u2022  AspNetUserLogins and AspNetUserTokens\u2014These are related to third-party logins. When configured, these let users sign in with a Google or Facebook account (for example) instead of creating a password on your app.<br \/>\nAspNetUserLogins \u548c AspNetUserTokens - \u8fd9\u4e9b\u4e0e\u7b2c\u4e09\u65b9\u767b\u5f55\u76f8\u5173\u3002\u914d\u7f6e\u540e\uff0c\u8fd9\u4e9b\u8868\u5141\u8bb8\u7528\u6237\u4f7f\u7528 Google \u6216 Facebook \u5e10\u6237 \uff08\u4f8b\u5982\uff09 \u767b\u5f55\uff0c\u800c\u4e0d\u662f\u5728\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e0a\u521b\u5efa\u5bc6\u7801\u3002<\/p>\n<p>\u2022  AspNetUserRoles, AspNetRoles, and AspNetRoleClaims\u2014These tables are somewhat of a legacy left over from the old role-based permission model of the pre-.NET 4.5 days, instead of the claims-based permission model. These tables let you define roles that multiple users can belong to. Each role can be assigned multiple claims. These claims are effectively inherited by a user principal when they are assigned that role.<br \/>\nAspNetUserRoles\u3001AspNetRoles \u548c AspNetRoleClaims - \u8fd9\u4e9b\u8868\u5728\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u662f pre-.NET 4.5 \u5929\u7684\u57fa\u4e8e\u89d2\u8272\u7684\u65e7\u6743\u9650\u6a21\u578b\u9057\u7559\u4e0b\u6765\u7684\u9057\u7559\u95ee\u9898\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e\u58f0\u660e\u7684\u6743\u9650\u6a21\u578b\u3002\u8fd9\u4e9b\u8868\u5141\u8bb8\u60a8\u5b9a\u4e49\u591a\u4e2a\u7528\u6237\u53ef\u4ee5\u5c5e\u4e8e\u7684\u89d2\u8272\u3002\u6bcf\u4e2a\u89d2\u8272\u90fd\u53ef\u4ee5\u5206\u914d\u591a\u4e2a\u58f0\u660e\u3002\u5f53\u4e3a\u7528\u6237\u4e3b\u4f53\u5206\u914d\u8be5\u89d2\u8272\u65f6\uff0c\u8fd9\u4e9b\u58f0\u660e\u5c06\u7531\u7528\u6237\u4e3b\u4f53\u6709\u6548\u5730\u7ee7\u627f\u3002<\/p>\n<p>You can explore these tables yourself, but the most interesting of them is the AspNetUsers table, shown in figure 23.8.<br \/>\n\u60a8\u53ef\u4ee5\u81ea\u5df1\u6d4f\u89c8\u8fd9\u4e9b\u8868\uff0c\u4f46\u5176\u4e2d\u6700\u6709\u8da3\u7684\u662f AspNetUsers \u8868\uff0c\u5982\u56fe 23.8 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2308.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.8 The AspNetUsers table is used to store all the details required to authenticate a user.<br \/>\n\u56fe 23.8 AspNetUsers \u8868\u7528\u4e8e\u5b58\u50a8\u9a8c\u8bc1\u7528\u6237\u6240\u9700\u7684\u6240\u6709\u8be6\u7ec6\u4fe1\u606f\u3002<\/p>\n<p>Most of the columns in the AspNetUsers table are security-related\u2014the user\u2019s email, password hash, whether they have confirmed their email, whether they have MFA enabled, and so on. By default, there are no columns for additional information, like the user\u2019s name.<br \/>\nAspNetUsers \u8868\u4e2d\u7684\u5927\u591a\u6570\u5217\u90fd\u4e0e\u5b89\u5168\u76f8\u5173 \u2014 \u7528\u6237\u7684\u7535\u5b50\u90ae\u4ef6\u3001\u5bc6\u7801\u54c8\u5e0c\u3001\u4ed6\u4eec\u662f\u5426\u5df2\u786e\u8ba4\u5176\u7535\u5b50\u90ae\u4ef6\u3001\u4ed6\u4eec\u662f\u5426\u542f\u7528\u4e86 MFA \u7b49\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6ca1\u6709\u5176\u4ed6\u4fe1\u606f\uff08\u5982\u7528\u6237\u540d\uff09\u7684\u5217\u3002<\/p>\n<p><b>NOTE<\/b> You can see from figure 23.8 that the primary key Id is stored as a string column. By default, Identity uses Guid for the identifier. To customize the data type, see the \u201cChange the primary key type\u201d section of Microsoft\u2019s \u201cIdentity model customization in ASP.NET Core\u201d documentation: <a href=\"http:\/\/mng.bz\/5jdB\">http:\/\/mng.bz\/5jdB<\/a>.<br \/>\n\u6ce8\u610f\uff1a\u4ece\u56fe 23.8 \u4e2d\u53ef\u4ee5\u770b\u51fa\uff0c\u4e3b\u952e Id \u5b58\u50a8\u4e3a\u5b57\u7b26\u4e32\u5217\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cIdentity \u4f7f\u7528 Guid \u4f5c\u4e3a\u6807\u8bc6\u7b26\u3002\u8981\u81ea\u5b9a\u4e49\u6570\u636e\u7c7b\u578b\uff0c\u8bf7\u53c2\u9605 Microsoft \u7684\u201cASP.NET Core \u4e2d\u7684\u8eab\u4efd\u6a21\u578b\u81ea\u5b9a\u4e49\u201d\u6587\u6863\u7684\u201c\u66f4\u6539\u4e3b\u952e\u7c7b\u578b\u201d\u90e8\u5206\uff1a<a href=\"http:\/\/mng.bz\/5jdB\">http:\/\/mng.bz\/5jdB<\/a>\u3002<\/p>\n<p>Any additional properties of the user are stored as claims in the AspNetUserClaims table associated with that user. This lets you add arbitrary additional information without having to change the database schema to accommodate it. Want to store the user\u2019s date of birth? You could add a claim to that user; there\u2019s no need to change the database schema. You\u2019ll see this in action in section 23.6, when you add a Name claim to every new user.<br \/>\n\u7528\u6237\u7684\u4efb\u4f55\u5176\u4ed6\u5c5e\u6027\u90fd\u4f5c\u4e3a\u58f0\u660e\u5b58\u50a8\u5728\u4e0e\u8be5\u7528\u6237\u5173\u8054\u7684 AspNetUserClaims \u8868\u4e2d\u3002\u8fd9\u6837\uff0c\u60a8\u5c31\u53ef\u4ee5\u6dfb\u52a0\u4efb\u610f\u7684\u9644\u52a0\u4fe1\u606f\uff0c\u800c\u4e0d\u5fc5\u66f4\u6539\u6570\u636e\u5e93\u67b6\u6784\u6765\u5bb9\u7eb3\u5b83\u3002\u60f3\u8981\u5b58\u50a8\u7528\u6237\u7684\u51fa\u751f\u65e5\u671f\uff1f\u60a8\u53ef\u4ee5\u5411\u8be5\u7528\u6237\u6dfb\u52a0\u58f0\u660e;\u65e0\u9700\u66f4\u6539\u6570\u636e\u5e93\u67b6\u6784\u3002\u60a8\u5c06\u5728\u7b2c 23.6 \u8282\u4e2d\u770b\u5230\u8fd9\u4e00\u70b9\uff0c\u5f53\u60a8\u4e3a\u6bcf\u4e2a\u65b0\u7528\u6237\u6dfb\u52a0 Name \u58f0\u660e\u65f6\u3002<\/p>\n<p><b>NOTE<\/b> Adding claims is often the easiest way to extend the default IdentityUser, but you can add properties to the IdentityUser directly. This requires database changes but is nevertheless useful in many situations. You can read how to add custom data using this approach here: <a href=\"http:\/\/mng.bz\/Xd61\">http:\/\/mng.bz\/Xd61<\/a>.<br \/>\n\u6ce8\u610f\uff1a\u6dfb\u52a0\u58f0\u660e\u901a\u5e38\u662f\u6269\u5c55\u9ed8\u8ba4 IdentityUser \u7684\u6700\u7b80\u5355\u65b9\u6cd5\uff0c\u4f46\u60a8\u53ef\u4ee5\u76f4\u63a5\u5411 IdentityUser \u6dfb\u52a0\u5c5e\u6027\u3002\u8fd9\u9700\u8981\u66f4\u6539\u6570\u636e\u5e93\uff0c\u4f46\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\u4ecd\u7136\u5f88\u6709\u7528\u3002\u60a8\u53ef\u4ee5\u5728\u6b64\u5904\u9605\u8bfb\u5982\u4f55\u4f7f\u7528\u6b64\u65b9\u6cd5\u6dfb\u52a0\u81ea\u5b9a\u4e49\u6570\u636e\uff1a<a href=\"http:\/\/mng.bz\/Xd61\">http:\/\/mng.bz\/Xd61<\/a>\u3002<\/p>\n<p>It\u2019s important to understand the difference between the IdentityUser entity (stored in the AspNetUsers table) and the ClaimsPrincipal, which is exposed on HttpContext.User. When a user first logs in, an IdentityUser is loaded from the database. This entity is combined with additional claims for the user from the AspNetUserClaims table to create a ClaimsPrincipal. It\u2019s this ClaimsPrincipal that is used for authentication and is serialized to the authentication cookie, not the IdentityUser.<br \/>\n\u4e86\u89e3 IdentityUser \u5b9e\u4f53\uff08\u5b58\u50a8\u5728 AspNetUsers \u8868\u4e2d\uff09\u548c ClaimsPrincipal\uff08\u5728 HttpContext.User \u4e0a\u516c\u5f00\uff09\u4e4b\u95f4\u7684\u533a\u522b\u975e\u5e38\u91cd\u8981\u3002\u5f53\u7528\u6237\u9996\u6b21\u767b\u5f55\u65f6\uff0c\u5c06\u4ece\u6570\u636e\u5e93\u4e2d\u52a0\u8f7d IdentityUser\u3002\u6b64\u5b9e\u4f53\u4e0e AspNetUserClaims \u8868\u4e2d\u7528\u6237\u7684\u5176\u4ed6\u58f0\u660e\u7ec4\u5408\u5728\u4e00\u8d77\uff0c\u4ee5\u521b\u5efa ClaimsPrincipal\u3002\u6b64 ClaimsPrincipal \u7528\u4e8e\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5e76\u5e8f\u5217\u5316\u4e3a\u8eab\u4efd\u9a8c\u8bc1 Cookie\uff0c\u800c\u4e0d\u662f IdentityUser\u3002<\/p>\n<p>It\u2019s useful to have a mental model of the underlying database schema Identity uses, but in day-to-day work, you shouldn\u2019t have to interact with it directly. That\u2019s what Identity is for, after all! In the next section we\u2019ll look at the other end of the scale: the UI of the app and what you get out of the box with the default UI.<br \/>\n\u62e5\u6709 Identity \u4f7f\u7528\u7684\u57fa\u7840\u6570\u636e\u5e93\u67b6\u6784\u7684\u5fc3\u667a\u6a21\u578b\u5f88\u6709\u7528\uff0c\u4f46\u5728\u65e5\u5e38\u5de5\u4f5c\u4e2d\uff0c\u60a8\u4e0d\u5e94\u8be5\u76f4\u63a5\u4e0e\u4e4b\u4ea4\u4e92\u3002\u6bd5\u7adf\uff0c\u8fd9\u5c31\u662f Identity \u7684\u610f\u4e49\u6240\u5728\uff01\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u4e86\u89e3\u5929\u5e73\u7684\u53e6\u4e00\u7aef\uff1a\u5e94\u7528\u7a0b\u5e8f\u7684 UI \u4ee5\u53ca\u60a8\u4f7f\u7528\u9ed8\u8ba4 UI \u5f00\u7bb1\u5373\u7528\u7684\u529f\u80fd\u3002<\/p>\n<h3>23.3.4 Interacting with ASP.NET Core Identity<\/h3>\n<p>23.3.4 \u4e0e ASP.NET Core Identity \u4ea4\u4e92<\/p>\n<p>You\u2019ll want to explore the default UI yourself to get a feel for how the pieces fit together, but in this section I\u2019ll highlight what you get out of the box, as well as areas that typically require additional attention right away.<br \/>\n\u60a8\u9700\u8981\u4eb2\u81ea\u63a2\u7d22\u9ed8\u8ba4 UI\uff0c\u4ee5\u4e86\u89e3\u5404\u4e2a\u90e8\u5206\u662f\u5982\u4f55\u7ec4\u5408\u5728\u4e00\u8d77\u7684\uff0c\u4f46\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u91cd\u70b9\u4ecb\u7ecd\u60a8\u5f00\u7bb1\u5373\u7528\u7684\u529f\u80fd\uff0c\u4ee5\u53ca\u901a\u5e38\u9700\u8981\u7acb\u5373\u989d\u5916\u6ce8\u610f\u7684\u9886\u57df\u3002<\/p>\n<p>The entry point to the default UI is the user registration page of the application, shown in figure 23.9. The register page enables users to sign up to your application by creating a new IdentityUser with an email and a password. After creating an account, users are redirected to a screen indicating that they should confirm their email. No email service is enabled by default, as this is dependent on your configuring an external email service. You can read how to enable email sending in Microsoft\u2019s \u201cAccount confirmation and password recovery in ASP.NET Core\u201d documentation at <a href=\"http:\/\/mng.bz\/6gBo\">http:\/\/mng.bz\/6gBo<\/a>. Once you configure this, users will automatically receive an email with a link to confirm their account.<br \/>\n\u9ed8\u8ba4 UI \u7684\u5165\u53e3\u70b9\u662f\u5e94\u7528\u7a0b\u5e8f\u7684\u7528\u6237\u6ce8\u518c\u9875\u9762\uff0c\u5982\u56fe 23.9 \u6240\u793a\u3002\u901a\u8fc7\u6ce8\u518c\u9875\u9762\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\u521b\u5efa\u65b0\u7684 IdentityUser \u6765\u6ce8\u518c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002\u521b\u5efa\u8d26\u6237\u540e\uff0c\u7528\u6237\u5c06\u88ab\u91cd\u5b9a\u5411\u5230\u4e00\u4e2a\u5c4f\u5e55\uff0c\u6307\u793a\u4ed6\u4eec\u5e94\u8be5\u786e\u8ba4\u4ed6\u4eec\u7684\u7535\u5b50\u90ae\u4ef6\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u4e0d\u542f\u7528\u4efb\u4f55\u7535\u5b50\u90ae\u4ef6\u670d\u52a1\uff0c\u56e0\u4e3a\u8fd9\u53d6\u51b3\u4e8e\u60a8\u914d\u7f6e\u5916\u90e8\u7535\u5b50\u90ae\u4ef6\u670d\u52a1\u3002\u60a8\u53ef\u4ee5\u5728 <a href=\"http:\/\/mng.bz\/6gBo\">http:\/\/mng.bz\/6gBo<\/a> \u7684 Microsoft \u7684\u201cASP.NET Core \u4e2d\u7684\u5e10\u6237\u786e\u8ba4\u548c\u5bc6\u7801\u6062\u590d\u201d\u6587\u6863\u4e2d\u9605\u8bfb\u5982\u4f55\u542f\u7528\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u3002\u914d\u7f6e\u6b64\u9879\u540e\uff0c\u7528\u6237\u5c06\u81ea\u52a8\u6536\u5230\u4e00\u5c01\u7535\u5b50\u90ae\u4ef6\uff0c\u5176\u4e2d\u5305\u542b\u7528\u4e8e\u786e\u8ba4\u5176\u5e10\u6237\u7684\u94fe\u63a5\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2309.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.9 The registration flow for users using the default Identity UI. Users enter an email and password and are redirected to a \u201cconfirm your email\u201d page. This is a placeholder page by default, but if you enable email confirmation, this page will update appropriately.<br \/>\n\u56fe 23.9 \u4f7f\u7528\u9ed8\u8ba4 Identity UI \u7684\u7528\u6237\u7684\u6ce8\u518c\u6d41\u7a0b\u3002\u7528\u6237\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\uff0c\u5e76\u88ab\u91cd\u5b9a\u5411\u5230\u201c\u786e\u8ba4\u60a8\u7684\u7535\u5b50\u90ae\u4ef6\u201d\u9875\u9762\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u8fd9\u662f\u4e00\u4e2a\u5360\u4f4d\u7b26\u9875\u9762\uff0c\u4f46\u5982\u679c\u60a8\u542f\u7528\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\uff0c\u6b64\u9875\u9762\u5c06\u76f8\u5e94\u5730\u66f4\u65b0\u3002<\/p>\n<p>By default, user emails must be unique (you can\u2019t have two users with the same email), and the password must meet various length and complexity requirements. You can customize these options and more in the configuration lambda of the call to AddDefaultIdentity() in Program.cs, as shown in the following listing.<br \/>\n\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u7528\u6237\u7535\u5b50\u90ae\u4ef6\u5fc5\u987b\u662f\u552f\u4e00\u7684\uff08\u60a8\u4e0d\u80fd\u8ba9\u4e24\u4e2a\u7528\u6237\u4f7f\u7528\u540c\u4e00\u7535\u5b50\u90ae\u4ef6\uff09\uff0c\u5e76\u4e14\u5bc6\u7801\u5fc5\u987b\u6ee1\u8db3\u5404\u79cd\u957f\u5ea6\u548c\u590d\u6742\u6027\u8981\u6c42\u3002\u60a8\u53ef\u4ee5\u5728 Program.cs \u4e2d\u8c03\u7528 AddDefaultIdentity\uff08\uff09 \u7684\u914d\u7f6e lambda \u4e2d\u81ea\u5b9a\u4e49\u8fd9\u4e9b\u9009\u9879\u4ee5\u53ca\u66f4\u591a\u9009\u9879\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002<\/p>\n<p>Listing 23.2 Customizing Identity settings in ConfigureServices in Startup.cs<br \/>\n\u6e05\u5355 23.2 \u5728 Startup.cs \u7684 ConfigureServices \u4e2d\u81ea\u5b9a\u4e49\u8eab\u4efd\u8bbe\u7f6e<\/p>\n<pre><code>builder.Services.AddDefaultIdentity&lt;IdentityUser&gt;(options =&gt;\n{\n    options.SignIn.RequireConfirmedAccount = true;     #A\n    options.Lockout.AllowedForNewUsers = true;    #B\n    options.Password.RequiredLength = 12;               #C\n    options.Password.RequireNonAlphanumeric = false;    #C\n    options.Password.RequireDigit = false;              #C\n})\n.AddEntityFrameworkStores&lt;AppDbContext&gt;();<\/code><\/pre>\n<p>\u2776 Requires users to confirm their account by email before they can log in<br \/>\n\u8981\u6c42\u7528\u6237\u5728\u767b\u5f55\u4e4b\u524d\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\u5176\u5e10\u6237<br \/>\n\u2777 Enables user lockout, to prevent brute-force attacks against user passwords<br \/>\n\u542f\u7528\u7528\u6237\u9501\u5b9a\uff0c\u4ee5\u9632\u6b62\u5bf9\u7528\u6237\u5bc6\u7801\u7684\u66b4\u529b\u653b\u51fb<br \/>\n\u2778 Updates password requirements. Current guidance is to require long passwords.<br \/>\n\u66f4\u65b0\u5bc6\u7801\u8981\u6c42\u3002\u5f53\u524d\u7684\u6307\u5bfc\u662f\u8981\u6c42\u4f7f\u7528\u957f\u5bc6\u7801\u3002<\/p>\n<p>After a user has registered with your application, they need to log in, as shown in figure 23.10. On the right side of the login page, the default UI templates describe how you, the developer, can configure external login providers, such as Facebook and Google. This is useful information for you, but it\u2019s one of the reasons you may need to customize the default UI templates, as you\u2019ll see in section 23.5.<br \/>\n\u7528\u6237\u6ce8\u518c\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u540e\uff0c\u4ed6\u4eec\u9700\u8981\u767b\u5f55\uff0c\u5982\u56fe 23.10 \u6240\u793a\u3002\u5728\u767b\u5f55\u9875\u9762\u7684\u53f3\u4fa7\uff0c\u9ed8\u8ba4 UI \u6a21\u677f\u63cf\u8ff0\u4e86\u60a8\uff08\u5f00\u53d1\u4eba\u5458\uff09\u5982\u4f55\u914d\u7f6e\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f8b\u5982 Facebook \u548c Google\u3002\u8fd9\u5bf9\u60a8\u6709\u7528\uff0c\u4f46\u8fd9\u4e5f\u662f\u60a8\u53ef\u80fd\u9700\u8981\u81ea\u5b9a\u4e49\u9ed8\u8ba4 UI \u6a21\u677f\u7684\u539f\u56e0\u4e4b\u4e00\uff0c\u5982\u7b2c 23.5 \u8282\u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2310.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.10 Logging in with an existing user and managing the user account. The Login page describes how to configure external login providers, such as Facebook and Google. The user-management pages allow users to change their email and password and to configure MFA.<br \/>\n\u56fe 23.10 \u4f7f\u7528\u73b0\u6709\u7528\u6237\u767b\u5f55\u5e76\u7ba1\u7406\u7528\u6237\u5e10\u6237\u3002Login \uff08\u767b\u5f55\uff09 \u9875\u9762\u4ecb\u7ecd\u4e86\u5982\u4f55\u914d\u7f6e\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u4f8b\u5982 Facebook \u548c Google\u3002\u7528\u6237\u7ba1\u7406\u9875\u9762\u5141\u8bb8\u7528\u6237\u66f4\u6539\u5176\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\u4ee5\u53ca\u914d\u7f6e MFA\u3002<\/p>\n<p>Once a user has signed in, they can access the management pages of the identity UI. These allow users to change their email, change their password, configure MFA with an authenticator app, or delete all their personal data. Most of these functions work without any effort on your part, assuming that you\u2019ve already configured an email-sending service.<br \/>\n\u7528\u6237\u767b\u5f55\u540e\uff0c\u4ed6\u4eec\u53ef\u4ee5\u8bbf\u95ee\u8eab\u4efd UI \u7684\u7ba1\u7406\u9875\u9762\u3002\u8fd9\u4e9b\u5141\u8bb8\u7528\u6237\u66f4\u6539\u4ed6\u4eec\u7684\u7535\u5b50\u90ae\u4ef6\u3001\u66f4\u6539\u4ed6\u4eec\u7684\u5bc6\u7801\u3001\u4f7f\u7528\u8eab\u4efd\u9a8c\u8bc1\u5668\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e MFA \u6216\u5220\u9664\u4ed6\u4eec\u7684\u6240\u6709\u4e2a\u4eba\u6570\u636e\u3002\u8fd9\u4e9b\u51fd\u6570\u4e2d\u7684\u5927\u591a\u6570\u90fd\u65e0\u9700\u60a8\u6267\u884c\u4efb\u4f55\u4f5c\u5373\u53ef\u5de5\u4f5c\uff0c\u524d\u63d0\u662f\u60a8\u5df2\u7ecf\u914d\u7f6e\u4e86\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u670d\u52a1\u3002<\/p>\n<p>That covers everything you get in the default UI templates. It may seem somewhat minimal, but it covers a lot of the requirements that are common to almost all apps. Nevertheless, there are a few things you\u2019ll nearly always want to customize:<br \/>\n\u8fd9\u6db5\u76d6\u4e86\u60a8\u5728\u9ed8\u8ba4 UI \u6a21\u677f\u4e2d\u83b7\u5f97\u7684\u6240\u6709\u5185\u5bb9\u3002\u5b83\u53ef\u80fd\u770b\u8d77\u6765\u6709\u4e9b\u5fae\u4e0d\u8db3\u9053\uff0c\u4f46\u5b83\u6db5\u76d6\u4e86\u51e0\u4e4e\u6240\u6709\u5e94\u7528\u7a0b\u5e8f\u901a\u7528\u7684\u8bb8\u591a\u8981\u6c42\u3002\u4e0d\u8fc7\uff0c\u60a8\u51e0\u4e4e\u603b\u662f\u9700\u8981\u81ea\u5b9a\u4e49\u4e00\u4e9b\u5185\u5bb9\uff1a<\/p>\n<p>\u2022  Configure an email-sending service, to enable account confirmation and password recovery, as described in Microsoft\u2019s \u201cAccount confirmation and password recovery in ASP.NET Core\u201d documentation: <a href=\"http:\/\/mng.bz\/vzy7\">http:\/\/mng.bz\/vzy7<\/a>.<br \/>\n\u914d\u7f6e\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u670d\u52a1\uff0c\u4ee5\u542f\u7528\u5e10\u6237\u786e\u8ba4\u548c\u5bc6\u7801\u6062\u590d\uff0c\u5982 Microsoft \u7684\u201cASP.NET Core \u4e2d\u7684\u5e10\u6237\u786e\u8ba4\u548c\u5bc6\u7801\u6062\u590d\u201d\u6587\u6863\u4e2d\u6240\u8ff0\uff1a<a href=\"http:\/\/mng.bz\/vzy7\">http:\/\/mng.bz\/vzy7<\/a>\u3002<\/p>\n<p>\u2022  Add a QR code generator for the enable MFA page, as described in Microsoft\u2019s \u201cEnable QR Code generation for TOTP authenticator apps in ASP.NET Core\u201d documentation: <a href=\"http:\/\/mng.bz\/4Zmw\">http:\/\/mng.bz\/4Zmw<\/a>.<br \/>\n\u4e3a\u542f\u7528 MFA \u9875\u9762\u6dfb\u52a0 QR \u7801\u751f\u6210\u5668\uff0c\u5982 Microsoft \u7684\u201c\u5728 ASP.NET Core \u4e2d\u4e3a TOTP \u9a8c\u8bc1\u5668\u5e94\u7528\u7a0b\u5e8f\u542f\u7528 QR \u7801\u751f\u6210\u201d\u6587\u6863\u4e2d\u6240\u8ff0\uff1a<a href=\"http:\/\/mng.bz\/4Zmw\">http:\/\/mng.bz\/4Zmw<\/a>\u3002<\/p>\n<p>\u2022  Customize the register and login pages to remove the documentation link for enabling external services. You\u2019ll see how to do this in section 23.5. Alternatively, you may want to disable user registration entirely, as described in Microsoft\u2019s \u201cScaffold Identity in ASP.NET Core projects\u201d documentation: <a href=\"http:\/\/mng.bz\/QmMG\">http:\/\/mng.bz\/QmMG<\/a>.<br \/>\n\u81ea\u5b9a\u4e49\u6ce8\u518c\u548c\u767b\u5f55\u9875\u9762\uff0c\u4ee5\u5220\u9664\u7528\u4e8e\u542f\u7528\u5916\u90e8\u670d\u52a1\u7684\u6587\u6863\u94fe\u63a5\u3002\u60a8\u5c06\u5728 Section 23.5 \u4e2d\u770b\u5230\u5982\u4f55\u6267\u884c\u6b64\u4f5c\u3002\u6216\u8005\uff0c\u60a8\u53ef\u80fd\u5e0c\u671b\u5b8c\u5168\u7981\u7528\u7528\u6237\u6ce8\u518c\uff0c\u5982 Microsoft \u7684\u201cASP.NET Core \u9879\u76ee\u4e2d\u7684\u57fa\u67b6\u8eab\u4efd\u201d\u6587\u6863\u4e2d\u6240\u8ff0\uff1a<a href=\"http:\/\/mng.bz\/QmMG\">http:\/\/mng.bz\/QmMG<\/a>\u3002<\/p>\n<p>\u2022  Collect additional information about users on the registration page. You\u2019ll see how to do this in section 23.6.<br \/>\n\u5728\u6ce8\u518c\u9875\u9762\u4e0a\u6536\u96c6\u6709\u5173\u7528\u6237\u7684\u5176\u4ed6\u4fe1\u606f\u3002\u60a8\u5c06\u5728 Section 23.6 \u4e2d\u770b\u5230\u5982\u4f55\u6267\u884c\u6b64\u4f5c\u3002<\/p>\n<p>There are many more ways you can extend or update the Identity system and lots of options available, so I encourage you to explore Microsoft\u2019s \u201cOverview of ASP.NET Core authentication\u201d at <a href=\"http:\/\/mng.bz\/XdGv\">http:\/\/mng.bz\/XdGv<\/a> to see your options. In the next section you\u2019ll see how to achieve another common requirement: adding users to an existing application.<br \/>\n\u8fd8\u6709\u66f4\u591a\u65b9\u6cd5\u53ef\u4ee5\u6269\u5c55\u6216\u66f4\u65b0 Identity \u7cfb\u7edf\uff0c\u5e76\u4e14\u6709\u5f88\u591a\u53ef\u7528\u9009\u9879\uff0c\u56e0\u6b64\u6211\u9f13\u52b1\u60a8\u5728 <a href=\"http:\/\/mng.bz\/XdGv\">http:\/\/mng.bz\/XdGv<\/a> \u4e0a\u6d4f\u89c8 Microsoft \u7684\u201cASP.NET Core \u8eab\u4efd\u9a8c\u8bc1\u6982\u8ff0\u201d\u4ee5\u67e5\u770b\u60a8\u7684\u9009\u9879\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u5b9e\u73b0\u53e6\u4e00\u4e2a\u5e38\u89c1\u8981\u6c42\uff1a\u5c06\u7528\u6237\u6dfb\u52a0\u5230\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<h2>23.4 Adding ASP.NET Core Identity to an existing project<\/h2>\n<p>23.4 \u5c06 ASP.NET Core Identity \u6dfb\u52a0\u5230\u73b0\u6709\u5de5\u7a0b<\/p>\n<p>In this section we\u2019re going to add users to an existing application. The initial app is a Razor Pages app, based on recipe application from chapter 12. This is a working app that you want to add user functionality to. In chapter 24 we\u2019ll extend this work to restrict control regarding who\u2019s allowed to edit recipes on the app.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u4eec\u5c06\u5411\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u3002\u521d\u59cb\u5e94\u7528\u662f Razor Pages \u5e94\u7528\uff0c\u57fa\u4e8e\u7b2c 12 \u7ae0\u4e2d\u7684\u914d\u65b9\u5e94\u7528\u3002\u8fd9\u662f\u60a8\u8981\u5411\u5176\u6dfb\u52a0\u7528\u6237\u529f\u80fd\u7684\u5de5\u4f5c\u5e94\u7528\u7a0b\u5e8f\u3002\u5728\u7b2c 24 \u7ae0\u4e2d\uff0c\u6211\u4eec\u5c06\u6269\u5c55\u8fd9\u9879\u5de5\u4f5c\uff0c\u4ee5\u9650\u5236\u5bf9\u8c01\u53ef\u4ee5\u5728\u5e94\u7528\u7a0b\u5e8f\u4e0a\u7f16\u8f91\u914d\u65b9\u7684\u63a7\u5236\u3002<\/p>\n<p>By the end of this section, you\u2019ll have an application with a registration page, a login screen, and a manage account screen, like the default templates. You\u2019ll also have a persistent widget in the top right of the screen showing the login status of the current user, as shown in figure 23.11.<br \/>\n\u5728\u672c\u90e8\u5206\u7ed3\u675f\u65f6\uff0c\u60a8\u5c06\u62e5\u6709\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\uff0c\u5176\u4e2d\u5305\u542b\u6ce8\u518c\u9875\u9762\u3001\u767b\u5f55\u5c4f\u5e55\u548c\u7ba1\u7406\u5e10\u6237\u5c4f\u5e55\uff0c\u5c31\u50cf\u9ed8\u8ba4\u6a21\u677f\u4e00\u6837\u3002\u5c4f\u5e55\u53f3\u4e0a\u89d2\u8fd8\u6709\u4e00\u4e2a\u6301\u4e45\u5c0f\u90e8\u4ef6\uff0c\u663e\u793a\u5f53\u524d\u7528\u6237\u7684\u767b\u5f55\u72b6\u6001\uff0c\u5982\u56fe 23.11 \u6240\u793a\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2311.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.11 The recipe app after adding authentication, showing the login widget<br \/>\n\u56fe 23.11 \u6dfb\u52a0\u8eab\u4efd\u9a8c\u8bc1\u540e\u7684\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\uff0c\u663e\u793a\u767b\u5f55\u5c0f\u90e8\u4ef6<\/p>\n<p>As in section 23.3, I\u2019m not going to customize any of the defaults at this point, so we won\u2019t set up external login providers, email confirmation, or MFA. I\u2019m concerned only with adding ASP.NET Core Identity to an existing app that\u2019s already using EF Core.<br \/>\n\u4e0e Section 23.3 \u4e00\u6837\uff0c\u6211\u6b64\u65f6\u4e0d\u6253\u7b97\u81ea\u5b9a\u4e49\u4efb\u4f55\u9ed8\u8ba4\u503c\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u4f1a\u8bbe\u7f6e\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3001\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\u6216 MFA\u3002\u6211\u53ea\u5173\u5fc3\u5c06 ASP.NET Core Identity \u6dfb\u52a0\u5230\u5df2\u5728\u4f7f\u7528 EF Core \u7684\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<p><b>Tip<\/b> It\u2019s worth making sure you\u2019re comfortable with the new project templates before you go about adding Identity to an existing project. Create a test app, and consider setting up an external login provider, configuring an email provider, and enabling MFA. This will take a bit of time, but it\u2019ll be invaluable for deciphering errors when you come to adding Identity to existing apps.<br \/>\n\u63d0\u793a\u5728\u5c06 Identity \u6dfb\u52a0\u5230\u73b0\u6709\u9879\u76ee\u4e4b\u524d\uff0c\u503c\u5f97\u786e\u4fdd\u60a8\u719f\u6089\u65b0\u7684\u9879\u76ee\u6a21\u677f\u3002\u521b\u5efa\u6d4b\u8bd5\u5e94\u7528\u7a0b\u5e8f\uff0c\u5e76\u8003\u8651\u8bbe\u7f6e\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u3001\u914d\u7f6e\u7535\u5b50\u90ae\u4ef6\u63d0\u4f9b\u7a0b\u5e8f\u5e76\u542f\u7528 MFA\u3002\u8fd9\u5c06\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\uff0c\u4f46\u5728\u60a8\u5c06 Identity \u6dfb\u52a0\u5230\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u65f6\uff0c\u5b83\u5bf9\u4e8e\u7834\u8bd1\u9519\u8bef\u975e\u5e38\u5b9d\u8d35\u3002<\/p>\n<p>To add Identity to your app, you\u2019ll need to do the following:<br \/>\n\u8981\u5c06 Identity \u6dfb\u52a0\u5230\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u60a8\u9700\u8981\u6267\u884c\u4ee5\u4e0b\u4f5c\uff1a<\/p>\n<ol>\n<li>Add the ASP.NET Core Identity NuGet packages.<br \/>\n\u6dfb\u52a0 ASP.NET Core Identity NuGet \u5305\u3002<\/li>\n<li>Add the required Identity services to the dependency injection (DI) container.<br \/>\n\u5c06\u6240\u9700\u7684\u8eab\u4efd\u670d\u52a1\u6dfb\u52a0\u5230\u4f9d\u8d56\u5173\u7cfb\u6ce8\u5165 \uff08DI\uff09 \u5bb9\u5668\u4e2d\u3002<\/li>\n<li>Update the EF Core data model with the Identity entities.<br \/>\n\u4f7f\u7528 Identity \u5b9e\u4f53\u66f4\u65b0 EF Core \u6570\u636e\u6a21\u578b\u3002<\/li>\n<li>Update your Razor Pages and layouts to provide links to the Identity UI.<br \/>\n\u66f4\u65b0 Razor \u9875\u9762\u548c\u5e03\u5c40\uff0c\u4ee5\u63d0\u4f9b\u6307\u5411\u6807\u8bc6 UI \u7684\u94fe\u63a5\u3002<\/li>\n<\/ol>\n<p>This section tackles each of these steps in turn. At the end of section 23.4 you\u2019ll have successfully added user accounts to the recipe app.<br \/>\n\u672c\u8282\u5c06\u4f9d\u6b21\u4ecb\u7ecd\u8fd9\u4e9b\u6b65\u9aa4\u4e2d\u7684\u6bcf\u4e00\u4e2a\u3002\u5728\u7b2c 23.4 \u8282\u7ed3\u675f\u65f6\uff0c\u60a8\u5c06\u6210\u529f\u5730\u5c06\u7528\u6237\u5e10\u6237\u6dfb\u52a0\u5230\u914d\u65b9\u5e94\u7528\u7a0b\u5e8f\u3002<\/p>\n<h3>23.4.1 Configuring the ASP.NET Core Identity services<\/h3>\n<p>23.4.1 \u914d\u7f6e ASP.NET Core Identity \u670d\u52a1<br \/>\nYou can add ASP.NET Core Identity with the default UI to an existing app by referencing two NuGet packages:<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u5f15\u7528\u4e24\u4e2a NuGet \u5305\uff0c\u5c06\u5e26\u6709\u9ed8\u8ba4 UI \u7684 ASP.NET Core Identity \u6dfb\u52a0\u5230\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\uff1a<\/p>\n<p>\u2022  Microsoft.AspNetCore.Identity.EntityFrameworkCore\u2014Provides all the core Identity services and integration with EF Core<br \/>\nMicrosoft.AspNetCore.Identity.EntityFrameworkCore - \u63d0\u4f9b\u6240\u6709\u6838\u5fc3\u8eab\u4efd\u670d\u52a1\u4ee5\u53ca\u4e0e EF Core\u7684\u96c6\u6210<br \/>\n\u2022  Microsoft.AspNetCore.Identity.UI\u2014Provides the default UI Razor Pages<br \/>\nMicrosoft.AspNetCore.Identity.UI - \u63d0\u4f9b\u9ed8\u8ba4 UI Razor \u9875\u9762<\/p>\n<p>Update your project .csproj file to include these two packages:<br \/>\n\u66f4\u65b0\u9879\u76ee .csproj \u6587\u4ef6\u4ee5\u5305\u542b\u4ee5\u4e0b\u4e24\u4e2a\u5305\uff1a<\/p>\n<pre><code>&lt;PackageReference\n    Include=&quot;Microsoft.AspNetCore.Identity.EntityFrameworkCore&quot;\n    Version=&quot;7.0.0&quot; \/&gt;\n&lt;PackageReference\n    Include=&quot;Microsoft.AspNetCore.Identity.UI&quot; Version=&quot;7.0.0&quot; \/&gt;<\/code><\/pre>\n<p>These packages bring in all the additional required dependencies you need to add Identity with the default UI. Be sure to run dotnet restore after adding them to your project.<br \/>\n\u8fd9\u4e9b\u5305\u5f15\u5165\u4e86\u4f7f\u7528\u9ed8\u8ba4 UI \u6dfb\u52a0 Identity \u6240\u9700\u7684\u6240\u6709\u989d\u5916\u5fc5\u9700\u4f9d\u8d56\u9879\u3002\u8bf7\u52a1\u5fc5\u5728\u5c06\u5b83\u4eec\u6dfb\u52a0\u5230\u9879\u76ee\u540e\u8fd0\u884c dotnet restore\u3002<\/p>\n<p>Once you\u2019ve added the Identity packages, you can update your Program.cs file to include the Identity services, as shown in the following listing. This is similar to the default template setup you saw in listing 23.1, but make sure to reference your existing AppDbContext.<br \/>\n\u6dfb\u52a0 Identity \u5305\u540e\uff0c\u60a8\u53ef\u4ee5\u66f4\u65b0 Program.cs \u6587\u4ef6\u4ee5\u5305\u542b Identity \u670d\u52a1\uff0c\u5982\u4ee5\u4e0b\u6e05\u5355\u6240\u793a\u3002\u8fd9\u7c7b\u4f3c\u4e8e\u60a8\u5728\u6e05\u5355 23.1 \u4e2d\u770b\u5230\u7684\u9ed8\u8ba4\u6a21\u677f\u8bbe\u7f6e\uff0c\u4f46\u8bf7\u786e\u4fdd\u5f15\u7528\u60a8\u73b0\u6709\u7684 AppDbContext\u3002<\/p>\n<p>Listing 23.3 Adding ASP.NET Core Identity services to the recipe app<br \/>\n\u6e05\u5355 23.3 \u5c06 ASP.NET Core Identity \u670d\u52a1\u6dfb\u52a0\u5230 recipe \u5e94\u7528\u7a0b\u5e8f<\/p>\n<pre><code>WebApplicationBuilder builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddDbContext&lt;AppDbContext&gt;(options =&gt;   #A\n    options.UseSqlite(builder.Configuration    #A\n        .GetConnectionString(&quot;DefaultConnection&quot;)!));   #A\n\nbuilder.Services.AddDefaultIdentity&lt;ApplicationUser&gt;(options =&gt;      #B\n        options.SignIn.RequireConfirmedAccount = true)       #B\n    .AddEntityFrameworkStores&lt;AppDbContext&gt;();     #C\n\nbuilder.Services.AddRazorPages();\nbuilder.Services.AddScoped&lt;RecipeService&gt;();<\/code><\/pre>\n<p>\u2776 The existing service configuration is unchanged.<br \/>\n\u73b0\u6709\u670d\u52a1\u914d\u7f6e\u4fdd\u6301\u4e0d\u53d8\u3002<br \/>\n\u2777 Adds the Identity services to the DI container and uses a custom user type, ApplicationUser<br \/>\n\u5c06\u8eab\u4efd\u670d\u52a1\u6dfb\u52a0\u5230 DI \u5bb9\u5668\u5e76\u4f7f\u7528\u81ea\u5b9a\u4e49\u7528\u6237\u7c7b\u578b ApplicationUser<br \/>\n\u2778 Makes sure you use the name of your existing DbContext app<br \/>\n\u786e\u4fdd\u60a8\u4f7f\u7528\u73b0\u6709 DbContext \u5e94\u7528\u7a0b\u5e8f\u7684\u540d\u79f0<\/p>\n<p>This adds all the necessary services and configures Identity to use EF Core. I\u2019ve introduced a new type here, ApplicationUser, which we\u2019ll use to customize our user entity later. You\u2019ll see how to add this type in section 23.4.2.<br \/>\n\u8fd9\u5c06\u6dfb\u52a0\u6240\u6709\u5fc5\u8981\u7684\u670d\u52a1\uff0c\u5e76\u5c06 Identity \u914d\u7f6e\u4e3a\u4f7f\u7528 EF Core\u3002\u6211\u5728\u8fd9\u91cc\u5f15\u5165\u4e86\u4e00\u4e2a\u65b0\u7c7b\u578b ApplicationUser\uff0c\u6211\u4eec\u7a0d\u540e\u5c06\u4f7f\u7528\u5b83\u6765\u81ea\u5b9a\u4e49\u6211\u4eec\u7684\u7528\u6237\u5b9e\u4f53\u3002\u60a8\u5c06\u5728 Section 23.4.2 \u4e2d\u770b\u5230\u5982\u4f55\u6dfb\u52a0\u6b64\u7c7b\u578b\u3002<\/p>\n<p>The next step is optional: add the AuthenticationMiddleware after the call to UseRouting() on WebApplication, as shown in the following listing. As I mentioned previously, the authentication middleware is added automatically by WebApplication, so this step is optional. I prefer to delay authentication until after the call to UseRouting(), as it eliminates the need to perform unnecessary work decrypting the authentication cookie for requests that don\u2019t reach the routing middleware, such as requests for static files.<br \/>\n\u4e0b\u4e00\u6b65\u662f\u53ef\u9009\u7684\uff1a\u5728\u8c03\u7528 WebApplication \u4e0a\u7684 UseRouting\uff08\uff09 \u4e4b\u540e\u6dfb\u52a0 AuthenticationMiddleware\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u6b63\u5982\u6211\u524d\u9762\u63d0\u5230\u7684\uff0c\u8eab\u4efd\u9a8c\u8bc1\u4e2d\u95f4\u4ef6\u662f\u7531 WebApplication \u81ea\u52a8\u6dfb\u52a0\u7684\uff0c\u56e0\u6b64\u6b64\u6b65\u9aa4\u662f\u53ef\u9009\u7684\u3002\u6211\u66f4\u559c\u6b22\u5c06\u8eab\u4efd\u9a8c\u8bc1\u5ef6\u8fdf\u5230\u8c03\u7528 UseRouting\uff08\uff09 \u4e4b\u540e\uff0c\u56e0\u4e3a\u8fd9\u6837\u5c31\u65e0\u9700\u4e3a\u672a\u5230\u8fbe\u8def\u7531\u4e2d\u95f4\u4ef6\u7684\u8bf7\u6c42\uff08\u4f8b\u5982\u9759\u6001\u6587\u4ef6\u8bf7\u6c42\uff09\u6267\u884c\u4e0d\u5fc5\u8981\u7684\u8eab\u4efd\u9a8c\u8bc1 Cookie \u89e3\u5bc6\u5de5\u4f5c\u3002<\/p>\n<p>Listing 23.4 Adding AuthenticationMiddleware to the recipe app<br \/>\n\u5217\u8868 23.4 \u5c06 AuthenticationMiddleware \u6dfb\u52a0\u5230 recipe \u5e94\u7528\u7a0b\u5e8f<\/p>\n<pre><code>app.UseStaticFiles();            #A\n\napp.UseRouting();\n\napp.UseAuthentication();        #B\napp.UseAuthorization();          #C\n\napp.MapRazorPages();\napp.Run<\/code><\/pre>\n<p>\u2776 StaticFileMiddleware will never see requests as authenticated, even after you sign in.<br \/>\nStaticFileMiddleware \u6c38\u8fdc\u4e0d\u4f1a\u5c06\u8bf7\u6c42\u89c6\u4e3a\u5df2\u9a8c\u8bc1\uff0c\u5373\u4f7f\u5728\u4f60\u767b\u5f55\u540e\u4e5f\u662f\u5982\u6b64\u3002<br \/>\n\u2777 Adds AuthenticationMiddleware after UseRouting() and before UseAuthorization<br \/>\n\u5728 UseRouting\uff08\uff09 \u4e4b\u540e\u548c UseAuthorization\u4e4b\u524d\u6dfb\u52a0 AuthenticationMiddleware<br \/>\n\u2778 Middleware after AuthenticationMiddleware can read the user principal from HttpContext.User.<br \/>\nAuthenticationMiddleware \u4e4b\u540e\u7684\u4e2d\u95f4\u4ef6\u53ef\u4ee5\u4ece HttpContext.User \u8bfb\u53d6\u7528\u6237\u4e3b\u4f53\u3002<\/p>\n<p>You\u2019ve configured your app to use Identity, so the next step is updating EF Core\u2019s data model. You\u2019re already using EF Core in this app, so you need to update your database schema to include the tables that Identity requires.<br \/>\n\u4f60\u5df2\u5c06\u5e94\u7528\u914d\u7f6e\u4e3a\u4f7f\u7528 Identity\uff0c\u56e0\u6b64\u4e0b\u4e00\u6b65\u662f\u66f4\u65b0 EF Core \u7684\u6570\u636e\u6a21\u578b\u3002\u4f60\u5df2\u5728\u6b64\u5e94\u7528\u4e2d\u4f7f\u7528 EF Core\uff0c\u56e0\u6b64\u9700\u8981\u66f4\u65b0\u6570\u636e\u5e93\u67b6\u6784\u4ee5\u5305\u542b Identity \u6240\u9700\u7684\u8868\u3002<\/p>\n<h3>23.4.2 Updating the EF Core data model to support Identity<\/h3>\n<p>23.4.2 \u66f4\u65b0 EF Core \u6570\u636e\u6a21\u578b\u4ee5\u652f\u6301\u8eab\u4efd<\/p>\n<p>The code in listing 23.3 won\u2019t compile, as it references the ApplicationUser type, which doesn\u2019t yet exist. Create the ApplicationUser in the Data folder, using the following line:<br \/>\n\u6e05\u5355 23.3 \u4e2d\u7684\u4ee3\u7801\u65e0\u6cd5\u7f16\u8bd1\uff0c\u56e0\u4e3a\u5b83\u5f15\u7528\u4e86\u5c1a\u4e0d\u5b58\u5728\u7684 ApplicationUser \u7c7b\u578b\u3002\u4f7f\u7528\u4ee5\u4e0b\u884c\u5728 Data \u6587\u4ef6\u5939\u4e2d\u521b\u5efa ApplicationUser\uff1a<\/p>\n<pre><code>public class ApplicationUser : IdentityUser { }<\/code><\/pre>\n<p>It\u2019s not strictly necessary to create a custom user type in this case (for example, the default templates use the raw IdentityUser), but I find it\u2019s easier to add the derived type now rather than try to retrofit it later if you need to add extra properties to your user type.<br \/>\n\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5e76\u975e\u7edd\u5bf9\u9700\u8981\u521b\u5efa\u81ea\u5b9a\u4e49\u7528\u6237\u7c7b\u578b\uff08\u4f8b\u5982\uff0c\u9ed8\u8ba4\u6a21\u677f\u4f7f\u7528\u539f\u59cb IdentityUser\uff09\uff0c\u4f46\u6211\u53d1\u73b0\uff0c\u5982\u679c\u60a8\u9700\u8981\u5411\u7528\u6237\u7c7b\u578b\u6dfb\u52a0\u989d\u5916\u7684\u5c5e\u6027\uff0c\u73b0\u5728\u6dfb\u52a0\u6d3e\u751f\u7c7b\u578b\u6bd4\u4ee5\u540e\u5c1d\u8bd5\u4fee\u6539\u5b83\u66f4\u5bb9\u6613\u3002<\/p>\n<p>In section 23.3.3 you saw that Identity provides a DbContext called IdentityDbContext, which you can inherit from. The IdentityDbContext base class includes the necessary DbSet<T> to store your user entities using EF Core.<br \/>\n\u5728\u7b2c 23.3.3 \u8282\u4e2d\uff0c\u60a8\u770b\u5230 Identity \u63d0\u4f9b\u4e86\u4e00\u4e2a\u540d\u4e3a IdentityDbContext \u7684 DbContext\uff0c\u60a8\u53ef\u4ee5\u4ece\u4e2d\u7ee7\u627f\u3002IdentityDbContext \u57fa\u7c7b\u5305\u62ec\u4f7f\u7528 EF Core \u5b58\u50a8\u7528\u6237\u5b9e\u4f53\u6240\u9700\u7684 DbSet\u3002<\/p>\n<p>Updating an existing DbContext for Identity is simple: update your app\u2019s DbContext to inherit from IdentityDbContext (which itself inherits from DbContext), as shown in the following listing. We\u2019re using the generic version of the base Identity context in this case and providing the ApplicationUser type.<br \/>\n\u66f4\u65b0\u73b0\u6709\u7684 DbContext for Identity \u5f88\u7b80\u5355\uff1a\u66f4\u65b0\u5e94\u7528\u7a0b\u5e8f\u7684 DbContext \u4ee5\u4ece IdentityDbContext\uff08\u5b83\u672c\u8eab\u7ee7\u627f\u81ea DbContext\uff09\u7ee7\u627f\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u5728\u672c\u4f8b\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u57fa\u672c Identity \u4e0a\u4e0b\u6587\u7684\u901a\u7528\u7248\u672c\uff0c\u5e76\u63d0\u4f9b ApplicationUser \u7c7b\u578b\u3002<\/p>\n<p>Listing 23.5 Updating AppDbContext to use IdentityDbContext<br \/>\n\u5217\u8868 23.5 \u66f4\u65b0 AppDbContext \u4ee5\u4f7f\u7528 IdentityDbContext<\/p>\n<pre><code>public class AppDbContext : IdentityDbContext&lt;ApplicationUser&gt;    #A\n{\n    public AppDbContext(DbContextOptions&lt;AppDbContext&gt; options)  #B\n        : base(options)                                          #B\n    { }                                                          #B\n\n    public DbSet&lt;Recipe&gt; Recipes { get; set; }                   #B\n}<\/code><\/pre>\n<p>\u2776 Updates to inherit from the Identity context instead of directly from DbContext<br \/>\n\u66f4\u65b0\u4ee5\u4ece Identity \u4e0a\u4e0b\u6587\u7ee7\u627f\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u4ece DbContext\u7ee7\u627f<br \/>\n\u2777 The remainder of the class remains the same.<br \/>\n\u7c7b\u7684\u5176\u4f59\u90e8\u5206\u4fdd\u6301\u4e0d\u53d8\u3002<\/p>\n<p>Effectively, by updating the base class of your context in this way, you\u2019ve added a whole load of new entities to EF Core\u2019s data model. As you saw in chapter 12, whenever EF Core\u2019s data model changes, you need to create a new migration and apply those changes to the database.<br \/>\n\u5b9e\u9645\u4e0a\uff0c\u901a\u8fc7\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u66f4\u65b0\u4e0a\u4e0b\u6587\u7684\u57fa\u7c7b\uff0c\u4f60\u5df2\u5411 EF Core \u7684\u6570\u636e\u6a21\u578b\u6dfb\u52a0\u4e86\u5927\u91cf\u65b0\u5b9e\u4f53\u3002\u5982\u7b2c 12 \u7ae0\u6240\u793a\uff0c\u6bcf\u5f53 EF Core \u7684\u6570\u636e\u6a21\u578b\u53d1\u751f\u66f4\u6539\u65f6\uff0c\u90fd\u9700\u8981\u521b\u5efa\u65b0\u7684\u8fc1\u79fb\u5e76\u5c06\u8fd9\u4e9b\u66f4\u6539\u5e94\u7528\u4e8e\u6570\u636e\u5e93\u3002<\/p>\n<p>At this point, your app should compile, so you can add a new migration called AddIdentitySchema using<br \/>\n\u6b64\u65f6\uff0c\u4f60\u7684\u5e94\u7528\u5e94\u8be5\u4f1a\u7f16\u8bd1\uff0c\u56e0\u6b64\u4f60\u53ef\u4ee5\u4f7f\u7528 AddIdentitySchema \u6dfb\u52a0\u540d\u4e3a AddIdentitySchema \u7684\u65b0\u8fc1\u79fb<\/p>\n<pre><code>dotnet ef migrations add AddIdentitySchema<\/code><\/pre>\n<p>The final step is updating your application\u2019s Razor Pages and layouts to reference the default identity UI. Normally, adding 30 new Razor Pages to your application would be a lot of work, but using the default Identity UI makes it a breeze.<br \/>\n\u6700\u540e\u4e00\u6b65\u662f\u66f4\u65b0\u5e94\u7528\u7a0b\u5e8f\u7684 Razor Pages \u548c\u5e03\u5c40\u4ee5\u5f15\u7528\u9ed8\u8ba4\u6807\u8bc6 UI\u3002\u901a\u5e38\uff0c\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0 30 \u4e2a\u65b0\u7684 Razor \u9875\u9762\u4f1a\u662f\u4e00\u9879\u8270\u5de8\u7684\u5de5\u4f5c\uff0c\u4f46\u4f7f\u7528\u9ed8\u8ba4\u6807\u8bc6 UI \u4f1a\u53d8\u5f97\u8f7b\u800c\u6613\u4e3e\u3002<\/p>\n<h3>23.4.3 Updating the Razor views to link to the Identity UI<\/h3>\n<p>23.4.3 \u66f4\u65b0 Razor \u89c6\u56fe\u4ee5\u94fe\u63a5\u5230\u8eab\u4efd UI<\/p>\n<p>Technically, you don\u2019t have to update your Razor Pages to reference the pages included in the default UI, but you probably want to add the login widget to your app\u2019s layout at a minimum. You\u2019ll also want to make sure that your Identity Razor Pages use the same base Layout.cshtml as the rest of your application.<br \/>\n\u4ece\u6280\u672f\u4e0a\u8bb2\uff0c\u60a8\u4e0d\u5fc5\u66f4\u65b0 Razor Pages \u6765\u5f15\u7528\u9ed8\u8ba4 UI \u4e2d\u5305\u542b\u7684\u9875\u9762\uff0c\u4f46\u60a8\u53ef\u80fd\u5e0c\u671b\u81f3\u5c11\u5c06\u767b\u5f55\u5c0f\u7ec4\u4ef6\u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u7684\u5e03\u5c40\u4e2d\u3002\u8fd8\u9700\u8981\u786e\u4fdd Identity Razor \u9875\u9762\u4f7f\u7528\u4e0e\u5e94\u7528\u7a0b\u5e8f\u5176\u4f59\u90e8\u5206\u76f8\u540c\u7684\u57fa Layout.cshtml\u3002<\/p>\n<p>We\u2019ll start by fixing the layout for your Identity pages. Create a file at the \u201cmagic\u201d path Areas\/Identity\/Pages\/_ViewStart.cshtml, and add the following contents:<br \/>\n\u9996\u5148\uff0c\u6211\u4eec\u5c06\u4fee\u590d Identity \u9875\u9762\u7684\u5e03\u5c40\u3002\u5728\u201cmagic\u201d\u8def\u5f84 Areas\/Identity\/Pages\/_ViewStart.cshtml \u5904\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\uff0c\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a<\/p>\n<pre><code>@{ Layout = &quot;\/Pages\/Shared\/_Layout.cshtml&quot;; }<\/code><\/pre>\n<p>This sets the default layout for your Identity pages to your application\u2019s default layout. Next, add a _LoginPartial.cshtml file in Pages\/Shared to define the login widget, as shown in the following listing. This is pretty much identical to the template generated by the default template, but it uses our custom ApplicationUser instead of the default IdentityUser.<br \/>\n\u8fd9\u4f1a\u5c06 Identity \u9875\u9762\u7684\u9ed8\u8ba4\u5e03\u5c40\u8bbe\u7f6e\u4e3a\u5e94\u7528\u7a0b\u5e8f\u7684\u9ed8\u8ba4\u5e03\u5c40\u3002\u63a5\u4e0b\u6765\uff0c\u5728 Pages\/Shared \u4e2d\u6dfb\u52a0 _LoginPartial.cshtml \u6587\u4ef6\u4ee5\u5b9a\u4e49\u767b\u5f55\u5c0f\u7ec4\u4ef6\uff0c\u5982\u4e0b\u9762\u7684\u6e05\u5355\u6240\u793a\u3002\u8fd9\u4e0e\u9ed8\u8ba4\u6a21\u677f\u751f\u6210\u7684\u6a21\u677f\u51e0\u4e4e\u76f8\u540c\uff0c\u4f46\u5b83\u4f7f\u7528\u6211\u4eec\u7684\u81ea\u5b9a\u4e49 ApplicationUser \u800c\u4e0d\u662f\u9ed8\u8ba4\u7684 IdentityUser\u3002<\/p>\n<p>Listing 23.6 Adding a _LoginPartial.cshtml to an existing app<br \/>\n\u5217\u8868 23.6 \u5c06 _LoginPartial.cshtml \u6dfb\u52a0\u5230\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f<\/p>\n<pre><code>@using Microsoft.AspNetCore.Identity\n@using RecipeApplication.Data;                 #A\n@inject SignInManager&lt;ApplicationUser&gt; SignInManager    #B\n@inject UserManager&lt;ApplicationUser&gt; UserManager        #B\n\n&lt;ul class=&quot;navbar-nav&quot;&gt;\n@if (SignInManager.IsSignedIn(User))\n{\n  &lt;li class=&quot;nav-item&quot;&gt;\n    &lt;a  class=&quot;nav-link text-dark&quot; asp-area=&quot;Identity&quot;\n    asp-page=&quot;\/Account\/Manage\/Index&quot; title=&quot;Manage&quot;&gt;\n        Hello @User.Identity.Name!&lt;\/a&gt;\n  &lt;\/li&gt;\n    &lt;li class=&quot;nav-item&quot;&gt;\n      &lt;form class=&quot;form-inline&quot; asp-page=&quot;\/Account\/Logout&quot;\n      asp-route-returnUrl=&quot;@Url.Page(&quot;\/&quot;, new { area = &quot;&quot; })&quot;\n      asp-area=&quot;Identity&quot; method=&quot;post&quot; &gt;\n        &lt;button  class=&quot;nav-link btn btn-link text-dark&quot;\n          type=&quot;submit&quot;&gt;Logout&lt;\/button&gt;\n        &lt;\/form&gt;\n    &lt;\/li&gt;\n}\nelse\n{\n  &lt;li class=&quot;nav-item&quot;&gt;\n    &lt;a class=&quot;nav-link text-dark&quot; asp-area=&quot;Identity&quot;\n      asp-page=&quot;\/Account\/Register&quot;&gt;Register&lt;\/a&gt;\n  &lt;\/li&gt;\n  &lt;li class=&quot;nav-item&quot;&gt;\n    &lt;a class=&quot;nav-link text-dark&quot; asp-area=&quot;Identity&quot;\n      asp-page=&quot;\/Account\/Login&quot;&gt;Login&lt;\/a&gt;\n  &lt;\/li&gt;\n}\n&lt;\/ul&gt;<\/code><\/pre>\n<p>\u2776 Updates to your project\u2019s namespace that contains ApplicationUser<br \/>\n\u66f4\u65b0\u5305\u542b ApplicationUser\u7684\u9879\u76ee\u547d\u540d\u7a7a\u95f4<br \/>\n\u2777 The default template uses IdentityUser. Update to use ApplicationUser instead.<br \/>\n\u9ed8\u8ba4\u6a21\u677f\u4f7f\u7528 IdentityUser\u3002\u66f4\u65b0\u4ee5\u6539\u7528 ApplicationUser\u3002<\/p>\n<p>This partial shows the current login status of the user and provides links to register or sign in. All that remains is to render the partial by calling<br \/>\n\u6b64\u90e8\u5206\u663e\u793a\u7528\u6237\u7684\u5f53\u524d\u767b\u5f55\u72b6\u6001\uff0c\u5e76\u63d0\u4f9b\u7528\u4e8e\u6ce8\u518c\u6216\u767b\u5f55\u7684\u94fe\u63a5\u3002\u5269\u4e0b\u7684\u5c31\u662f\u901a\u8fc7\u8c03\u7528<\/p>\n<pre><code>&lt;partial name=&quot;_LoginPartial&quot; \/&gt;<\/code><\/pre>\n<p>in the main layout file of your app, _Layout.cshtml.<br \/>\n\u5728\u5e94\u7528\u7a0b\u5e8f\u7684\u4e3b\u5e03\u5c40\u6587\u4ef6\u4e2d\uff0c_Layout.cshtml\u3002<\/p>\n<p>And there you have it: you\u2019ve added Identity to an existing application. The default UI makes doing this relatively simple, and you can be sure you haven\u2019t introduced any security holes by building your own UI!<br \/>\n\u597d\u4e86\uff1a\u60a8\u5df2\u5c06 Identity \u6dfb\u52a0\u5230\u73b0\u6709\u5e94\u7528\u7a0b\u5e8f\u3002\u9ed8\u8ba4 UI \u4f7f\u6b64\u4f5c\u76f8\u5bf9\u7b80\u5355\uff0c\u60a8\u53ef\u4ee5\u786e\u4fdd\u901a\u8fc7\u6784\u5efa\u81ea\u5df1\u7684 UI \u6ca1\u6709\u5f15\u5165\u4efb\u4f55\u5b89\u5168\u6f0f\u6d1e\uff01<\/p>\n<p>As I described in section 23.3.4, there are some features that the default UI doesn\u2019t provide and you need to implement yourself, such as email confirmation and MFA QR code generation. It\u2019s also common to find that you want to update a single page here and there. In the next section I\u2019ll show how you can replace a page in the default UI, without having to rebuild the entire UI yourself.<br \/>\n\u6b63\u5982\u6211\u5728\u7b2c 23.3.4 \u8282\u4e2d\u6240\u63cf\u8ff0\u7684\uff0c\u9ed8\u8ba4 UI \u4e0d\u63d0\u4f9b\u4e00\u4e9b\u529f\u80fd\uff0c\u60a8\u9700\u8981\u81ea\u884c\u5b9e\u73b0\uff0c\u4f8b\u5982\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\u548c MFA QR \u7801\u751f\u6210\u3002\u4f60\u4e5f\u7ecf\u5e38\u4f1a\u53d1\u73b0\u4f60\u60f3\u5728\u8fd9\u91cc\u548c\u90a3\u91cc\u66f4\u65b0\u5355\u4e2a\u9875\u9762\u3002\u5728\u4e0b\u4e00\u8282\u4e2d\uff0c\u6211\u5c06\u5c55\u793a\u5982\u4f55\u66ff\u6362\u9ed8\u8ba4 UI \u4e2d\u7684\u9875\u9762\uff0c\u800c\u4e0d\u5fc5\u81ea\u5df1\u91cd\u65b0\u6784\u5efa\u6574\u4e2a UI\u3002<\/p>\n<h2>23.5 Customizing a page in ASP.NET Core Identity\u2019s default UI<\/h2>\n<p>23.5 \u5728 ASP.NET Core Identity \u7684\u9ed8\u8ba4 UI \u4e2d\u81ea\u5b9a\u4e49\u9875\u9762<\/p>\n<p>In this section you\u2019ll learn how to use scaffolding to replace individual pages in the default Identity UI. You\u2019ll learn to scaffold a page so that it overrides the default UI, allowing you to customize both the Razor template and the PageModel page handlers.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u4f7f\u7528\u57fa\u67b6\u66ff\u6362\u9ed8\u8ba4 Identity UI \u4e2d\u7684\u5404\u4e2a\u9875\u9762\u3002\u60a8\u5c06\u5b66\u4e60\u5982\u4f55\u642d\u5efa\u9875\u9762\u57fa\u67b6\uff0c\u4f7f\u5176\u8986\u76d6\u9ed8\u8ba4 UI\uff0c\u4ece\u800c\u5141\u8bb8\u60a8\u81ea\u5b9a\u4e49 Razor \u6a21\u677f\u548c PageModel \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u3002<\/p>\n<p>Having Identity provide the whole UI for your application is great in theory, but in practice there are a few wrinkles, as you saw in section 23.3.4. The default UI provides as much as it can, but there are some things you may want to tweak. For example, both the login and register pages describe how to configure external login providers for your ASP.NET Core applications, as you saw in figures 23.12 and 23.13. That\u2019s useful information for you as a developer, but it\u2019s not something you want to be showing to your users. Another often-cited requirement is the desire to change the look and feel of one or more pages.<br \/>\n\u8ba9 Identity \u4e3a\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u6574\u4e2a UI \u5728\u7406\u8bba\u4e0a\u5f88\u597d\uff0c\u4f46\u5728\u5b9e\u8df5\u4e2d\u5b58\u5728\u4e00\u4e9b\u95ee\u9898\uff0c\u6b63\u5982\u60a8\u5728\u7b2c 23.3.4 \u8282\u4e2d\u770b\u5230\u7684\u90a3\u6837\u3002\u9ed8\u8ba4 UI \u63d0\u4f9b\u4e86\u5c3d\u53ef\u80fd\u591a\u7684\u529f\u80fd\uff0c\u4f46\u60a8\u53ef\u80fd\u9700\u8981\u8c03\u6574\u4e00\u4e9b\u5185\u5bb9\u3002\u4f8b\u5982\uff0c\u767b\u5f55\u548c\u6ce8\u518c\u9875\u9762\u90fd\u63cf\u8ff0\u4e86\u5982\u4f55\u4e3a ASP.NET Core \u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5982\u56fe 23.12 \u548c 23.13 \u6240\u793a\u3002\u8fd9\u5bf9\u5f00\u53d1\u4eba\u5458\u6765\u8bf4\u5f88\u6709\u7528\uff0c\u4f46\u4e0d\u662f\u60a8\u5e0c\u671b\u5411\u7528\u6237\u5c55\u793a\u7684\u4fe1\u606f\u3002\u53e6\u4e00\u4e2a\u7ecf\u5e38\u88ab\u5f15\u7528\u7684\u8981\u6c42\u662f\u5e0c\u671b\u66f4\u6539\u4e00\u4e2a\u6216\u591a\u4e2a\u9875\u9762\u7684\u5916\u89c2\u3002<\/p>\n<p>Luckily, the default Identity UI is designed to be incrementally replaceable, so you can override a single page without having to rebuild the entire UI yourself. On top of that, both Visual Studio and the .NET CLI have functions that allow you to scaffold any (or all) of the pages in the default UI so that you don\u2019t have to start from scratch when you want to tweak a page.<br \/>\n\u5e78\u8fd0\u7684\u662f\uff0c\u9ed8\u8ba4\u7684 Identity UI \u8bbe\u8ba1\u4e3a\u53ef\u589e\u91cf\u66ff\u6362\uff0c\u56e0\u6b64\u60a8\u53ef\u4ee5\u8986\u76d6\u5355\u4e2a\u9875\u9762\uff0c\u800c\u65e0\u9700\u81ea\u5df1\u91cd\u65b0\u6784\u5efa\u6574\u4e2a UI\u3002\u6700\u91cd\u8981\u7684\u662f\uff0cVisual Studio \u548c .NET CLI \u90fd\u5177\u6709\u5141\u8bb8\u60a8\u5728\u9ed8\u8ba4 UI \u4e2d\u642d\u5efa\u4efb\u4f55\uff08\u6216\u6240\u6709\uff09\u9875\u9762\u7684\u57fa\u67b6\u7684\u529f\u80fd\uff0c\u8fd9\u6837\u5f53\u60a8\u60f3\u8981\u8c03\u6574\u9875\u9762\u65f6\uff0c\u5c31\u4e0d\u5fc5\u4ece\u5934\u5f00\u59cb\u3002<\/p>\n<p><b>DEFINITION<\/b> Scaffolding is the process of generating files in your project that serve as the basis for customization. The Identity scaffolder adds Razor Pages in the correct locations so they override equivalent pages with the default UI. Initially, the code in the scaffolded pages matches that in the default Identity UI, but you are free to customize it.<br \/>\n\u5b9a\u4e49\uff1a\u57fa\u67b6\u662f\u5728\u9879\u76ee\u4e2d\u751f\u6210\u6587\u4ef6\u4f5c\u4e3a\u81ea\u5b9a\u4e49\u57fa\u7840\u7684\u8fc7\u7a0b\u3002Identity \u57fa\u67b6\u5c06 Razor Pages \u6dfb\u52a0\u5230\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u4ee5\u4fbf\u5b83\u4eec\u4f7f\u7528\u9ed8\u8ba4 UI \u8986\u76d6\u7b49\u6548\u9875\u9762\u3002\u6700\u521d\uff0c\u57fa\u67b6\u9875\u9762\u4e2d\u7684\u4ee3\u7801\u4e0e\u9ed8\u8ba4 Identity UI \u4e2d\u7684\u4ee3\u7801\u5339\u914d\uff0c\u4f46\u60a8\u53ef\u4ee5\u81ea\u7531\u81ea\u5b9a\u4e49\u5b83\u3002<\/p>\n<p>As an example of the changes you can easily make, we\u2019ll scaffold the registration page and remove the additional information section about external providers. The following steps describe how to scaffold the Register.cshtml page in Visual Studio:<br \/>\n\u4f5c\u4e3a\u60a8\u53ef\u4ee5\u8f7b\u677e\u8fdb\u884c\u7684\u66f4\u6539\u7684\u793a\u4f8b\uff0c\u6211\u4eec\u5c06\u642d\u5efa\u6ce8\u518c\u9875\u9762\u5e76\u5220\u9664\u6709\u5173\u5916\u90e8\u63d0\u4f9b\u5546\u7684\u5176\u4ed6\u4fe1\u606f\u90e8\u5206\u3002\u4ee5\u4e0b\u6b65\u9aa4\u4ecb\u7ecd\u5982\u4f55\u5728 Visual Studio \u4e2d\u642d\u5efa Register.cshtml \u9875\u9762\u7684\u57fa\u67b6\uff1a<\/p>\n<ol>\n<li>Add the Microsoft.VisualStudio.Web.CodeGeneration.Design and Microsoft .EntityFrameworkCore.Tools NuGet packages to your project file, if they\u2019re not already added. Visual Studio uses these packages to scaffold your application correctly, and without them you may get an error running the scaffolder:<br \/>\n\u6dfb\u52a0 Microsoft.VisualStudio.Web.CodeGeneration.Design \u548c Microsoft \u3002EntityFrameworkCore.Tools NuGet \u5305\u6dfb\u52a0\u5230\u9879\u76ee\u6587\u4ef6\u4e2d\uff08\u5982\u679c\u5c1a\u672a\u6dfb\u52a0\uff09\u3002Visual Studio \u4f7f\u7528\u8fd9\u4e9b\u5305\u6765\u6b63\u786e\u642d\u5efa\u5e94\u7528\u7a0b\u5e8f\u57fa\u67b6\uff0c\u5982\u679c\u6ca1\u6709\u5b83\u4eec\uff0c\u8fd0\u884c Scaffolder \u65f6\u53ef\u80fd\u4f1a\u9047\u5230\u9519\u8bef\uff1a<\/li>\n<\/ol>\n<pre><code>&lt;PackageReference Version=&quot;7.0.0&quot;\n    Include=&quot;Microsoft.VisualStudio.Web.CodeGeneration.Design&quot; \/&gt;\n&lt;PackageReference Version=&quot;7.0.0&quot;\n    Include=&quot;Microsoft.EntityFrameworkCore.Tools&quot; \/&gt;<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>Ensure that your project builds. If it doesn\u2019t build, the scaffolder will fail before adding your new pages.<br \/>\n\u786e\u4fdd\u60a8\u7684\u9879\u76ee\u6784\u5efa\u6210\u529f\u3002\u5982\u679c\u5b83\u6ca1\u6709\u6784\u5efa\uff0c\u5219 scaffolder \u5c06\u5728\u6dfb\u52a0\u65b0\u9875\u9762\u4e4b\u524d\u5931\u8d25\u3002<\/p>\n<\/li>\n<li>\n<p>Right-click your project, and choose Add &gt; New Scaffolded Item from the contextual menu.<br \/>\n\u53f3\u952e\u5355\u51fb\u60a8\u7684\u9879\u76ee\uff0c\u7136\u540e\u4ece\u4e0a\u4e0b\u6587\u83dc\u5355\u4e2d\u9009\u62e9 Add &gt; New Scaffolded Item \uff08\u6dfb\u52a0\u65b0\u57fa\u67b6\u9879\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>In the selection dialog box, choose Identity from the category, and choose Add.<br \/>\n\u5728\u9009\u62e9\u5bf9\u8bdd\u6846\u4e2d\uff0c\u4ece\u7c7b\u522b\u4e2d\u9009\u62e9 Identity \uff08\u8eab\u4efd\uff09\uff0c\u7136\u540e\u9009\u62e9 Add \uff08\u6dfb\u52a0\uff09\u3002<\/p>\n<\/li>\n<li>\n<p>In the Add Identity dialog box, select the Account\/Register page, and select your application\u2019s AppDbContext as the Data context class, as shown in figure 23.12. Choose Add to scaffold the page.<br \/>\n\u5728 Add Identity \u5bf9\u8bdd\u6846\u4e2d\uff0c\u9009\u62e9 Account\/Register \u9875\u9762\uff0c\u7136\u540e\u9009\u62e9\u5e94\u7528\u7a0b\u5e8f\u7684 AppDbContext \u4f5c\u4e3a Data \u4e0a\u4e0b\u6587\u7c7b\uff0c\u5982\u56fe 23.12 \u6240\u793a\u3002\u9009\u62e9 Add \uff08\u6dfb\u52a0\uff09 \u4ee5\u642d\u5efa\u9875\u9762\u57fa\u67b6\u3002<\/p>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2312.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.12 Using Visual Studio to scaffold Identity pages. The generated Razor Pages will override the versions provided by the default UI.<br \/>\n\u56fe 23.12 \u4f7f\u7528 Visual Studio \u642d\u5efa Identity \u9875\u9762\u7684\u57fa\u67b6\u3002\u751f\u6210\u7684 Razor Pages \u5c06\u66ff\u4ee3\u9ed8\u8ba4 UI \u63d0\u4f9b\u7684\u7248\u672c\u3002<\/p>\n<p><b>Tip<\/b> To scaffold the registration page using the .NET CLI, install the required tools and packages as described in Microsoft\u2019s \u201cScaffold Identity in ASP.NET Core projects\u201d documentation: <a href=\"http:\/\/mng.bz\/QPRv\">http:\/\/mng.bz\/QPRv<\/a>. Then run dotnet aspnet-codegenerator identity -dc RecipeApplication.Data.AppDbContext --files &quot;Account.Register&quot;.<br \/>\n\u63d0\u793a\uff1a\u8981\u4f7f\u7528 .NET CLI \u642d\u5efa\u6ce8\u518c\u9875\u9762\u7684\u57fa\u67b6\uff0c\u8bf7\u6309\u7167 Microsoft \u7684\u201cASP.NET Core \u9879\u76ee\u4e2d\u7684\u57fa\u67b6\u6807\u8bc6\u201d\u6587\u6863\u4e2d\u6240\u8ff0\u5b89\u88c5\u6240\u9700\u7684\u5de5\u5177\u548c\u5305\uff1a<a href=\"http:\/\/mng.bz\/QPRv\u3002\u7136\u540e\u8fd0\u884c\">http:\/\/mng.bz\/QPRv\u3002\u7136\u540e\u8fd0\u884c<\/a> dotnet aspnet-codegenerator identity -dc RecipeApplication.Data.AppDbContext --files \u201cAccount.Register\u201d\u3002<\/p>\n<p>Visual Studio builds your application and then generates the Register.cshtml page for you, placing it in the Areas\/Identity\/Pages\/Account folder. It also generates several supporting files, as shown in figure 23.13. These are required mostly to ensure that your new Register.cshtml page can reference the remaining pages in the default Identity UI.<br \/>\nVisual Studio \u751f\u6210\u5e94\u7528\u7a0b\u5e8f\uff0c\u7136\u540e\u751f\u6210 Register.cshtml \u9875\u9762\uff0c\u5c06\u5176\u653e\u7f6e\u5728 Areas\/Identity\/Pages\/Account \u6587\u4ef6\u5939\u4e2d\u3002\u5b83\u8fd8\u4f1a\u751f\u6210\u51e0\u4e2a\u652f\u6301\u6587\u4ef6\uff0c\u5982\u56fe 23.13 \u6240\u793a\u3002\u8fd9\u4e9b\u4e3b\u8981\u662f\u4e3a\u4e86\u786e\u4fdd\u65b0\u7684 Register.cshtml \u9875\u9762\u53ef\u4ee5\u5f15\u7528\u9ed8\u8ba4\u6807\u8bc6 UI \u4e2d\u7684\u5176\u4f59\u9875\u9762\u3002<\/p>\n<p><img decoding=\"async\" src=\"\/images\/aspnetcoreinaction\/2313.png\" alt=\"alt text\" \/><\/p>\n<p>Figure 23.13 The scaffolder generates the Register.cshtml Razor Page, along with supporting files required to integrate with the remainder of the default Identity UI.<br \/>\n\u56fe 23.13 \u57fa\u67b6\u751f\u6210 Register.cshtml Razor \u9875\u9762\uff0c\u4ee5\u53ca\u4e0e\u9ed8\u8ba4\u6807\u8bc6 UI \u7684\u5176\u4f59\u90e8\u5206\u96c6\u6210\u6240\u9700\u7684\u652f\u6301\u6587\u4ef6\u3002<\/p>\n<p>We\u2019re interested in the Register.cshtml page, as we want to customize the UI on the Register page, but if we look inside the code-behind page, Register.cshtml.cs, we see how much complexity the default Identity UI is hiding from us. It\u2019s not insurmountable (we\u2019ll customize the page handler in section 23.6), but it\u2019s always good to avoid writing code if we can help it.<br \/>\n\u6211\u4eec\u5bf9 Register.cshtml \u9875\u9762\u611f\u5174\u8da3\uff0c\u56e0\u4e3a\u6211\u4eec\u5e0c\u671b\u81ea\u5b9a\u4e49 Register \u9875\u9762\u4e0a\u7684 UI\uff0c\u4f46\u5982\u679c\u6211\u4eec\u67e5\u770b\u4ee3\u7801\u9690\u85cf\u9875\u9762 Register.cshtml.cs\uff0c\u6211\u4eec\u4f1a\u770b\u5230\u9ed8\u8ba4\u8eab\u4efd UI \u5bf9\u6211\u4eec\u9690\u85cf\u4e86\u591a\u5c11\u590d\u6742\u6027\u3002\u8fd9\u5e76\u4e0d\u662f\u4e0d\u53ef\u514b\u670d\u7684\uff08\u6211\u4eec\u5c06\u5728 Section 23.6 \u4e2d\u81ea\u5b9a\u4e49\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff09\uff0c\u4f46\u5982\u679c\u6211\u4eec\u53ef\u4ee5\u63d0\u4f9b\u5e2e\u52a9\uff0c\u907f\u514d\u7f16\u5199\u4ee3\u7801\u603b\u662f\u597d\u7684\u3002<\/p>\n<p>Now that you have the Razor template in your application, you can customize it to your heart\u2019s content. The downside is that you\u2019re now maintaining more code than you were with the default UI. You didn\u2019t have to write it, but you may still have to update it when a new version of ASP.NET Core is released.<br \/>\n\u73b0\u5728\uff0c\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u4e2d\u5df2\u6709 Razor \u6a21\u677f\uff0c\u60a8\u53ef\u4ee5\u6839\u636e\u81ea\u5df1\u7684\u559c\u597d\u5bf9\u5176\u8fdb\u884c\u81ea\u5b9a\u4e49\u3002\u7f3a\u70b9\u662f\uff0c\u60a8\u73b0\u5728\u7ef4\u62a4\u7684\u4ee3\u7801\u6bd4\u4f7f\u7528\u9ed8\u8ba4 UI \u65f6\u8981\u591a\u3002\u60a8\u4e0d\u5fc5\u7f16\u5199\u5b83\uff0c\u4f46\u5728 ASP.NET Core \u7684\u65b0\u7248\u672c\u53d1\u5e03\u65f6\uff0c\u60a8\u53ef\u80fd\u4ecd\u9700\u8981\u66f4\u65b0\u5b83\u3002<\/p>\n<p>I like to use a bit of a trick when it comes to overriding the default Identity UI like this. In many cases, you don\u2019t want to change the page handlers for the Razor Page\u2014only the Razor view. You can achieve this by deleting the Register.cshtml.cs PageModel file, and pointing your newly scaffolded .cshtml file at the original PageModel, which is part of the default UI NuGet package.<br \/>\n\u5728\u8986\u76d6\u50cf\u8fd9\u6837\u7684\u9ed8\u8ba4\u8eab\u4efd UI \u65f6\uff0c\u6211\u559c\u6b22\u4f7f\u7528\u4e00\u4e9b\u6280\u5de7\u3002\u5728\u8bb8\u591a\u60c5\u51b5\u4e0b\uff0c\u60a8\u4e0d\u5e0c\u671b\u66f4\u6539 Razor \u9875\u9762\u7684\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u800c\u53ea\u9700\u8981\u66f4\u6539 Razor \u89c6\u56fe\u3002\u4e3a\u6b64\uff0c\u60a8\u53ef\u4ee5\u5220\u9664Register.cshtml.cs PageModel \u6587\u4ef6\uff0c\u5e76\u5c06\u65b0\u642d\u5efa\u7684 .cshtml \u6587\u4ef6\u6307\u5411\u539f\u59cb PageModel\uff0c\u8be5 PageModel \u662f\u9ed8\u8ba4 UI NuGet \u5305\u7684\u4e00\u90e8\u5206\u3002<\/p>\n<p>The other benefit of this approach is that you can delete some of the other files that were autoscaffolded. In total, you can make the following changes:<br \/>\n\u6b64\u65b9\u6cd5\u7684\u53e6\u4e00\u4e2a\u597d\u5904\u662f\uff0c\u60a8\u53ef\u4ee5\u5220\u9664\u4e00\u4e9b\u81ea\u52a8\u57fa\u67b6\u7684\u5176\u4ed6\u6587\u4ef6\u3002\u603b\u7684\u6765\u8bf4\uff0c\u60a8\u53ef\u4ee5\u8fdb\u884c\u4ee5\u4e0b\u66f4\u6539\uff1a<\/p>\n<p>\u2022  Update the @model directive in Register.cshtml to point to the default UI PageModel:<br \/>\n\u66f4\u65b0 Register.cshtml \u4e2d\u7684 @model \u6307\u4ee4\u4ee5\u6307\u5411\u9ed8\u8ba4 UI PageModel\uff1a<\/p>\n<pre><code>@model Microsoft.AspNetCore.Identity.UI.V5.Pages.Account.Internal.RegisterModel<\/code><\/pre>\n<p>\u2022  Update Areas\/Identity\/Pages\/_ViewImports.cshtml to the following:<br \/>\n\u5c06 Areas\/Identity\/Pages\/_ViewImports.cshtml \u66f4\u65b0\u4e3a\u4ee5\u4e0b\u5185\u5bb9\uff1a<\/p>\n<pre><code>@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<\/code><\/pre>\n<p>\u2022  Delete Areas\/Identity\/Pages\/_ValidationScriptsPartial.cshtml.<br \/>\n\u2022  Delete Areas\/Identity\/Pages\/Account\/Register.cshtml.cs.<br \/>\n\u2022  Delete Areas\/Identity\/Pages\/Account\/_ViewImports.cshtml.<\/p>\n<p>After making all these changes, you\u2019ll have the best of both worlds: you can update the default UI Razor Pages HTML without taking on the responsibility of maintaining the default UI code-behind.<br \/>\n\u8fdb\u884c\u6240\u6709\u8fd9\u4e9b\u66f4\u6539\u540e\uff0c\u4f60\u5c06\u83b7\u5f97\u4e24\u5168\u5176\u7f8e\u7684\u6548\u679c\uff1a\u53ef\u4ee5\u66f4\u65b0\u9ed8\u8ba4 UI Razor Pages HTML\uff0c\u800c\u65e0\u9700\u8d1f\u8d23\u7ef4\u62a4\u9ed8\u8ba4 UI \u4ee3\u7801\u9690\u85cf\u3002<\/p>\n<p><b>Tip<\/b> In the source code for the book, you can see these changes in action, where the Register view has been customized to remove the references to external identity providers.<br \/>\n\u63d0\u793a\uff1a\u5728\u672c\u4e66\u7684\u6e90\u4ee3\u7801\u4e2d\uff0c\u60a8\u53ef\u4ee5\u770b\u5230\u8fd9\u4e9b\u5b9e\u9645\u66f4\u6539\uff0c\u5176\u4e2d Register \u89c6\u56fe\u5df2\u81ea\u5b9a\u4e49\u4ee5\u5220\u9664\u5bf9\u5916\u90e8\u8eab\u4efd\u63d0\u4f9b\u8005\u7684\u5f15\u7528\u3002<\/p>\n<p>Unfortunately, it\u2019s not always possible to use the default UI PageModel. Sometimes you need to update the page handlers, such as when you want to change the functionality of your Identity area rather than only the look and feel. A common requirement is needing to store additional information about a user, as you\u2019ll see in the next section.<br \/>\n\u9057\u61be\u7684\u662f\uff0c\u5e76\u975e\u603b\u662f\u53ef\u4ee5\u4f7f\u7528\u9ed8\u8ba4\u7684 UI PageModel\u3002\u6709\u65f6\uff0c\u60a8\u9700\u8981\u66f4\u65b0\u9875\u9762\u5904\u7406\u7a0b\u5e8f\uff0c\u4f8b\u5982\uff0c\u5f53\u60a8\u60f3\u8981\u66f4\u6539 Identity \u533a\u57df\u7684\u529f\u80fd\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u5916\u89c2\u65f6\u3002\u4e00\u4e2a\u5e38\u89c1\u7684\u8981\u6c42\u662f\u9700\u8981\u5b58\u50a8\u6709\u5173\u7528\u6237\u7684\u5176\u4ed6\u4fe1\u606f\uff0c\u60a8\u5c06\u5728\u4e0b\u4e00\u8282\u4e2d\u770b\u5230\u3002<\/p>\n<h2>23.6 Managing users: Adding custom data to users<\/h2>\n<p>23.6 \u7ba1\u7406\u7528\u6237\uff1a\u5411\u7528\u6237\u6dfb\u52a0\u81ea\u5b9a\u4e49\u6570\u636e<\/p>\n<p>In this section you\u2019ll see how to customize the ClaimsPrincipal assigned to your users by adding claims to the AspNetUserClaims table when the user is created. You\u2019ll also see how to access these claims in your Razor Pages and templates.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3\u5982\u4f55\u901a\u8fc7\u5728\u521b\u5efa\u7528\u6237\u65f6\u5411 AspNetUserClaims \u8868\u6dfb\u52a0\u58f0\u660e\u6765\u81ea\u5b9a\u4e49\u5206\u914d\u7ed9\u7528\u6237\u7684 ClaimsPrincipal\u3002\u60a8\u8fd8\u5c06\u4e86\u89e3\u5982\u4f55\u5728 Razor \u9875\u9762\u548c\u6a21\u677f\u4e2d\u8bbf\u95ee\u8fd9\u4e9b\u58f0\u660e\u3002<\/p>\n<p>Often, the next step after adding Identity to an application is customizing it. The default templates require only an email and password to register. What if you need more details, like a friendly name for the user? Also, I\u2019ve mentioned that we use claims for security, so what if you want to add a claim called IsAdmin to certain users?<br \/>\n\u901a\u5e38\uff0c\u5c06 Identity \u6dfb\u52a0\u5230\u5e94\u7528\u7a0b\u5e8f\u540e\u7684\u4e0b\u4e00\u6b65\u662f\u5bf9\u5176\u8fdb\u884c\u81ea\u5b9a\u4e49\u3002\u9ed8\u8ba4\u6a21\u677f\u53ea\u9700\u8981\u7535\u5b50\u90ae\u4ef6\u548c\u5bc6\u7801\u5373\u53ef\u6ce8\u518c\u3002\u5982\u679c\u60a8\u9700\u8981\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u4f8b\u5982\u7528\u6237\u7684\u53cb\u597d\u540d\u79f0\uff0c\u8be5\u600e\u4e48\u529e\uff1f\u6b64\u5916\uff0c\u6211\u8fd8\u63d0\u5230\u8fc7\u6211\u4eec\u4f7f\u7528\u58f0\u660e\u6765\u5b9e\u73b0\u5b89\u5168\u6027\uff0c\u90a3\u4e48\uff0c\u5982\u679c\u60a8\u60f3\u5411\u67d0\u4e9b\u7528\u6237\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a IsAdmin \u7684\u58f0\u660e\uff0c\u8be5\u600e\u4e48\u529e\uff1f<\/p>\n<p>You know that every user principal has a collection of claims, so conceptually, adding any claim requires adding it to the user\u2019s collection. There are two main times that you would want to grant a claim to a user:<br \/>\n\u60a8\u77e5\u9053\u6bcf\u4e2a\u7528\u6237\u4e3b\u4f53\u90fd\u6709\u4e00\u4e2a\u58f0\u660e\u96c6\u5408\uff0c\u56e0\u6b64\u4ece\u6982\u5ff5\u4e0a\u8bb2\uff0c\u6dfb\u52a0\u4efb\u4f55\u58f0\u660e\u90fd\u9700\u8981\u5c06\u5176\u6dfb\u52a0\u5230\u7528\u6237\u7684\u96c6\u5408\u4e2d\u3002\u60a8\u5e0c\u671b\u5411\u7528\u6237\u6388\u4e88\u58f0\u660e\u7684\u4e3b\u8981\u65f6\u95f4\u6709\u4e24\u4e2a\uff1a<\/p>\n<p>\u2022  For every user, when they register on the app\u2014For example, you might want to add a Name field to the Register form and add that as a claim to the user when they register.<br \/>\n\u5bf9\u4e8e\u6bcf\u4e2a\u7528\u6237\uff0c\u5f53\u4ed6\u4eec\u5728\u5e94\u7528\u7a0b\u5e8f\u4e0a\u6ce8\u518c\u65f6 - \u4f8b\u5982\uff0c\u60a8\u53ef\u80fd\u5e0c\u671b\u5c06\u201c\u540d\u79f0\u201d\u5b57\u6bb5\u6dfb\u52a0\u5230\u201c\u6ce8\u518c\u201d\u8868\u5355\u4e2d\uff0c\u5e76\u5728\u7528\u6237\u6ce8\u518c\u65f6\u5c06\u5176\u4f5c\u4e3a\u58f0\u660e\u6dfb\u52a0\u5230\u7528\u6237\u3002<br \/>\n\u2022  Manually, after the user has registered\u2014This is common for claims used as permissions, where an existing user might want to add an IsAdmin claim to a specific user after they have registered on the app.<br \/>\n\u5728\u7528\u6237\u6ce8\u518c\u540e\u624b\u52a8 - \u8fd9\u5728\u7528\u4f5c\u6743\u9650\u7684\u58f0\u660e\u4e2d\u5f88\u5e38\u89c1\uff0c\u5176\u4e2d\u73b0\u6709\u7528\u6237\u53ef\u80fd\u5e0c\u671b\u5728\u7279\u5b9a\u7528\u6237\u6ce8\u518c\u5e94\u7528\u7a0b\u5e8f\u540e\u5411\u7279\u5b9a\u7528\u6237\u6dfb\u52a0 IsAdmin \u58f0\u660e\u3002<\/p>\n<p>In this section I\u2019ll show you the first approach, automatically adding new claims to a user when they\u2019re created. The latter approach is more flexible and ultimately is the approach many apps will need, especially line-of-business apps. Luckily, there\u2019s nothing conceptually difficult to it; it requires a simple UI that lets you view users and add a claim through the same mechanism I\u2019ll show here.<br \/>\n\u5728\u672c\u8282\u4e2d\uff0c\u6211\u5c06\u5411\u60a8\u5c55\u793a\u7b2c\u4e00\u79cd\u65b9\u6cd5\uff0c\u5373\u5728\u521b\u5efa\u7528\u6237\u65f6\u81ea\u52a8\u5411\u7528\u6237\u6dfb\u52a0\u65b0\u58f0\u660e\u3002\u540e\u4e00\u79cd\u65b9\u6cd5\u66f4\u7075\u6d3b\uff0c\u6700\u7ec8\u662f\u8bb8\u591a\u5e94\u7528\u7a0b\u5e8f\u9700\u8981\u7684\u65b9\u6cd5\uff0c\u5c24\u5176\u662f\u4e1a\u52a1\u7ebf\u5e94\u7528\u7a0b\u5e8f\u3002\u5e78\u8fd0\u7684\u662f\uff0c\u5b83\u5728\u6982\u5ff5\u4e0a\u6ca1\u6709\u4ec0\u4e48\u56f0\u96be;\u5b83\u9700\u8981\u4e00\u4e2a\u7b80\u5355\u7684 UI\uff0c\u5141\u8bb8\u60a8\u901a\u8fc7\u6211\u5c06\u5728\u6b64\u5904\u5c55\u793a\u7684\u76f8\u540c\u673a\u5236\u67e5\u770b\u7528\u6237\u5e76\u6dfb\u52a0\u58f0\u660e\u3002<\/p>\n<p><b>Tip<\/b> Another common approach is to customize the IdentityUser entity, by adding a Name property, for example. This approach is sometimes easier to work with if you want to give users the ability to edit that property. Microsoft\u2019s \u201cAdd, download, and delete custom user data to Identity in an ASP.NET Core project\u201d documentation describes the steps required to achieve that: <a href=\"http:\/\/mng.bz\/aoe7\">http:\/\/mng.bz\/aoe7<\/a>.<br \/>\n\u63d0\u793a\uff1a\u53e6\u4e00\u79cd\u5e38\u89c1\u65b9\u6cd5\u662f\u81ea\u5b9a\u4e49 IdentityUser \u5b9e\u4f53\uff0c\u4f8b\u5982\uff0c\u901a\u8fc7\u6dfb\u52a0 Name \u5c5e\u6027\u3002\u5982\u679c\u60a8\u60f3\u8ba9\u7528\u6237\u80fd\u591f\u7f16\u8f91\u8be5\u5c5e\u6027\uff0c\u8fd9\u79cd\u65b9\u6cd5\u6709\u65f6\u66f4\u5bb9\u6613\u4f7f\u7528\u3002Microsoft \u7684\u201c\u5728 ASP.NET Core \u9879\u76ee\u4e2d\u5411 Identity \u6dfb\u52a0\u3001\u4e0b\u8f7d\u548c\u5220\u9664\u81ea\u5b9a\u4e49\u7528\u6237\u6570\u636e\u201d\u6587\u6863\u4ecb\u7ecd\u4e86\u5b9e\u73b0\u6b64\u76ee\u7684\u6240\u9700\u7684\u6b65\u9aa4\uff1a<a href=\"http:\/\/mng.bz\/aoe7\">http:\/\/mng.bz\/aoe7<\/a>\u3002<\/p>\n<p>Let\u2019s say you want to add a new Claim to a user, called FullName. A typical approach would be as follows:<br \/>\n\u5047\u8bbe\u60a8\u8981\u5411\u540d\u4e3a FullName \u7684\u7528\u6237\u6dfb\u52a0\u65b0\u58f0\u660e\u3002\u5178\u578b\u7684\u65b9\u6cd5\u5982\u4e0b\uff1a<\/p>\n<ol>\n<li>\n<p>Scaffold the Register.cshtml Razor Page, as you did in section 23.5.<br \/>\n\u642d\u5efa Register.cshtml Razor \u9875\u9762\u7684\u57fa\u67b6\uff0c\u5c31\u50cf\u5728\u7b2c 23.5 \u8282\u4e2d\u6240\u505a\u7684\u90a3\u6837\u3002<\/p>\n<\/li>\n<li>\n<p>Add a Name field to the InputModel in the Register.cshtml.cs PageModel.<br \/>\n\u5c06 Name \u5b57\u6bb5\u6dfb\u52a0\u5230 Register.cshtml.cs PageModel \u4e2d\u7684 InputModel\u3002<\/p>\n<\/li>\n<li>\n<p>Add a Name input field to the Register.cshtml Razor view template.<br \/>\n\u5c06 Name \u8f93\u5165\u5b57\u6bb5\u6dfb\u52a0\u5230 Register.cshtml Razor \u89c6\u56fe\u6a21\u677f\u3002<\/p>\n<\/li>\n<li>\n<p>Create the new ApplicationUser entity as before in the OnPost() page handler by calling CreateAsync on <code>UserManager&lt;ApplicationUser&gt;<\/code>.<br \/>\n\u50cf\u4ee5\u524d\u4e00\u6837\uff0c\u901a\u8fc7\u5728 UserManager \u4e0a\u8c03\u7528 CreateAsync \u5728 OnPost\uff08\uff09 \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e2d\u521b\u5efa\u65b0\u7684 <code>UserManager&lt;ApplicationUser&gt;<\/code>\u5b9e\u4f53\u3002<\/p>\n<\/li>\n<li>\n<p>Add a new Claim to the user by calling UserManager.AddClaimAsync().<br \/>\n\u901a\u8fc7\u8c03\u7528 UserManager.AddClaimAsync\uff08\uff09 \u5411\u7528\u6237\u6dfb\u52a0\u65b0\u7684\u58f0\u660e\u3002<\/p>\n<\/li>\n<li>\n<p>Continue the method as before, sending a confirmation email or signing the user in if email confirmation is not required.<br \/>\n\u50cf\u4ee5\u524d\u4e00\u6837\u7ee7\u7eed\u8be5\u65b9\u6cd5\uff0c\u53d1\u9001\u786e\u8ba4\u7535\u5b50\u90ae\u4ef6\uff0c\u5982\u679c\u4e0d\u9700\u8981\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\uff0c\u5219\u8ba9\u7528\u6237\u767b\u5f55\u3002<\/p>\n<\/li>\n<\/ol>\n<p>Steps 1\u20133 are fairly self-explanatory and require only updating the existing templates with the new field. Steps 4\u20136 take place in Register.cshtml.cs in the OnPostAsync() page handler, which is summarized in the following listing. In practice, the page handler has more error checking, boilerplate, extra features, and abstraction. I\u2019ve simplified the code in listing 23.7 to focus on the additional lines that add the extra Claim to the ApplicationUser; you can find the full code in the sample code for this chapter.<br \/>\n\u6b65\u9aa4 1-3 \u76f8\u5f53\u4e0d\u8a00\u81ea\u660e\uff0c\u53ea\u9700\u8981\u4f7f\u7528\u65b0\u5b57\u6bb5\u66f4\u65b0\u73b0\u6709\u6a21\u677f\u3002\u6b65\u9aa4 4-6 \u5728 OnPostAsync\uff08\uff09 \u9875\u9762\u5904\u7406\u7a0b\u5e8f\u4e2dRegister.cshtml.cs\u8fdb\u884c\uff0c\u4e0b\u9762\u7684\u6e05\u5355\u5bf9\u6b64\u8fdb\u884c\u4e86\u603b\u7ed3\u3002\u5728\u5b9e\u8df5\u4e2d\uff0c\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u5177\u6709\u66f4\u591a\u7684\u9519\u8bef\u68c0\u67e5\u3001\u6837\u677f\u3001\u989d\u5916\u529f\u80fd\u548c\u62bd\u8c61\u3002\u6211\u7b80\u5316\u4e86\u6e05\u5355 23.7 \u4e2d\u7684\u4ee3\u7801\uff0c\u4ee5\u4e13\u6ce8\u4e8e\u5411 ApplicationUser \u6dfb\u52a0\u989d\u5916 Claim \u7684\u5176\u4ed6\u884c;\u60a8\u53ef\u4ee5\u5728\u672c\u7ae0\u7684\u793a\u4f8b\u4ee3\u7801\u4e2d\u627e\u5230\u5b8c\u6574\u4ee3\u7801\u3002<\/p>\n<p>Listing 23.7 Adding a custom claim to a new user in the Register.cshtml.cs page<br \/>\n\u6e05\u5355 23.7 \u5728 Register.cshtml.cs \u9875\u9762\u4e2d\u4e3a\u65b0\u7528\u6237\u6dfb\u52a0\u81ea\u5b9a\u4e49\u58f0\u660e<\/p>\n<pre><code>public async Task&lt;IActionResult&gt; OnPostAsync(string returnUrl = null)\n{\n    if (ModelState.IsValid)\n    {\n        var user = new ApplicationUser {                    #A\n            UserName = Input.Email, Email = Input.Email };  #A\n        var result = await _userManager.CreateAsync(      #B\n            user, Input.Password);                        #B\n        if (result.Succeeded)\n        {\n            var claim = new Claim(&quot;FullName&quot;, Input.Name);   #C\n            await _userManager.AddClaimAsync(user, claim);   #D\n            var code = await _userManager                      #E\n                .GenerateEmailConfirmationTokenAsync(user);    #E\n            await _emailSender.SendEmailAsync(                 #E\n                 Input.Email, &quot;Confirm your email&quot;, code );    #E\n            await _signInManager.SignInAsync(user);   #F\n            return LocalRedirect(returnUrl);\n        }\n        foreach (var error in result.Errors)         #G\n        {                                            #G\n            ModelState.AddModelError(                #G\n                string.Empty, error.Description);    #G\n        }                                            #G\n    }\n       return Page();                                #G\n}<\/code><\/pre>\n<p>\u2776 Creates an instance of the ApplicationUser entity<br \/>\n\u521b\u5efa ApplicationUser \u5b9e\u4f53\u7684\u5b9e\u4f8b<br \/>\n\u2777 Validates that the provided password meets requirements, and creates the user in the database<br \/>\n\u9a8c\u8bc1\u63d0\u4f9b\u7684\u5bc6\u7801\u662f\u5426\u6ee1\u8db3\u8981\u6c42\uff0c\u5e76\u5728\u6570\u636e\u5e93\u4e2d\u521b\u5efa\u7528\u6237<br \/>\n\u2778 Creates a claim, with a string name of \u201cFullName\u201d and the provided value<br \/>\n\u521b\u5efa\u5b57\u7b26\u4e32\u540d\u79f0\u4e3a\u201cFullName\u201d\u4e14\u63d0\u4f9b\u7684\u503c\u7684\u58f0\u660e<br \/>\n\u2779 Adds the new claim to the ApplicationUser\u2019s collection<br \/>\n\u5c06\u65b0\u58f0\u660e\u6dfb\u52a0\u5230 ApplicationUser \u7684\u96c6\u5408<br \/>\n\u277a Sends a confirmation email to the user, if you have configured the email sender<br \/>\n\u5411\u7528\u6237\u53d1\u9001\u786e\u8ba4\u7535\u5b50\u90ae\u4ef6\uff08\u5982\u679c\u60a8\u5df2\u914d\u7f6e\u7535\u5b50\u90ae\u4ef6\u53d1\u4ef6\u4eba\uff09<br \/>\n\u277b Signs the user in by setting the HttpContext.User; the principal will include the custom claim<br \/>\n\u901a\u8fc7\u8bbe\u7f6e HttpContext.User \u6765\u767b\u5f55\u7528\u6237;\u4e3b\u4f53\u5c06\u5305\u542b\u81ea\u5b9a\u4e49\u58f0\u660e<br \/>\n\u277c There was a problem creating the user. Adds the errors to the ModelState and redisplays the page.<br \/>\n\u521b\u5efa\u7528\u6237\u65f6\u51fa\u73b0\u95ee\u9898\u3002\u5c06\u9519\u8bef\u6dfb\u52a0\u5230 ModelState \u5e76\u91cd\u65b0\u663e\u793a\u9875\u9762\u3002<\/p>\n<p><b>Tip<\/b> Listing 23.7 shows how you can add extra claims at registration time, but you will often need to add more data later, such as permission-related claims or other information. You will need to create additional endpoints and pages for adding this data, securing the pages as appropriate (so that users can\u2019t update their own permissions, for example).<br \/>\n\u63d0\u793a:\u6e05\u5355 23.7 \u5c55\u793a\u4e86\u5982\u4f55\u5728\u6ce8\u518c\u65f6\u6dfb\u52a0\u989d\u5916\u7684\u58f0\u660e\uff0c\u4f46\u60a8\u901a\u5e38\u9700\u8981\u7a0d\u540e\u6dfb\u52a0\u66f4\u591a\u6570\u636e\uff0c\u4f8b\u5982\u4e0e\u6743\u9650\u76f8\u5173\u7684\u58f0\u660e\u6216\u5176\u4ed6\u4fe1\u606f\u3002\u60a8\u9700\u8981\u521b\u5efa\u5176\u4ed6\u7ec8\u7aef\u8282\u70b9\u548c\u9875\u9762\u6765\u6dfb\u52a0\u6b64\u6570\u636e\uff0c\u5e76\u6839\u636e\u9700\u8981\u4fdd\u62a4\u9875\u9762\uff08\u4f8b\u5982\uff0c\u4f7f\u7528\u6237\u65e0\u6cd5\u66f4\u65b0\u81ea\u5df1\u7684\u6743\u9650\uff09\u3002<\/p>\n<p>This is all that\u2019s required to add the new claim, but you\u2019re not using it anywhere currently. What if you want to display it? Well, you\u2019ve added a claim to the ClaimsPrincipal, which was assigned to the HttpContext.User property when you called SignInAsync. That means you can retrieve the claims anywhere you have access to the ClaimsPrincipal\u2014including in your page handlers and in view templates. For example, you could display the user\u2019s FullName claim anywhere in a Razor template with the following statement:<br \/>\n\u8fd9\u5c31\u662f\u6dfb\u52a0\u65b0\u58f0\u660e\u6240\u9700\u7684\u5168\u90e8\u5185\u5bb9\uff0c\u4f46\u60a8\u76ee\u524d\u6ca1\u6709\u5728\u4efb\u4f55\u5730\u65b9\u4f7f\u7528\u5b83\u3002\u5982\u679c\u8981\u663e\u793a\u5b83\u600e\u4e48\u529e\uff1f\u55ef\uff0c\u60a8\u5df2\u7ecf\u5411 ClaimsPrincipal \u6dfb\u52a0\u4e86\u4e00\u4e2a\u58f0\u660e\uff0c\u8be5\u58f0\u660e\u5728\u8c03\u7528 SignInAsync \u65f6\u5206\u914d\u7ed9 HttpContext.User \u5c5e\u6027\u3002\u8fd9\u610f\u5473\u7740\u60a8\u53ef\u4ee5\u5728\u4efb\u4f55\u6709\u6743\u8bbf\u95ee ClaimsPrincipal \u7684\u4f4d\u7f6e\u68c0\u7d22\u58f0\u660e\uff0c\u5305\u62ec\u5728\u9875\u9762\u5904\u7406\u7a0b\u5e8f\u548c\u89c6\u56fe\u6a21\u677f\u4e2d\u3002\u4f8b\u5982\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u8bed\u53e5\u5728 Razor \u6a21\u677f\u4e2d\u7684\u4efb\u610f\u4f4d\u7f6e\u663e\u793a\u7528\u6237\u7684 FullName \u58f0\u660e\uff1a<\/p>\n<pre><code>@User.Claims.FirstOrDefault(x=&gt;x.Type == &quot;FullName&quot;)?.Value<\/code><\/pre>\n<p>This finds the first claim on the current user principal with a Type of &quot;FullName&quot; and prints the assigned value (or, if the claim is not found, prints nothing). The Identity system even includes a handy extension method that tidies up this LINQ expression (found in the System.Security.Claims namespace):<br \/>\n\u8fd9\u5c06\u5728\u5f53\u524d\u7528\u6237\u4e3b\u4f53\u4e0a\u67e5\u627e Type \u4e3a \u201cFullName\u201d \u7684\u7b2c\u4e00\u4e2a\u58f0\u660e\uff0c\u5e76\u6253\u5370\u5206\u914d\u7684\u503c\uff08\u6216\u8005\uff0c\u5982\u679c\u672a\u627e\u5230\u58f0\u660e\uff0c\u5219\u4e0d\u6253\u5370\u4efb\u4f55\u5185\u5bb9\uff09\u3002Identity \u7cfb\u7edf\u751a\u81f3\u5305\u62ec\u4e00\u4e2a\u65b9\u4fbf\u7684\u6269\u5c55\u65b9\u6cd5\uff0c\u7528\u4e8e\u6574\u7406\u6b64 LINQ \u8868\u8fbe\u5f0f\uff08\u4f4d\u4e8e System.Security.Claims \u547d\u540d\u7a7a\u95f4\u4e2d\uff09\uff1a<\/p>\n<pre><code>@User.FindFirstValue(&quot;FullName&quot;)<\/code><\/pre>\n<p>With that last tidbit, we\u2019ve reached the end of this chapter on ASP.NET Core Identity. I hope you\u2019ve come to appreciate the amount of effort using Identity can save you, especially when you make use of the default Identity UI package.<br \/>\n\u8bf4\u5230\u6700\u540e\u7684\u82b1\u7d6e\uff0c\u6211\u4eec\u5173\u4e8e ASP.NET Core Identity \u7684\u672c\u7ae0\u5df2\u7ecf\u7ed3\u675f\u4e86\u3002\u6211\u5e0c\u671b\u60a8\u5df2\u7ecf\u610f\u8bc6\u5230\u4f7f\u7528 Identity \u53ef\u4ee5\u8282\u7701\u5927\u91cf\u7cbe\u529b\uff0c\u5c24\u5176\u662f\u5728\u4f7f\u7528\u9ed8\u8ba4\u7684 Identity UI \u5305\u65f6\u3002<\/p>\n<p>Adding user accounts and authentication to an app is typically the first step in customizing your app further. Once you have authentication, you can have authorization, which lets you lock down certain actions in your app, based on the current user. In the next chapter you\u2019ll learn about the ASP.NET Core authorization system and how you can use it to customize your apps; in particular, the recipe application, which is coming along nicely!<br \/>\n\u5411\u5e94\u7528\u7a0b\u5e8f\u6dfb\u52a0\u7528\u6237\u5e10\u6237\u548c\u8eab\u4efd\u9a8c\u8bc1\u901a\u5e38\u662f\u8fdb\u4e00\u6b65\u81ea\u5b9a\u4e49\u5e94\u7528\u7a0b\u5e8f\u7684\u7b2c\u4e00\u6b65\u3002\u83b7\u5f97\u8eab\u4efd\u9a8c\u8bc1\u540e\uff0c\u60a8\u53ef\u4ee5\u83b7\u5f97\u6388\u6743\uff0c\u4ece\u800c\u5141\u8bb8\u60a8\u6839\u636e\u5f53\u524d\u7528\u6237\u9501\u5b9a\u5e94\u7528\u7a0b\u5e8f\u4e2d\u7684\u67d0\u4e9b\u4f5c\u3002\u5728\u4e0b\u4e00\u7ae0\u4e2d\uff0c\u60a8\u5c06\u4e86\u89e3 ASP.NET Core \u6388\u6743\u7cfb\u7edf\u4ee5\u53ca\u5982\u4f55\u4f7f\u7528\u5b83\u6765\u81ea\u5b9a\u4e49\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f;\u7279\u522b\u662f recipe \u5e94\u7528\u7a0b\u5e8f\uff0c\u5b83\u8fdb\u5c55\u987a\u5229\uff01<\/p>\n<h2>23.7 Summary<\/h2>\n<p>23.7 \u603b\u7ed3<\/p>\n<p>Authentication is the process of determining who you are, and authorization is the process of determining what you\u2019re allowed to do. You need to authenticate users before you can apply authorization.<br \/>\n\u8eab\u4efd\u9a8c\u8bc1\u662f\u786e\u5b9a\u60a8\u662f\u8c01\u7684\u8fc7\u7a0b\uff0c\u6388\u6743\u662f\u786e\u5b9a\u5141\u8bb8\u60a8\u6267\u884c\u54ea\u4e9b\u4f5c\u7684\u8fc7\u7a0b\u3002\u60a8\u9700\u8981\u5148\u5bf9\u7528\u6237\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u7136\u540e\u624d\u80fd\u5e94\u7528\u6388\u6743\u3002<\/p>\n<p>Every request in ASP.NET Core is associated with a user, also known as a principal. By default, without authentication, this is an anonymous user. You can use the claims principal to behave differently depending on who made a request.<br \/>\nASP.NET Core \u4e2d\u7684\u6bcf\u4e2a\u8bf7\u6c42\u90fd\u4e0e\u4e00\u4e2a\u7528\u6237\uff08\u4e5f\u79f0\u4e3a\u59d4\u6258\u4eba\uff09\u76f8\u5173\u8054\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5982\u679c\u4e0d\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\uff0c\u5219\u6b64\u7528\u6237\u4e3a\u533f\u540d\u7528\u6237\u3002\u60a8\u53ef\u4ee5\u4f7f\u7528 claims principal \u6839\u636e\u53d1\u51fa\u8bf7\u6c42\u7684\u4eba\u5458\u6765\u6267\u884c\u4e0d\u540c\u7684\u884c\u4e3a\u3002<\/p>\n<p>The current principal for a request is exposed on HttpContext.User. You can access this value from your Razor Pages and views to find out properties of the user such as their, ID, name, or email.<br \/>\n\u8bf7\u6c42\u7684\u5f53\u524d\u4e3b\u4f53\u5728 HttpContext.User \u4e0a\u516c\u5f00\u3002\u53ef\u4ee5\u4ece Razor \u9875\u9762\u548c\u89c6\u56fe\u8bbf\u95ee\u6b64\u503c\uff0c\u4ee5\u67e5\u627e\u7528\u6237\u7684\u5c5e\u6027\uff0c\u4f8b\u5982\u4ed6\u4eec\u7684 ID\u3001\u540d\u79f0\u6216\u7535\u5b50\u90ae\u4ef6\u3002<\/p>\n<p>Every user has a collection of claims. These claims are single pieces of information about the user. Claims could be properties of the physical user, such as Name and Email, or they could be related to things the user has, such as HasAdminAccess or IsVipCustomer.<br \/>\n\u6bcf\u4e2a\u7528\u6237\u90fd\u6709\u4e00\u4e2a\u58f0\u660e\u96c6\u5408\u3002\u8fd9\u4e9b\u58f0\u660e\u662f\u6709\u5173\u7528\u6237\u7684\u5355\u4e2a\u4fe1\u606f\u3002\u58f0\u660e\u53ef\u4ee5\u662f\u7269\u7406\u7528\u6237\u7684\u5c5e\u6027\uff0c\u4f8b\u5982 Name \u548c Email\uff0c\u4e5f\u53ef\u4ee5\u4e0e\u7528\u6237\u62e5\u6709\u7684\u5185\u5bb9\u76f8\u5173\uff0c\u4f8b\u5982 HasAdminAccess \u6216 IsVipCustomer\u3002<\/p>\n<p>Legacy versions of ASP.NET used roles instead of claims. You can still use roles if you need to, but you should typically use claims where possible.<br \/>\n\u65e7\u7248\u672c\u7684 ASP.NET \u4f7f\u7528\u89d2\u8272\u800c\u4e0d\u662f\u58f0\u660e\u3002\u5982\u679c\u9700\u8981\uff0c\u60a8\u4ecd\u7136\u53ef\u4ee5\u4f7f\u7528\u89d2\u8272\uff0c\u4f46\u901a\u5e38\u5e94\u5c3d\u53ef\u80fd\u4f7f\u7528\u58f0\u660e\u3002<\/p>\n<p>Authentication in ASP.NET Core is provided by AuthenticationMiddleware and a number of authentication services. These services are responsible for setting the current principal when a user logs in, saving it to a cookie, and loading the principal from the cookie on subsequent requests.<br \/>\nASP.NET Core \u4e2d\u7684\u8eab\u4efd\u9a8c\u8bc1\u7531 AuthenticationMiddleware \u548c\u8bb8\u591a\u8eab\u4efd\u9a8c\u8bc1\u670d\u52a1\u63d0\u4f9b\u3002\u8fd9\u4e9b\u670d\u52a1\u8d1f\u8d23\u5728\u7528\u6237\u767b\u5f55\u65f6\u8bbe\u7f6e\u5f53\u524d\u4e3b\u4f53\uff0c\u5c06\u5176\u4fdd\u5b58\u5230 Cookie\uff0c\u5e76\u5728\u540e\u7eed\u8bf7\u6c42\u4e2d\u4ece Cookie \u52a0\u8f7d\u4e3b\u4f53\u3002<\/p>\n<p>The AuthenticationMiddleware is added automatically by WebApplication. You can ensure that it\u2019s inserted at a specific point in the middleware pipeline by calling UseAuthentication(). It must be placed before any middleware that requires authentication, such as UseAuthorization().<br \/>\nAuthenticationMiddleware \u7531 WebApplication \u81ea\u52a8\u6dfb\u52a0\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528 UseAuthentication\uff08\uff09 \u6765\u786e\u4fdd\u5b83\u63d2\u5165\u5230\u4e2d\u95f4\u4ef6\u7ba1\u9053\u4e2d\u7684\u7279\u5b9a\u70b9\u3002\u5b83\u5fc5\u987b\u653e\u5728\u4efb\u4f55\u9700\u8981\u8eab\u4efd\u9a8c\u8bc1\u7684\u4e2d\u95f4\u4ef6\u4e4b\u524d\uff0c\u4f8b\u5982 UseAuthorization\uff08\uff09\u3002<\/p>\n<p>ASP.NET Core Identity handles low-level services needed for storing users in a database, ensuring that their passwords are stored safely, and for logging users in and out. You must provide the UI for the functionality yourself and wire it up to the Identity subsystem.<br \/>\nASP.NET Core Identity \u5904\u7406\u5c06\u7528\u6237\u5b58\u50a8\u5728\u6570\u636e\u5e93\u4e2d\u3001\u786e\u4fdd\u5176\u5bc6\u7801\u5b89\u5168\u5b58\u50a8\u4ee5\u53ca\u767b\u5f55\u548c\u6ce8\u9500\u7528\u6237\u6240\u9700\u7684\u4f4e\u7ea7\u670d\u52a1\u3002\u60a8\u5fc5\u987b\u81ea\u5df1\u63d0\u4f9b\u8be5\u529f\u80fd\u7684 UI\uff0c\u5e76\u5c06\u5176\u8fde\u63a5\u5230 Identity \u5b50\u7cfb\u7edf\u3002<\/p>\n<p>The Microsoft.AspNetCore.Identity.UI package provides a default UI for the Identity system and includes email confirmation, MFA, and external login provider support. You need to do some additional configuration to enable these features.<br \/>\nMicrosoft.AspNetCore.Identity.UI \u5305\u4e3a\u6807\u8bc6\u7cfb\u7edf\u63d0\u4f9b\u9ed8\u8ba4 UI\uff0c\u5e76\u5305\u62ec\u7535\u5b50\u90ae\u4ef6\u786e\u8ba4\u3001MFA \u548c\u5916\u90e8\u767b\u5f55\u63d0\u4f9b\u7a0b\u5e8f\u652f\u6301\u3002\u60a8\u9700\u8981\u8fdb\u884c\u4e00\u4e9b\u989d\u5916\u7684\u914d\u7f6e\u624d\u80fd\u542f\u7528\u8fd9\u4e9b\u529f\u80fd\u3002<\/p>\n<p>The default template for Web Application with Individual Account Authentication uses ASP.NET Core Identity to store users in the database with EF Core. It includes all the boilerplate code required to wire the UI up to the Identity system.<br \/>\n\u5177\u6709\u4e2a\u4eba\u5e10\u6237\u8eab\u4efd\u9a8c\u8bc1\u7684 Web \u5e94\u7528\u7a0b\u5e8f\u7684\u9ed8\u8ba4\u6a21\u677f\u4f7f\u7528 ASP.NET Core Identity \u5c06\u7528\u6237\u5b58\u50a8\u5728\u5177\u6709 EF Core \u7684\u6570\u636e\u5e93\u4e2d\u3002\u5b83\u5305\u62ec\u5c06 UI \u8fde\u63a5\u5230\u6807\u8bc6\u7cfb\u7edf\u6240\u9700\u7684\u6240\u6709\u6837\u677f\u4ee3\u7801\u3002<\/p>\n<p>You can use the <code>UserManager&lt;T&gt;<\/code> class to create new user accounts, load them from the database, and change their passwords. SignInManager<T> is used to sign a user in and out by assigning the principal for the request and by setting an authentication cookie. The default UI uses these classes for you, to facilitate user registration and login.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528<code>UserManager&lt;T&gt;<\/code>\u8be5\u7c7b\u521b\u5efa\u65b0\u7684\u7528\u6237\u5e10\u6237\uff0c\u4ece\u6570\u636e\u5e93\u4e2d\u52a0\u8f7d\u5b83\u4eec\uff0c\u5e76\u66f4\u6539\u5176\u5bc6\u7801\u3002SignInManager \u7528\u4e8e\u901a\u8fc7\u4e3a\u8bf7\u6c42\u5206\u914d\u4e3b\u4f53\u548c\u8bbe\u7f6e\u8eab\u4efd\u9a8c\u8bc1 cookie \u6765\u767b\u5f55\u548c\u6ce8\u9500\u7528\u6237\u3002\u9ed8\u8ba4 UI \u4f1a\u4e3a\u60a8\u4f7f\u7528\u8fd9\u4e9b\u7c7b\uff0c\u4ee5\u65b9\u4fbf\u7528\u6237\u6ce8\u518c\u548c\u767b\u5f55\u3002<\/p>\n<p>You can update an EF Core DbContext to support Identity by deriving from IdentityDbContext<TUser>, where TUser is a class that derives from IdentityUser.<br \/>\n\u60a8\u53ef\u4ee5\u901a\u8fc7\u4ece IdentityDbContext \u6d3e\u751f\u6765\u66f4\u65b0 EF Core DbContext \u4ee5\u652f\u6301 Identity\uff0c\u5176\u4e2d TUser \u662f\u4ece IdentityUser \u6d3e\u751f\u7684\u7c7b\u3002<\/p>\n<p>You can add additional claims to a user using the UserManager<TUser>.AddClaimAsync(TUser user, Claim claim) method. These claims are added to the HttpContext.User object when the user logs in to your app.<br \/>\n\u60a8\u53ef\u4ee5\u4f7f\u7528 UserManager \u5411\u7528\u6237\u6dfb\u52a0\u5176\u4ed6\u58f0\u660e\u3002AddClaimAsync\uff08TUser user\uff0c Claim claim\uff09 \u65b9\u6cd5\u3002\u5f53\u7528\u6237\u767b\u5f55\u5230\u60a8\u7684\u5e94\u7528\u65f6\uff0c\u8fd9\u4e9b\u58f0\u660e\u5c06\u6dfb\u52a0\u5230 HttpContext.User \u5bf9\u8c61\u4e2d\u3002<\/p>\n<p>Claims consist of a type and a value. Both values are strings. You can use standard values for types exposed on the ClaimTypes class, such as ClaimTypes.GivenName and ClaimTypes.FirstName, or you can use a custom string, such as &quot;FullName&quot;.<br \/>\n\u58f0\u660e\u7531\u7c7b\u578b\u548c\u503c\u7ec4\u6210\u3002\u8fd9\u4e24\u4e2a\u503c\u90fd\u662f\u5b57\u7b26\u4e32\u3002\u60a8\u53ef\u4ee5\u5bf9 ClaimTypes \u7c7b\u4e0a\u516c\u5f00\u7684\u7c7b\u578b\u4f7f\u7528\u6807\u51c6\u503c\uff0c\u4f8b\u5982 ClaimTypes.GivenName \u548c ClaimTypes.FirstName\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u81ea\u5b9a\u4e49\u5b57\u7b26\u4e32\uff0c\u4f8b\u5982\u201cFullName\u201d\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Part 4 Securing and deploying your applications \u7b2c 4 \u90e8\u5206\uff1a\u4fdd\u62a4\u548c\u90e8\u7f72\u5e94\u7528\u7a0b\u5e8f So far in the book you\u2019ve learned how to use minimal APIs,Razor Pages, and Model-View-Controller (MVC) controllers to build both server-rendered applications and APIs. You know how to dynamically generate JavaScript Object Notation (JSON) and HTML code based on incoming requests, and how to use [&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-617","post","type-post","status-publish","format-standard","hentry","category-csharp"],"_links":{"self":[{"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/617","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=617"}],"version-history":[{"count":0,"href":"https:\/\/diji.net\/index.php?rest_route=\/wp\/v2\/posts\/617\/revisions"}],"wp:attachment":[{"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=617"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=617"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diji.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=617"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}