OpenID 配置步骤
允许客户端基于授权服务器执行的身份验证来验证最终用户的身份,以及以可互操作和类似REST的方式获取关于最终用户的基本配置文件信息。
创建一个MVC客户端
1.新建一个ASP.NET Core MVC应用程序
2.配置 OpenID Connect 认证
在类Startup
的 ConfigureServices
方法中添加以下代码:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 services.AddMvc(); 4 5 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 6 7 services.AddAuthentication(options => 8 { 9 options.DefaultScheme = "Cookies"; 10 options.DefaultChallengeScheme = "oidc"; 11 }) 12 .AddCookie("Cookies") 13 .AddOpenIdConnect("oidc", options => 14 { 15 options.SignInScheme = "Cookies"; 16 17 options.Authority = "http://localhost:5000"; 18 options.RequireHttpsMetadata = false; 19 20 options.ClientId = "mvc"; 21 options.SaveTokens = true; 22 }); 23 }
AddAuthentication将认证服务添加到依赖注入容器中,使用Cookie作为验证用户的主要方法(通过"Cookies"
作为 DefaultScheme
)。
DefaultChallengeScheme 设置为"oidc"
(OIDC是OpenID Connect的简称),因为当我们需要用户登录时,我们将使用OpenID Connect方案。
然后我们使用AddCookie
添加可以处理Cookie的处理程序。
最后,AddOpenIdConnect
用于配置执行OpenID Connect协议的处理程序。Authority
表示id4服务的地址。 然后我们通过ClientId
识别该客户端。SignInScheme
用于在OpenID Connect协议完成后使用cookie处理程序发出cookie。 而SaveTokens
用于在Cookie中保存IdentityServer中的令牌(稍后将需要)。
然后确保在每个请求上执行认证服务,在Startup
中的Configure
方法添加UseAuthentication
:
1 public void Configure(IApplicationBuilder app, IHostingEnvironment env) 2 { 3 if (env.IsDevelopment()) 4 { 5 app.UseDeveloperExceptionPage(); 6 } 7 else 8 { 9 app.UseExceptionHandler("/Home/Error"); 10 } 11 12 app.UseAuthentication(); 13 14 app.UseStaticFiles(); 15 app.UseMvcWithDefaultRoute(); 16 }
验证中间件应该在MVC之前添加。
最后一步是触发认证。为了进入HomeController,并在其中一个Action上添加特性[Authorize]
还要修改该Action的View以显示用户的信息,例如:
1 <dl> 2 @foreach (var claim in User.Claims) 3 { 4 <dt>@claim.Type</dt> 5 <dd>@claim.Value</dd> 6 } 7 </dl>
如果您现在使用浏览器访问HomeController,将会导致重定向到IdentityServer,这将导致错误,因为MVC客户端尚未注册。
添加OpenID Connect Identity Scopes的支持
与OAuth 2.0类似,OpenID Connect也使用Scopes概念。 再次,Scopes代表您想要保护的客户端希望访问的内容。 与OAuth相反,OIDC中的范围不代表API,而是代表用户ID,姓名或电子邮件地址等身份信息。
在Config.cs
中添加如下代码:
1 public static IEnumerable<IdentityResource> GetIdentityResources() 2 { 3 return new List<IdentityResource> 4 { 5 new IdentityResources.OpenId(), 6 new IdentityResources.Profile(), 7 }; 8 }
所有标准Scopes及其相应的声明都可以在OpenID Connect规范中找到。
然后,您需要将这些身份资源添加到Startup.cs中的IdentityServer配置中。使用AddInMemoryIdentityResources
扩展方法调用AddIdentityServer()
:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 services.AddMvc(); 4 5 // configure identity server with in-memory stores, keys, clients and scopes 6 services.AddIdentityServer() 7 .AddDeveloperSigningCredential() 8 .AddInMemoryIdentityResources(Config.GetIdentityResources()) 9 .AddInMemoryApiResources(Config.GetApiResources()) 10 .AddInMemoryClients(Config.GetClients()) 11 .AddTestUsers(Config.GetUsers()); 12 }
为OpenID Connect implicit flow 添加客户端
Implicit Flow指的是使用OAuth2的Implicit流程获取Id Token和Access Token
最后一步是将MVC客户端的配置添加到IdentityServer。
基于OpenID Connect的客户端与我们迄今添加的OAuth 2.0客户端非常相似。 但是由于OIDC中的流程始终是交互式的,我们需要在配置中添加一些重定向URL。
将以下内容添加到您的客户端配置:
1 public static IEnumerable<Client> GetClients() 2 { 3 return new List<Client> 4 { 5 // other clients omitted... 6 7 // OpenID Connect implicit flow client (MVC) 8 new Client 9 { 10 ClientId = "mvc", 11 ClientName = "MVC Client", 12 AllowedGrantTypes = GrantTypes.Implicit, 13 14 // where to redirect to after login 15 RedirectUris = { "http://localhost:5002/signin-oidc" }, 16 17 // where to redirect to after logout 18 PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" }, 19 20 AllowedScopes = new List<string> 21 { 22 IdentityServerConstants.StandardScopes.OpenId, 23 IdentityServerConstants.StandardScopes.Profile 24 } 25 } 26 }; 27 }
测试客户端
通过访问受保护的Action来触发身份验证握手。 你应该看到重定向到IdentityServer的登录页面。
成功登录后,用户将看到同意画面。 在这里,用户可以决定是否要将他的身份信息发布到客户端应用程序。
可以使用客户端对象上的RequireConsent属性以每个客户端为基础关闭同意询问。
最后浏览器重定向到客户端应用程序,该应用程序显示了用户的声明。
在开发过程中,您有时可能会看到一个异常,说明令牌无法验证。 这是因为签名密钥信息是即时创建的,并且只保存在内存中。 当客户端和IdentityServer不同步时,会发生此异常。 只需在客户端重复操作,下次元数据已经追上,一切都应该正常工作。
添加注销
最后一步是给MVC客户端添加注销功能。
使用IdentityServer等身份验证服务,仅清除本地应用程序Cookie是不够的。 此外,您还需要往身份服务器交互,以清除单点登录会话。
确切的协议步骤在OpenID Connect中间件内实现,只需将以下代码添加到某个控制器即可触发注销:
1 public async Task Logout() 2 { 3 await HttpContext.SignOutAsync("Cookies"); 4 await HttpContext.SignOutAsync("oidc"); 5 }
这将清除本地cookie,然后重定向到IdentityServer。 IdentityServer将清除它的cookie,然后给用户一个链接返回到MVC应用程序。
进一步实验
如上所述,OpenID Connect中间件默认要求配置 profile scope。 这个scope还包括像名字或网站这样的声明。
让我们将这些声明添加到用户,以便IdentityServer可以将它们放入身份令牌中:
1 public static List<TestUser> GetUsers() 2 { 3 return new List<TestUser> 4 { 5 new TestUser 6 { 7 SubjectId = "1", 8 Username = "alice", 9 Password = "password", 10 11 Claims = new [] 12 { 13 new Claim("name", "Alice"), 14 new Claim("website", "https://alice.com") 15 } 16 }, 17 new TestUser 18 { 19 SubjectId = "2", 20 Username = "bob", 21 Password = "password", 22 23 Claims = new [] 24 { 25 new Claim("name", "Bob"), 26 new Claim("website", "https://bob.com") 27 } 28 } 29 }; 30 }
下一次您进行身份验证时,你的声明页面现在将显示额外的声明。
OpenID Connect中间件上的Scope属性是您配置哪些Scope将在身份验证期间发送到IdentityServer。
值得注意的是,对令牌中身份信息的遍历是一个扩展点 - IProfileService。因为我们正在使用 AddTestUser,所以默认使用的是 TestUserProfileService。你可以检出这里的源代码来查看它的工作原理。
Demo下载地址
参考官方文档:https://identityserver4.readthedocs.io/en/release/quickstarts/3_interactive_login.html
官方的Demo已经更新到最新的.NET Core 2.0