网站建设论文范文,wordpress弹窗代码,上海 企业网站制,用mcu做灯光效果网站原文地址 Identity Server 4是IdentityServer的最新版本#xff0c;它是流行的OpenID Connect和OAuth Framework for .NET#xff0c;为ASP.NET Core和.NET Core进行了更新和重新设计。在本文中#xff0c;我们将快速了解IdentityServer 4存在的原因#xff0c;然后直接进入…原文地址 Identity Server 4是IdentityServer的最新版本它是流行的OpenID Connect和OAuth Framework for .NET为ASP.NET Core和.NET Core进行了更新和重新设计。在本文中我们将快速了解IdentityServer 4存在的原因然后直接进入并创建一个从零到英雄的工作实现。 IdentityServer 3与IdentityServer 4 目前流行的一句话是“概念上兼容”但这对于Identity Server 4来说是正确的。概念是相同的它仍然是按照规范构建的OpenID Connect提供程序但是它的大部分内部和可扩展性点已经改变。当我们将客户端应用程序与IdentityServer集成时我们没有集成到实现中。相反我们使用OpenID Connect或OAuth规范进行集成。这意味着当前与IdentityServer 3一起使用的任何应用程序都将与IdentityServer 4一起使用。 Identity Server被设计为作为自托管组件运行使用ASP.NET 4.x很难实现而MVC仍然与IIS和System.Web紧密耦合从而导致katana提供内部视图引擎零件。借助在ASP.NET Core上运行的Identity Server 4我们现在可以在ASP.NET Core可以运行的任何环境中使用任何UI技术和主机IdentityServer。这也意味着我们现在可以与现有的登录表单/系统集成从而实现升级。 IUserService用于集成用户存储 的Identity Server 现在也已消失取而代之的是以IProfileService和形式的新用户存储抽象IResourceOwnerPasswordValidator。 IdentityServer 3不会去任何地方就像.NET Framework不会去任何地方一样。就像微软已将大多数活动开发转移到.NET Core参见Katana和ASP.NET Identity一样我想IdentityServer最终会做同样的事情但我们在这里讨论的是OSS而项目保持这种状态它始终是开放的PRs修复错误和相关的新功能。我不会很快放弃它商业支持将继续下去。 在写作的初始阶段IdentityServer 4在RC5中IdentityServer 3在v2.5.3上计划在未来使用另一个主要版本v3.0.0。此文章已更新为IdentityServer 4 v2.0。 IdentityServer4以.NET标准2.0为目标这意味着它可以针对.NET核心或.NET框架尽管本文仅针对.NET Core。IdentityServer 4现在支持.NET Core 2.0由于两个版本之间的重大变化而留下.NET Core 1.x。 您可以在Dominick Baier的IdentityServer 4公告文章中阅读有关IdentityServer 4背后原因的更多信息。 从.NET Core 2.0开始还有一些重大变化。对于ASP.NET Core 1.x支持请查看主存储库中的aspnetcore1分支。 在ASP.NET Core和.NET Core上实现IdentityServer4 对于我们的初始实现我们将使用为演示和轻量级实现保留的内存服务。在本文的后面我们将切换到实体框架以更真实地表示IdentityServer的生产实例。 在开始本教程之前请确保您使用的是最新版本的ASP.NET Core和.NET Core工具。在创建本教程时我使用了.NET Core 2.0和Visual Studio 2017。 首先我们需要一个使用.NET Core的新ASP.NET Core项目在VS中参见ASP.NET Core Web Application。您将需要使用没有身份验证的Empty模板。确保您的项目设置为.NET Core和ASP.NET Core 2.0。 在开始编码之前将项目URL切换为HTTPS。在没有TLS的情况下您不应该运行身份验证服务。假设您使用的是IIS Express则可以通过打开项目属性进入“调试”选项卡并单击“启用SSL”来执行此操作。虽然我们在这里但您应该将生成的HTTPS URL作为App URL这样当我们运行项目时我们就会从正确的页面开始。 如果在为localhost使用IIS Express开发证书时遇到证书信任问题请尝试按照本文中的步骤操作。如果您发现此方法存在问题请随意切换到自托管模式而不是IIS Express使用项目的命名空间运行。 首先我们需要安装以下nuget包目前为2.0.2编写的文章 IdentityServer4 现在到我们的Startup类开始注册依赖项和连接服务。 在您的ConfigureServices方法中添加以下内容以注册所需的最低依赖项 services.AddIdentityServer() .AddInMemoryClients(new ListClient()) .AddInMemoryIdentityResources(new ListIdentityResource()) .AddInMemoryApiResources(new ListApiResource()) .AddTestUsers(new ListTestUser()) .AddDeveloperSigningCredential(); 然后在您的Configure方法中添加以下内容以将IdentityServer中间件添加到HTTP管道 app.UseIdentityServer(); 我们在这里做的是在我们的DI容器中注册IdentityServer AddIdentityServer使用演示签名证书AddDeveloperSigningCredential并为我们的客户资源和用户使用内存存储。通过使用AddIdentityServer我们还将所有生成的令牌/授权存储在内存中。我们将很快添加实际的客户资源和用户。 UseIdentityServer 允许IdentityServer开始拦截路由并处理请求。 我们实际上可以运行IdentityServer它可能没有UI不支持任何范围并且没有用户但您已经可以开始使用它了查看OpenID Connect Discovery文档/.well-known/openid-configuration。 OpenID Connect Discovery文档 OpenID Connect Discovery文档被亲切地称为disco doc可在此着名端点的每个OpenID Connect提供程序上使用根据规范。本文档包含各种端点的位置例如令牌端点和结束会话端点提供程序支持的授权类型可提供的范围等信息。通过这个标准化文档我们开辟了自动集成的可能性。 您可以在OpenID Connect Discovery 1.0规范中阅读有关OpenID Connect Discovery文档的更多信息。 签署证书 签名证书是用于签署令牌的专用证书允许客户端应用程序验证令牌的内容在传输过程中未被更改。这涉及用于签署令牌的私钥和用于验证签名的公钥。客户端应用程序可以通过jwks_uriOpenID Connect发现文档访问此公钥。 当您创建并使用自己的签名证书时请随意使用自签名证书。此证书不需要由受信任的证书颁发机构颁发。 现在我们启动并运行IdentityServer让我们添加一些数据。 客户资源和用户 首先我们需要存储允许使用IdentityServer的客户端应用程序以及这些客户端可以使用的资源以及允许对其进行身份验证的用户。 我们目前正在使用InMemory商店这些商店接受他们各自实体的集合我们现在可以使用一些静态方法填充它们。 客户端 IdentityServer需要知道允许哪些客户端应用程序使用它。我想将此视为白名单即您的访问控制列表。然后将每个客户端应用程序配置为仅允许执行某些操作例如他们只能请求将令牌返回到某些URL或者他们只能请求某些信息。他们有访问范围。 internal class Clients { public static IEnumerableClient Get() { return new ListClient { new Client { ClientId oauthClient, ClientName Example Client Credentials Client Application, AllowedGrantTypes GrantTypes.ClientCredentials, ClientSecrets new ListSecret { new Secret(superSecretPassword.Sha256())}, AllowedScopes new Liststring {customAPI.read} } }; } } 这里我们添加一个使用Client Credentials OAuth授权类型的客户端。此授权类型需要客户端ID和客户端密钥来授权访问使用Identity Server提供的扩展方法简单地对密码进行哈希处理毕竟我们从不在纯文本中存储任何密码这总比没有好。允许的范围是允许此客户端请求的范围列表。这里我们的范围是customAPI.read我们现在将以API资源的形式初始化它。 资源和范围 范围代表您可以做的事情。它们代表我之前提到的范围访问。在IdentityServer 4中作用域被建模为资源它有两种形式Identity和API。标识资源允许您为将返回特定声明集的作用域建模而API资源作用域允许您建模对受保护资源通常是API的访问。 internal class Resources { public static IEnumerableIdentityResource GetIdentityResources() { return new ListIdentityResource { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Email(), new IdentityResource { Name role, UserClaims new Liststring {role} } }; } public static IEnumerableApiResource GetApiResources() { return new ListApiResource { new ApiResource { Name customAPI, DisplayName Custom API, Description Custom API Access, UserClaims new Liststring {role}, ApiSecrets new ListSecret {new Secret(scopeSecret.Sha256())}, Scopes new ListScope { new Scope(customAPI.read), new Scope(customAPI.write) } } }; } } IdentityResources 前三个身份资源代表我们希望IdentityServer支持的一些标准OpenID Connect定义的范围。例如email范围允许返回email和email_verified声明。我们还创建了一个自定义标识资源其形式为经过身份验证的用户role返回role声明。 快速提示openid使用OpenID Connect流时始终需要范围。您可以在OpenID Connect规范中找到有关这些的更多信息。 ApiResources 对于api资源我们正在建模一个我们希望保护的API customApi。此API有两个可以请求的范围customAPI.read和customAPI.write。 通过在这样的范围内设置声明我们确保将这些声明类型添加到具有此范围的任何标记中当然如果用户具有该类型的值。在这种情况下我们确保将用户角色声明添加到具有此范围的任何令牌。稍后将在令牌自省期间使用范围秘密。 范围与资源 OpenID Connect和OAuth作用域现在被建模为资源是IdentityServer 3和IdentityServer 4之间最大的概念上的变化。 offline_access现在默认情况下支持用于请求刷新令牌 的作用域并授权使用由该Client属性控制的此作用域AllowOfflineAccess。 用户 在完全成熟的用户存储如ASP.NET Identity的位置我们可以使用TestUsers internal class Users { public static ListTestUser Get() { return new ListTestUser { new TestUser { SubjectId 5BE86359-073C-434B-AD2D-A3932222DABE, Username scott, Password password, Claims new ListClaim { new Claim(JwtClaimTypes.Email, scottscottbrady91.com), new Claim(JwtClaimTypes.Role, admin) } } }; } } 用户主题或子声明是其唯一标识符。这应该是您的身份提供商独有的东西而不是电子邮件地址。我指出这是由于最近Azure AD的漏洞。 我们现在需要使用此信息更新我们的DI容器而不是以前的空集合 services.AddIdentityServer() .AddInMemoryClients(Clients.Get()) .AddInMemoryIdentityResources(Resources.GetIdentityResources()) .AddInMemoryApiResources(Resources.GetApiResources()) .AddTestUsers(Users.Get()) .AddDeveloperSigningCredential(); 如果您再次运行此命令并再次访问发现文档您现在将看到填充的部分scopes_supported和claims_supported部分。 OAuth功能 为了测试我们的实现我们可以使用之前的OAuth客户端从Identity Server获取访问令牌。这将使用Client Credentials流程因此我们的请求将如下所示 POST /connect/token
Headers:
Content-Type: application/x-www-form-urlencoded
Body:
grant_typeclient_credentialsscopecustomAPI.readclient_idoauthClientclient_secretsuperSecretPassword 这会将我们的访问令牌作为JWT返回 access_token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjE0M2U4MjljMmI1NzQ4OTk2OTc1M2JhNGY4MjA1OTc5ZGYwZGE5ODhjNjQwY2ZmYTVmMWY0ZWRhMWI2ZTZhYTQiLCJ0eXAiOiJKV1QifQ.eyJuYmYiOjE0ODE0NTE5MDMsImV4cCI6MTQ4MTQ1NTUwMywiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNTAiLCJhdWQiOlsiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNTAvcmVzb3VyY2VzIiwiY3VzdG9tQVBJIl0sImNsaWVudF9pZCI6Im9hdXRoQ2xpZW50Iiwic2NvcGUiOlsiY3VzdG9tQVBJLnJlYWQiXX0.D50LeW9265IH695FlykBiWVkKDj-Gjiv-8q-YJl9qV3_jLkTFVeHUaCDuPfe1vd_XVxmx_CwIwmIGPXftKtEcjMiA5WvFB1ToafQ1AqUzRyDgugekWh-i8ODyZRped4SxrlI8OEMcbtTJNzhfDpyeYBiQh7HeQ6URn4eeHq3ePqbJSTPrqsYyG9YpU6azO7XJlNeq_Ml1KZms1lxrkXcETfo7U1h-z66TxpvH4qQRrRcNOY_kejq1x_GD3peWcoKPJ_f4Rbc4B-UvqicslKM44dLNoMDVw_gjKHRCUaaevFlzyS59pwv0UHFAuy4_wyp1uX7ciQOjUPyhl63ZEOX1w,
expires_in: 3600, token_type: Bearer 如果我们将此访问令牌转到jwt.io我们可以看到它包含以下声明 alg: RS256,
kid: 143e829c2b57489969753ba4f8205979df0da988c640cffa5f1f4eda1b6e6aa4, typ: JWT nbf: 1481451903, exp: 1481455503, iss: https://localhost:44350, aud: [ https://localhost:44350/resources, customAPI ], client_id: oauthClient, scope: [ customAPI.read ] 我们现在可以使用IdentityServer的令牌内省端点来验证令牌就好像我们是从外部方接收它的OAuth资源一样。如果成功我们将收到该标记中的声明回复给我们。请注意IdentityServer 4中的访问令牌验证端点在IdentityServer 4中不再可用。 在这里我们之前创建的范围秘密通过使用基本身份验证来使用其中用户名是范围Id密码是范围秘密。 POST /connect/introspect
Headers:
Authorization: Basic Y3VzdG9tQVBJOnNjb3BlU2VjcmV0
Content-Type: application/x-www-form-urlencoded
Body:
tokeneyJhbGciOiJSUzI1NiIsImtpZCI6IjE0M2U4MjljMmI1NzQ4OTk2OTc1M2JhNGY4MjA1OTc5ZGYwZGE5ODhjNjQwY2ZmYTVmMWY0ZWRhMWI2ZTZhYTQiLCJ0eXAiOiJKV1QifQ.eyJuYmYiOjE0ODE0NTE5MDMsImV4cCI6MTQ4MTQ1NTUwMywiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNTAiLCJhdWQiOlsiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzNTAvcmVzb3VyY2VzIiwiY3VzdG9tQVBJIl0sImNsaWVudF9pZCI6Im9hdXRoQ2xpZW50Iiwic2NvcGUiOlsiY3VzdG9tQVBJLnJlYWQiXX0.D50LeW9265IH695FlykBiWVkKDj-Gjiv-8q-YJl9qV3_jLkTFVeHUaCDuPfe1vd_XVxmx_CwIwmIGPXftKtEcjMiA5WvFB1ToafQ1AqUzRyDgugekWh-i8ODyZRped4SxrlI8OEMcbtTJNzhfDpyeYBiQh7HeQ6URn4eeHq3ePqbJSTPrqsYyG9YpU6azO7XJlNeq_Ml1KZms1lxrkXcETfo7U1h-z66TxpvH4qQRrRcNOY_kejq1x_GD3peWcoKPJ_f4Rbc4B-UvqicslKM44dLNoMDVw_gjKHRCUaaevFlzyS59pwv0UHFAuy4_wyp1uX7ciQOjUPyhl63ZEOX1w 响应 nbf: 1481451903,
exp: 1481455503, iss: https://localhost:44350, aud: [ https://localhost:44350/resources, customAPI ], client_id: oauthClient, scope: [ customAPI.read ], active: true 如果您希望以编程方式执行此过程并以此方式授权访问.NET Core资源请查看IdentityServer4.AcessTokenValidation库。 资源所有者密码凭据ROPC授予类型 IdentityServer文档还提供了有关如何使用资源所有者授权类型的指南。不要被这种授权类型包含用户名和密码的事实所迷惑它仍然只是授权而不是身份验证。实际上文章和原始OAuth 2.0规范中有多个免责声明声明此授权类型应仅用于旧版应用程序。请参阅我的文章为什么资源所有者密码凭据授予类型不是身份验证也不适合现代应用程序以调查资源所有者授予类型的所有错误。 用户界面 到目前为止我们一直在没有UI工作让我们通过从使用ASP.NET Core MVC的GitHub引入Quickstart UI来改变这一点。 要下载此文件请将repo中的所有文件夹复制到项目中或使用以下powershell命令同样在项目文件夹中 iex ((New-Object System.Net.WebClient).DownloadString(https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1)) 现在我们需要将ASP.NET MVC Core添加到我们的项目中。为此首先将以下包添加到项目中如果已安装则可以跳过此安装Microsoft.AspNetCore.All Microsoft.AspNetCore.Mvc
Microsoft.AspNetCore.StaticFiles 然后添加到您的服务ConfigureServices services.AddMvc(); 最后添加到HTTP管道的末尾Configure app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); 现在当我们运行项目时我们会看到一个闪屏。万岁现在我们有了UI现在我们可以开始验证用户了。 IdentityServer 4快速入门UI启动画面 OpenID Connect 要使用OpenID Connect演示身份验证我们需要创建一个客户端Web应用程序并在IdentityServer中添加相应的客户端。 首先我们需要在IdentityServer中添加一个新客户端 new Client {ClientId openIdConnectClient, ClientName Example Implicit Client Application, AllowedGrantTypes GrantTypes.Implicit, AllowedScopes new Liststring { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Email, role, customAPI.write }, RedirectUris new Liststring {https://localhost:44330/signin-oidc}, PostLogoutRedirectUris new Liststring {https://localhost:44330} } 重定向和后注销重定向uris的位置是我们即将推出的应用程序的URL。重定向uri需要路径/signin-oidc这条路径将由即将推出的中间件自动创建和处理。 这里我们使用OpenID Connect隐式授权类型。此授权类型允许我们通过浏览器请求身份和访问令牌。我会称之为最简单的授权类型但也是最不安全的。 客户申请 现在我们需要创建客户端应用程序。为此我们需要另一个ASP.NET Core网站这次使用Web应用程序MVCVS模板但没有认证。 要将OpenID Connect身份验证添加到ASP.NET Core站点我们需要将以下两个包添加到我们的站点同样如果您使用可以跳过安装Microsoft.AspNetCore.All Microsoft.AspNetCore.Authentication.Cookies
Microsoft.AspNetCore.Authentication.OpenIdConnect 然后在我们的DIConfigureServices中 services.AddAuthentication(options { options.DefaultScheme cookie; }) .AddCookie(cookie); 在这里我们告诉我们的应用程序使用cookie身份验证登录用户并将其用作默认的身份验证方法。虽然我们可能正在使用IdentityServer对用户进行身份验证但每个客户端应用程序仍需要发布自己的cookie到其自己的域。 现在我们需要添加OpenID Connect身份验证 services.AddAuthentication(options { options.DefaultScheme cookie; options.DefaultChallengeScheme oidc; }) .AddCookie(cookie) .AddOpenIdConnect(oidc, options { options.Authority https://localhost:44350/; options.ClientId openIdConnectClient; options.SignInScheme cookie; }); 在这里我们告诉我们的应用程序使用我们的OpenID Connect ProviderIdentityServer我们希望登录的客户端ID以及成功验证时登录的身份验证类型我们之前定义的cookie中间件。 默认情况下ID连接中间件选项将使用/signin-oidc其重定向URI请求范围openid和profile并用implicit流动只要求身份令牌。 接下来我们需要在我们的管道Configure之前添加身份验证UseMvc app.UseAuthentication(); 现在剩下的就是让页面需要身份验证才能访问。让我们将“添加”属性添加到“联系人”操作因为联系我们的人是我们想要的最后一件事。 [Authorize]
public IActionResult Contact() { ... } 现在当我们运行此应用程序并选择“联系”页面时我们将收到未经授权的401。这反过来将被我们的OpenID Connect中间件拦截该中间件将302重定向到我们的Identity Server身份验证端点以及必要的参数。 IdentityServer 4快速入门UI登录屏幕 成功登录后IdentityServer将要求我们同意客户端应用程序代表您访问某些信息或资源这些信息或资源对应于客户端请求的身份和资源范围。可以在客户端基于客户端禁用此同意请求。默认情况下ASP.NET Core的OpenID Connect中间件将请求openid和配置文件范围。 IdentityServer 4快速入门UI同意屏幕 这就是使用隐式授权类型连接简单OpenID Connect Client所需的全部内容。 Entity Framework Core 目前我们在内存存储中使用正如我们之前提到的那样它是用于演示目的或者最多是非常轻量级的实现。理想情况下我们希望将各种商店移动到一个持久性数据库中该数据库在每次部署时都不会被删除或者需要更改代码才能添加新条目。 IdentityServer有一个Entity FrameworkEFCore包我们可以使用它来使用任何EF Core关系数据库提供程序实现客户端范围和持久授权存储。 Identity Server Entity Framework Core软件包已使用In-MemorySQLite内存中和SQL Server数据库提供程序进行了集成测试。如果您发现其他提供商存在任何问题或希望针对其他数据库提供商编写测试请随时在GitHub问题跟踪器上打开问题或提交拉取请求。 对于本文我们将使用SQL服务器SQL Express或本地数据库会这样做因此我们需要以下nuget包 IdentityServer4.EntityFramework
Microsoft.EntityFrameworkCore.SqlServer 持久的赠款商店 持久授权存储包含有关给定同意的所有信息因此我们不会一直要求对每个请求的同意引用令牌存储的jwt其中只有与jwt相对应的密钥被提供给请求者使其易于撤销以及更多。如果没有持久性存储则在每次重新部署IdentityServer时令牌都将失效并且我们无法一次承载多个安装无负载平衡。 首先让新的几个变量 const string connectionString Data Source(LocalDb)\MSSQLLocalDB;databaseTest.IdentityServer4.EntityFramework;trusted_connectionyes;; var migrationsAssembly typeof(Startup).GetTypeInfo().Assembly.GetName().Name; 然后我们可以通过添加到AddIdentityServer以下内容来添加对持久授权存储的支持 AddOperationalStore(options options.ConfigureDbContext builder builder.UseSqlServer(connectionString, sqlOptions sqlOptions.MigrationsAssembly(migrationsAssembly))) 我们的迁移程序集是我们托管IdentityServer的项目。这对于不在您的托管项目中的DbContexts在这种情况下它位于nuget包中是必要的并允许我们运行EF迁移。否则我们将遇到一个例外情况例如 Your target project Project.Host doesnt match your migrations assembly Project.BusinessLogic. Either change your target project or change your migrations assembly. Change your migrations assembly by using DbContextOptionsBuilder. E.g. options.UseSqlServer(connection, b b.MigrationsAssembly(Project.Host)). By default, the migrations assembly is the assembly containing the DbContext.
Change your target project to the migrations project by using the Package Manager Consoles Default project drop-down list, or by executing dotnet ef from the directory containing the migrations project. 客户端和Scope存储 要为我们需要类似的东西我们的更换范围和客户商店添加持久存储AddInMemoryClientsAddInMemoryIdentityResources并AddInMemoryApiResources用 .AddConfigurationStore(options options.ConfigureDbContext builder builder.UseSqlServer(connectionString, sqlOptions sqlOptions.MigrationsAssembly(migrationsAssembly))) 这些注册还包括从我们的客户端表中读取的CORS策略服务。 运行EF迁移 要运行EF迁移我们需要Microsoft.EntityFrameworkCore.Tools在csproj中将包作为CLI工具添加 ItemGroupDotNetCliToolReference IncludeMicrosoft.EntityFrameworkCore.Tools.DotNet Version2.0.0 / /ItemGroup 然后我们可以使用以下方法创建迁移 dotnet ef migrations add InitialIdentityServerMigration -c PersistedGrantDbContext
dotnet ef migrations add InitialIdentityServerMigration -c ConfigurationDbContext 要使用我们之前使用的配置以编程方式创建客户端和资源请查看本文库中的InitializeDbTestData方法。 ASP.NET Core Identity 为了为我们的用户添加持久性存储Identity Server 4提供了ASP.NET Core Identity (ASP.NET Identity 3)库的集成。我们将使用ASP.NET核心身份实体框架库和基础IdentityUser实体再次使用SQL服务器执行此操作 IdentityServer4.AspNetIdentity
Microsoft.AspNetCore.Identity.EntityFrameworkCore Microsoft.EntityFrameworkCore.SqlServer 目前我们需要创建自己的自定义实现IdentityDbContext以覆盖构造函数以获取非泛型版本DbContextOptions。这是因为IdentityDbContext只有一个接受通用的构造函数DbContextOptions当我们注册多个DbContexts时会导致无效的操作异常。我已经就此问题提出了一个问题希望我们能尽快跳过这一步。 public class ApplicationDbContext : IdentityDbContext { public ApplicationDbContext(DbContextOptionsApplicationDbContext options) : base(options) { } } 然后我们需要为我们的ConfigureServices方法添加ASP.NET Identity DbContext的注册。 services.AddDbContextApplicationDbContext(builder builder.UseSqlServer(connectionString, sqlOptions sqlOptions.MigrationsAssembly(migrationsAssembly))); services.AddIdentityIdentityUser, IdentityRole() .AddEntityFrameworkStoresApplicationDbContext(); 然后在我们的IdentityServerBuilder替换AddTestUsers中 .AddAspNetIdentityIdentityUser() 我们再次需要运行迁移。这可以通过以下方式完成 dotnet ef migrations add InitialIdentityServerMigration -c ApplicationDbContext 这就是将ASP.NET核心身份与IdentityServer 4连接起来所需的全部内容但不幸的是我们之前下载的Quickstart用户界面不再正常工作因为它仍在使用TestUserStore。 但是我们可以通过替换一些代码从Quickstart UI修改我们现有的AccountsController以适用于ASP.NET Core Identity。 首先我们需要更改构造函数以接受ASP.NET核心标识UserManager而不是现有的TestUserStore。我们的构造函数现在应该如下所示 private readonly UserManagerIdentityUser _userManager; private readonly IIdentityServerInteractionService _interaction; private readonly IEventService _events; private readonly AccountService _account; public AccountController( IIdentityServerInteractionService interaction, IClientStore clientStore, IHttpContextAccessor httpContextAccessor, IEventService events, UserManagerIdentityUser userManager) { _userManager userManager; _interaction interaction; _events events; _account new AccountService(interaction, httpContextAccessor, clientStore); } 通过删除TestUserStore我们没有破两种方法:( Login发布和ExternalCallback。我们可以Login完全用以下方法替换该方法 [HttpPost]
[ValidateAntiForgeryToken] public async TaskIActionResult Login(LoginInputModel model, string button) { if (button ! login) { var context await _interaction.GetAuthorizationContextAsync(model.ReturnUrl); if (context ! null) { await _interaction.GrantConsentAsync(context, ConsentResponse.Denied); return Redirect(model.ReturnUrl); } else { return Redirect(~/); } } if (ModelState.IsValid) { var user await _userManager.FindByNameAsync(model.Username); if (user ! null await _userManager.CheckPasswordAsync(user, model.Password)) { await _events.RaiseAsync( new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName)); AuthenticationProperties props null; if (AccountOptions.AllowRememberLogin model.RememberLogin) { props new AuthenticationProperties { IsPersistent true, ExpiresUtc DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration) }; }; await HttpContext.SignInAsync(user.Id, user.UserName, props); if (_interaction.IsValidReturnUrl(model.ReturnUrl) || Url.IsLocalUrl(model.ReturnUrl)) { return Redirect(model.ReturnUrl); } return Redirect(~/); } await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, invalid credentials)); ModelState.AddModelError(, AccountOptions.InvalidCredentialsErrorMessage); } var vm await _account.BuildLoginViewModelAsync(model); return View(vm); } 使用ExternalCallback回调方法我们需要使用以下内容替换find和provision逻辑 [HttpGet]
public async TaskIActionResult ExternalLoginCallback() { var result await HttpContext.AuthenticateAsync(IdentityConstants.ExternalScheme); if (result?.Succeeded ! true) { throw new Exception(External authentication error); } var externalUser result.Principal; var claims externalUser.Claims.ToList(); var userIdClaim claims.FirstOrDefault(x x.Type JwtClaimTypes.Subject); if (userIdClaim null) { userIdClaim claims.FirstOrDefault(x x.Type ClaimTypes.NameIdentifier); } if (userIdClaim null) { throw new Exception(Unknown userid); } claims.Remove(userIdClaim); var provider result.Properties.Items[scheme]; var userId userIdClaim.Value; var user await _userManager.FindByLoginAsync(provider, userId); if (user null) { user new IdentityUser { UserName Guid.NewGuid().ToString() }; await _userManager.CreateAsync(user); await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, userId, provider)); } var additionalClaims new ListClaim(); var sid claims.FirstOrDefault(x x.Type JwtClaimTypes.SessionId); if (sid ! null) { additionalClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value)); } AuthenticationProperties props null; var id_token result.Properties.GetTokenValue(id_token); if (id_token ! null) { props new AuthenticationProperties(); props.StoreTokens(new[] { new AuthenticationToken { Name id_token, Value id_token } }); } await _events.RaiseAsync转载于:https://www.cnblogs.com/miskis/p/9456420.html