前言
本篇說說ids中的網頁登陸以及單點登陸的大致原理,主要是以基本跑通為目的,下一篇開始會詳細說明整合ids網頁登陸原理。
最好先熟悉以下知識:
- asp.net core
- asp.net core的身份驗證和基於策略的授權
- identityServer官方文件過一遍
推薦蔣老師的《asp.net core 3 框架解密》
場景
你在訪問一個網站登陸時,可以選擇輸入賬號密碼登陸,也可以選擇第三方登陸,如:QQ、微博賬號等。登陸流程我就不廢話了。假設是QQ登陸,我們這裡可以通過ids4來實現QQ伺服器來向第三方應用提供身份驗證的功能。
- 我們有多個MVC應用,假如是mvc1、mvc2,
- 希望統一由IndentityServer來做使用者管理,假如這個服務叫idsServer
- 使用者在登陸mvc1時自動跳轉到idsServer的登陸頁面,登陸成功後mvc1能拿到一個代表此使用者的id(一個加密的字串)
- 在我們後續請求mvc1時隨時可以拿到使用者的id
- 當請求mvc2時,由於是另一給應用,沒登陸的情況下會跳轉到idsServer去做登陸
- idsServer檢測到這個瀏覽器之前在mvc1中做過登陸,直接返回使用者id給mvc2
到此實現了mvc應用整合ids登陸,並實現了單點登陸。步驟5、6有點玄乎,下面會說明。ids4針對使用者來說只是做身份驗證(登陸),也就是識別出當前使用者是誰,最終體現就是我們的應用可以拿到當前使用者的id,ids4不負責使用者的應用程式功能的授權,比如通常理解的基於角色的選單、按鈕許可權
環境搭建
按官方文件的如下步驟可以搭建環境:
- https://identityserver4.readthedocs.io/en/latest/quickstarts/1_client_credentials.html
- https://identityserver4.readthedocs.io/en/latest/quickstarts/2_interactive_aspnetcore.html
我們這裡使用更直接一點的方式,使用它提供的專案模板一步到位
1、安裝ids4的專案模板
dotnet new -i IdentityServer4.Templates
2、根據模板建立ids4專案
dotnet new is4inmem
此模板建立會直接幫你建立要給立即可用的ids服務應用,裡面的客戶端、資源、使用者都是以記憶體的形式定義的。直接F5就可用跑起來
3、在ids服務端中註冊mvc1、mvc2的配置
就是在ids登記下這倆客戶端,我是ids,你倆要讓我來幫你們做登陸得先來我這裡登個記對吧
在Config.Clients中新增如下配置:
new Client { //客戶端id ClientId = "mvc1", //客戶端金鑰 ClientSecrets = { new Secret("secret".Sha256()) }, //授權模式為code AllowedGrantTypes = GrantTypes.Code, //ids發放code時要回撥客戶端的地址 RedirectUris = { "https://localhost:5002/signin-oidc" }, //完成在ids中登出後回撥客戶端的這個地址 PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" }, //ids允許此客戶端訪問這些scope AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile } }
mvc2的配置一樣。
4、新建mvc1、mvc2客戶端
5、配置mvc1客戶端,mvc2類似略了
5.1、調整倆專案啟動監聽的埠,防止3個專案的埠衝突,我這裡ids用的5001,mvc1用的5002,mvc2用的5003
5.2、引用nuget包
install-package Microsoft.AspNetCore.Authentication.OpenIdConnect
5.3、在startup.cs中做配置
1 public void ConfigureServices(IServiceCollection services) 2 { 3 services.AddControllersWithViews(); 4 JwtSecurityTokenHandler.DefaultMapInboundClaims = false;//還沒研究過它是幹啥的 5 services.AddAuthentication(options => //註冊asp.net core 身份驗證核心服務,並配置 6 { 7 options.DefaultScheme = "Cookies";//預設的身份驗證方案名 8 options.DefaultChallengeScheme = "oidc";//用來跳轉到dis登入頁的身份驗證方案名 9 //注意這倆配置與下面註冊的身份驗證方案的名字對應 10 }) 11 .AddCookie("Cookies")//註冊asp.net core 預設的基於cookie的身份驗證方案 12 .AddOpenIdConnect("oidc", options =>//註冊ids為我們提供的oidc身份驗證方案 13 { 14 options.Authority = "https://localhost:5001";//配置ids的根路徑 15 options.ClientId = "mvc1";//此客戶但的id 16 options.ClientSecret = "secret";//此客戶端的金鑰 17 options.ResponseType = "code";//授權模式 18 options.SaveTokens = true;//是否將最後獲取的idToken和accessToken儲存到預設身份驗證方案中 19 }); 20 }
5.4、在startup.cs中做配置啟用asp.net core的身份驗證中介軟體
1 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 2 { 3 //略... 4 app.UseAuthentication(); 5 app.UseAuthorization(); 6 //略... 7 }
5.5、找個Controller的Action來充當受保護的頁面,比如HomeController.Index
[Authorize] public IActionResult Index() { return View(); }
5.6、為了容易看到效果,可用修改下首頁的檢視,顯示下當前登陸使用者的資訊
1 @using Microsoft.AspNetCore.Authentication 2 <h2>Claims</h2> 3 <dl> 4 @foreach (var claim in User.Claims) 5 { 6 <dt>@claim.Type</dt> 7 <dd>@claim.Value</dd> 8 } 9 </dl> 10 <h2>Properties</h2> 11 <dl> 12 @foreach (var prop in (await Context.AuthenticateAsync()).Properties.Items) 13 { 14 <dt>@prop.Key</dt> 15 <dd>@prop.Value</dd> 16 } 17 </dl>
跑起來
在解決方案上右鍵->屬性
Ctrl + F5 走起...
此時由於mvc1和2的HomeController.Index是受保護的資源,首次訪問因為使用者並沒有登陸,因此會調轉到ids的登入頁去
錄入測試賬號和密碼,ailice點選登陸,此時會跳轉到mvc1的首頁,因為已登陸成功,所以此時頁面可用正常方案
此時若去訪問mvc2的首頁https://localhost:5003/你會發現它會跳轉以下,最後直接就可用訪問,並不需要我們再登陸了,這就是所謂的單點登陸。
如何登出?
登出時要清楚本地登陸和ids那邊的登陸狀態,在mvc1和2的HomeController中加入如下Action
public IActionResult Logout()
{
return SignOut("Cookies", "oidc");
}
此時訪問下這個Action就可用登出了。
主體流程
- 首先使用者請求mvc1的受保護頁面,mvc1的授權策略檢測使用者未登入,發出一個質詢,由ids客戶端庫提供的身份驗證處理器(在startup中配置的那個"oidc"的身份驗證方案)處理這個質詢,組織請求引數並跳重定向使用者轉到idsServer的登入頁
- idsServer的AccountController.Login接收請求,通過相互服務介面IIdentityServerInteractionService對當前請求做驗證(客戶端啊、請求的scope啊、等等..),驗證成功的話,得到一個結果AuthorizationRequest,表示當前授權請求,裡面包含客戶端id及其它引數
- 根據結果組織一個ViewModel,主要是決定是否顯示第三方登陸(客戶端請求時指定了希望哪種登陸方式?客戶端配置時指定了支援哪些驗證方式?idsServer預設支援哪些驗證方式?)
- 假如使用者使用賬號密碼登陸,輸入後提交
- AccountController.Login Post接收請求,做步驟2一樣的事,驗證下客戶端以及其它引數的驗證,若通過則驗證使用者賬號密碼,若成功則得到使用者實體(ids中註冊的使用者資訊)
- ids自己做本地登陸,將使用者資訊加密儲存到cookie中,然後跳轉到自己的/connect/authenraztion/callback終結點
- 在/callback終結點中先驗證客戶端提交的各引數,生成臨時code,回撥客戶端的".../signin-oidc"
- 客戶端攜帶clientid 金鑰 code 之類的引數找ids請求idToken和accessToken
- ids返回idToken和accessToken,mvc1服務端儲存它們,然後將使用者標識加密儲存到使用者的cookie中
- 使用者後續攜帶使用者標識cookie請求mvc1就可用了
- mvc1有時候需要攜帶accessToken訪問被ids保護的第三方介面
- 當使用者發起登出呼叫Home/logout時,在mvc1中註冊的兩個身份驗證方案都會執行,"Cookies"將情況使用者本地儲存使用者標識的cookie,“oidc”會與ids通訊,刪除ids存到使用者瀏覽器中的cookie,此時ids還會以某種機智通知到其它已登陸的客戶端,如何通知的後面再說
單點登陸的重點
按流程看,使用者瀏覽器儲存了兩份代表使用者標識的cookie,一個在idsServer域名下,要給在mvc1域名下,當mvc跳轉到ids登入頁時,會攜帶ids域名下的cookie
ids一看,這使用者登陸過,就直接攜帶使用者資訊和token並跳轉到回撥客戶端的".../signin-oidc",客戶端的後續步驟不變
結尾
本篇只是草草說了各大概,下一篇會先說說ids網頁登陸裡涉及到的交給核心類,之後會重新按這裡的流程走走原始碼...