我希望有个如你一般的人
我希望有个如你一般的人,如山间清爽的风,如古城温暖的光,从清晨到夜晚,从山野到书房,只要最后是你,就好。
单点登录是利用 identity server4中open id的特性(也就是身份验证的特性)。OAuth2.0是用于授权的,身份验证和授权要区别开来,4大授权模式也是针对的OAuth2.0特性来说的
大概的猜测一下实现单点登录的流程。
A项目访问需要登录模块的时候先在本地取缓存数据发现没有就跳转到认证中心的缓存取,发现也没有就跳转到登录界面,登录成功后在认证中心写入登录缓存信息,并且在客户端写入缓存信息(缓存在客户端信息,然后把token存储在cookie什么的即可),这样当A项目再次访问的时候直接在本地取认证信息即可。
B项目访问的时候在本地取没有信息,就去认证中心去取发现前面已经登录过了(服务器会根据客户端信息去取,由于是同一台电脑同一个浏览器,比如ip什么的可以作为一个客户端key)就通过认证并且在回来的时候把认证信息写入客户端。
如图可以看看的登录日志
当然要更详细更准确的了解还是分析源码好,这个工作放到后面做
创建统一的授权中心
一:下载需要的包
Install-package IdentityServer4 –version xxx
二:创建配置类
public class Config { // scopes define the resources in your system public static IEnumerable<IdentityResource> GetIdentityResources() { return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), }; } // clients want to access resources (aka scopes) public static IEnumerable<Client> GetClients() { return new List<Client> { // OpenID Connect隐式流客户端(MVC) new Client { ClientId = "gobuy.product", ClientName = "MVC Client", AllowedGrantTypes = GrantTypes.Implicit,//隐式方式 RequireConsent=false,//如果不需要显示否同意授权 页面 这里就设置为false RedirectUris = { "http://localhost:52316/signin-oidc" },//登录成功后返回的客户端地址 PostLogoutRedirectUris = { "http://localhost:52316/signout-callback-oidc" },//注销登录后返回的客户端地址 AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile } }, new Client { ClientId = "gobuy.order", ClientName = "MVC Client", AllowedGrantTypes = GrantTypes.Implicit,//隐式方式 RequireConsent=false,//如果不需要显示否同意授权 页面 这里就设置为false RedirectUris = { "http://localhost:52302/signin-oidc" },//登录成功后返回的客户端地址 PostLogoutRedirectUris = { "http://localhost:52302/signout-callback-oidc" },//注销登录后返回的客户端地址 AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile } } }; } }
这里配置的两个客户端,用于测试登录一个后,另外一个也自动登录
三:ConfigureServices增加ids4
services.AddIdentityServer()//Ids4服务 .AddDeveloperSigningCredential()//添加开发人员签名凭据 .AddInMemoryIdentityResources(Config.GetIdentityResources()) //添加内存apiresource .AddInMemoryClients(Config.GetClients());//把配置文件的Client配置资源放到内存
五:Configure中启动ids4中间件
//启动ids4中间件 app.UseIdentityServer();
六:实现自己的登录逻辑
创建Account控制器,增加代码如下:
public class AccountController : Controller { /// <summary> /// 登录页面 /// </summary> [HttpGet] public IActionResult Login(string returnUrl = null) { ViewData["returnUrl"] = returnUrl; return View(); } /// <summary> /// 登录post回发处理 /// </summary> [HttpPost] public async Task<IActionResult> Login(string userName, string password, string returnUrl = null) { ViewData["returnUrl"] = returnUrl; //模拟登录成功,真正的逻辑换成自己的即可 if (userName != null) { AuthenticationProperties props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1)), }; //注意这里应该引用Microsoft.AspNetCore.Http这个下面的 await HttpContext.SignInAsync("10000", userName, props); //HttpContext.SignOutAsync(); if (returnUrl != null) //登录成功跳转回原地址 { return Redirect(returnUrl); } return View(); } else { return Content("登录失败"); } } }
这里说几点:
1:returnUrl是ids4封装好的,没有登录的时候跳转到配置中心会带上很多客户端信息,其中一个就是客户端地址
2:HttpContext.SignInAsync方法是用的Microsoft.AspNetCore.Http这个下面的,不是 identity server4 包下面的
登录页面:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Login</title> </head> <body> <div align="center"> <h1>tnblog统一认证登录中心</h1> <form method="post" action="/account/Login"> 用户名:<input type="text" name="userName" /><br /> 密 码:<input type="password" name="password" /> <input type="hidden" name="returnUrl" value="@ViewData["returnUrl"]" /> <br /> <input type="submit" value="登录" /> </form> </div> </body> </html>
很简单就是常规的
创建客户端
登录服务创建好后,客户端就相对比较简单了
一:在ConfigureServices添加相关配置
services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "http://localhost:55845";//登录中心的地址 options.RequireHttpsMetadata = false; options.ClientId = "gobuy.product"; options.SaveTokens = true; });
这里的AddOpenIdConnect
需要下载一个依赖:Microsoft.AspNetCore.Authentication.OpenIdConnect
install-package Microsoft.AspNetCore.Authentication.OpenIdConnect -version 3.0
二:在Configure中添加身份验证中间件
//身份验证 app.UseAuthentication();
三:在需要登录验证的地方增加 [Authorize]即可
然后就可以测试了,当我们没有登录的时候访问需要登录验证的就会跳转到授权中心
登录后就能访问
并且项目一登录后项目二可以直接访问需要登录的页面
注意这里使用的是:隐藏模式,如果想要使用授权码模式的话需要使用:混合模式(Hybrid)
客户端获取Id_token与隐藏模式和授权码模式一样,都是通过redirect_url参数返回的,所以前面的四种模式中的客户端模式与密码模式不支持获取id_token,而授权码模式受限于流程,必需先取得Code才能取到token,所以不能直接支持获取id_token,如果需求是使用授权码模式,同时又需要id_token,OpenIdConnect支持第五种模式:混合模式(Hybrid),就是基于隐藏模式与授权码模式的结合.
欢迎加群讨论技术,群:677373950(满了,可以加,但通过不了),2群:656732739