IdentityServer4網頁(單點)登陸入門

變形精怪發表於2020-08-23

前言

本篇說說ids中的網頁登陸以及單點登陸的大致原理,主要是以基本跑通為目的,下一篇開始會詳細說明整合ids網頁登陸原理。 

最好先熟悉以下知識:

  • asp.net core
  • asp.net core的身份驗證和基於策略的授權
  • identityServer官方文件過一遍

推薦蔣老師的《asp.net core 3 框架解密

場景

你在訪問一個網站登陸時,可以選擇輸入賬號密碼登陸,也可以選擇第三方登陸,如:QQ、微博賬號等。登陸流程我就不廢話了。假設是QQ登陸,我們這裡可以通過ids4來實現QQ伺服器來向第三方應用提供身份驗證的功能

  1. 我們有多個MVC應用,假如是mvc1、mvc2,
  2. 希望統一由IndentityServer來做使用者管理,假如這個服務叫idsServer
  3. 使用者在登陸mvc1時自動跳轉到idsServer的登陸頁面,登陸成功後mvc1能拿到一個代表此使用者的id(一個加密的字串)
  4. 在我們後續請求mvc1時隨時可以拿到使用者的id
  5. 當請求mvc2時,由於是另一給應用,沒登陸的情況下會跳轉到idsServer去做登陸
  6. idsServer檢測到這個瀏覽器之前在mvc1中做過登陸,直接返回使用者id給mvc2

到此實現了mvc應用整合ids登陸,並實現了單點登陸。步驟5、6有點玄乎,下面會說明。ids4針對使用者來說只是做身份驗證(登陸),也就是識別出當前使用者是誰,最終體現就是我們的應用可以拿到當前使用者的id,ids4不負責使用者的應用程式功能的授權,比如通常理解的基於角色的選單、按鈕許可權

環境搭建

按官方文件的如下步驟可以搭建環境:

  1. https://identityserver4.readthedocs.io/en/latest/quickstarts/1_client_credentials.html
  2. 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就可用登出了。

主體流程

  1. 首先使用者請求mvc1的受保護頁面,mvc1的授權策略檢測使用者未登入,發出一個質詢,由ids客戶端庫提供的身份驗證處理器(在startup中配置的那個"oidc"的身份驗證方案)處理這個質詢,組織請求引數並跳重定向使用者轉到idsServer的登入頁
  2. idsServer的AccountController.Login接收請求,通過相互服務介面IIdentityServerInteractionService對當前請求做驗證(客戶端啊、請求的scope啊、等等..),驗證成功的話,得到一個結果AuthorizationRequest,表示當前授權請求,裡面包含客戶端id及其它引數
  3. 根據結果組織一個ViewModel,主要是決定是否顯示第三方登陸(客戶端請求時指定了希望哪種登陸方式?客戶端配置時指定了支援哪些驗證方式?idsServer預設支援哪些驗證方式?)
  4. 假如使用者使用賬號密碼登陸,輸入後提交
  5. AccountController.Login Post接收請求,做步驟2一樣的事,驗證下客戶端以及其它引數的驗證,若通過則驗證使用者賬號密碼,若成功則得到使用者實體(ids中註冊的使用者資訊)
  6. ids自己做本地登陸,將使用者資訊加密儲存到cookie中,然後跳轉到自己的/connect/authenraztion/callback終結點
  7. 在/callback終結點中先驗證客戶端提交的各引數,生成臨時code,回撥客戶端的".../signin-oidc"
  8. 客戶端攜帶clientid 金鑰 code 之類的引數找ids請求idToken和accessToken
  9. ids返回idToken和accessToken,mvc1服務端儲存它們,然後將使用者標識加密儲存到使用者的cookie中
  10. 使用者後續攜帶使用者標識cookie請求mvc1就可用了
  11. mvc1有時候需要攜帶accessToken訪問被ids保護的第三方介面
  12. 當使用者發起登出呼叫Home/logout時,在mvc1中註冊的兩個身份驗證方案都會執行,"Cookies"將情況使用者本地儲存使用者標識的cookie,“oidc”會與ids通訊,刪除ids存到使用者瀏覽器中的cookie,此時ids還會以某種機智通知到其它已登陸的客戶端,如何通知的後面再說

單點登陸的重點

按流程看,使用者瀏覽器儲存了兩份代表使用者標識的cookie,一個在idsServer域名下,要給在mvc1域名下,當mvc跳轉到ids登入頁時,會攜帶ids域名下的cookie

ids一看,這使用者登陸過,就直接攜帶使用者資訊和token並跳轉到回撥客戶端的".../signin-oidc",客戶端的後續步驟不變

結尾

本篇只是草草說了各大概,下一篇會先說說ids網頁登陸裡涉及到的交給核心類,之後會重新按這裡的流程走走原始碼...

相關文章