1. 程式人生 > 實用技巧 >IdentityServer4系列 | 快速搭建簡易專案

IdentityServer4系列 | 快速搭建簡易專案

原文:https://www.cnblogs.com/i3yuan/p/13843082.html


一 、前言

從上一篇關於 常見術語說明中,主要是對IdentityServer4的說明,以及其中涉及常見的術語的表述說明,包括對身份認證伺服器、使用者、客戶端、資源以及各個令牌等進行對比區別說明。

而在這一篇中,我們將嘗試通過簡單的方式來搭一個我們的IdentityServer授權伺服器,熟悉IdentityServer4中搭建的流程以及將出現的問題。

二、 搭建

以下的專案示例都是基於IdentityServer4 4.x版本以上進行說明。

4.x版本較之前3.x的版本都有一些變更,在本例中,若發現與3.x版本有變更的一些地方,都會進行記錄說明。

2.1.建立專案

建立一個空的Asp.Net Core專案 ,使用Empty空模板

2.2.安裝配置

2.2.1. 安裝程式包

  • 可通過命令列的方式

    NuGet>Install-Package IdentityServer4

  • 通過包管理器方式

    新增IdentityServer4包

2.2.2. 配置管道

修改Configure方法,注入到容器

 app.UseIdentityServer();

2.2.3. 配置內容

將服務注入到容器後,還需要對IdentityServce進行配置內容

  • 哪些API需要Authorization Server進行資源保護
  • 哪些Client可以使用這個Authorization Server
  • 哪些User可以被這個AuthorizationServer識別並授權
  • 哪些資源可以指定作用域

這裡方便演示,直接以靜態化的形式展示,實際開發應用中,可結合資料庫或reidis快取的資料持久化方式獲取。

建立配置內容檔案 IdentityConfig.cs

(具體的 OpenID Connect 配置資訊來原始檔)

    public class IdentityConfig
    {
        public static IEnumerable<IdentityResource> IdentityResources =>
           new IdentityResource[]
           {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
           };
        /// <summary>
        /// Authorization Server保護了哪些 API Scope(作用域)
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiScope> GetApiScopes()
        {
            return new[] { new ApiScope("ApiScope1", "ApiScope2") };
        }
        /// <summary>
        /// 哪些客戶端 Client(應用) 可以使用這個 Authorization Server
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new[]
            {
                new Client()
                {
                    ClientId="YuanIdentity", ///客戶端的標識,要是惟一的
                    ClientSecrets=new []{new Secret("6KGqzUx6nfZZp0a4NH2xenWSJQWAT8la".Sha256())}, ////客戶端密碼,進行了加密
                    AllowedGrantTypes= GrantTypes.ClientCredentials, ////授權方式,這裡採用的是客戶端認證模式,只要ClientId,以及ClientSecrets正確即可訪問對應的AllowedScopes裡面的api資源
                    AllowedScopes=new[]{"ApiScope1" }, //定義這個客戶端可以訪問的APi資源陣列,上面只有一個api
                   
                }
            };
        }
        /// <summary>
        /// 哪些User可以被這個AuthorizationServer識別並授權
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<TestUser> GetTestUsers()
        {
            return new[]
            {
               new TestUser
               {
                   SubjectId="001",
                   Username="i3yuan",
                   Password="123456"
               }
           };
        }


    }

注意,如果你的程式碼沒問題,但是依然報錯,比如“無效的scope”等,就可能是nuget包版本問題

在3.1.x 到 4.x 的變更中,ApiResourceScope 正式獨立出來為 ApiScope 物件,區別ApiResourceScope的關係, Scope 是屬於 ApiResource 的一個屬性,可以包含多個 Scope

所以

在3.x版本中

 public static IEnumerable<ApiResource> GetApiResources()
 {
     return new[] { new ApiResource("ApiScope1", "ApiScope2") };
 }

改成4.x版本為

public static IEnumerable<ApiScope> GetApiScopes()
{
 return new[] { new ApiScope("ApiScope1", "ApiScope2") };
}

2.2.4. 新增配置服務

在Startup.cs檔案,ConfigureServices方法中

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddIdentityServer()
                .AddDeveloperSigningCredential() //開發環境    
                .AddTestUsers(IdentityConfig.GetTestUsers().ToList())
                .AddInMemoryClients(IdentityConfig.GetClients())
                .AddInMemoryApiScopes(IdentityConfig.GetApiScopes());
            services.AddControllers();
        }

1. 在學習 IdentityServer4 時熟悉的 InMemory 來說,AddInMemoryApiResources 變為了 AddInMemoryApiScopes 這個 ApiScope

2. 我們現在是本地除錯,可以告訴identity server4在程式的執行時候對這項工作進行設定: AddDeveloperSigningCredential(),它預設會存到硬碟上的, 所以每次重啟服務不會破壞開發時的資料同步。這個方法只適合用於identity server4在單個機器執行, 如果是 production 你得使用AddSigningCredential()這個方法

以上操作完成後, 啟動專案,通過它的 .well-known 端點來訪問伺服器的配置資訊,在瀏覽器的位址列中,輸入地址:http://localhost:5050/.well-known/openid-configuration,並回車。應該可以看到如下的響應資訊。

2.3. 獲取token

2.3.1. 啟動專案

2.3.2. 測試訪問地址

http://localhost:5050/connect/token

body引數 application/x-www-form-urlencoded (post)

2.3.3. Access_Token

需要對token進行簽名, 這意味著 identity server 需要一對public和private key。同時也是可以由上圖的解析發現是需要一對公私key的。

三、UI介面

考慮IdentityServer4需要進行管理檢視,新增頁面管理介面

官方為我們提供了一個快速啟動的UI介面,我們只需要下載下來即可,這裡有兩個方法:

3.1. QuickStart UI介面

1、直接從這個地址下來下載,拷貝到專案中,一共三個資料夾;// https://github.com/IdentityServer/IdentityServer4.Quickstart.UI

2、在當前資料夾中執行命令,自動下載;

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/master/getmaster.ps1'))

3.2. 預設目錄

下載完官方提供的預設UI介面後,會提供預設的三個目錄資料夾分別為:Quickstart (控制器方法)、Views(檢視)、wwwroot (靜態檔案)

3.3. 修改配置

配置中介軟體來使用靜態檔案:

app.UseStaticFiles();

四、執行

執行展示效果,啟動預設的地址如下:

http://localhost:5050

執行專案後,可以發現啟動預設的歡迎介面,看到對應的專案版本,我們這裡用的是最新的IdentityServer4版本為4.1.1 ,以及點選 discovery document,可以看到了我們上邊說到的 token 獲取的介面地址 ,其中對應的端點地址資訊。

通過它的 .well-known 端點來訪問伺服器的配置資訊,在瀏覽器的位址列中,輸入地址:http://localhost:5050/.well-known/openid-configuration,並回車,可以看到對應的響應資訊。

五、模板

在上文中,我們通過手動搭建的方式,從一個空模板的搭建,到引用對應的Nuget包,安裝修改配置,並搭配了官方提供的UI介面,初步形成了一個簡易的IdentityServer4初始化專案框架,這種一步步的構建專案的方式。

官方也給我們提供了對應的快捷建立專案的模板,所以,如果你不想建立MVC專案,可以用官方提供的模板方式進行建立初始化專案。

5.1. 安裝模板

dotnet new -i IdentityServer4.Templates

在命令的輸出中,可以看到已經安裝了多個關於 IdentityServer4 的模版

模板 簡稱 說明
IdentityServer4 with AdminUI is4admin 這為使用者、身份、客戶端和資源提供了一個基於web的管理介面.該社群版本旨在測試IdentityServer整合場景,並且僅限於本地主機:5000、SQLite、10個使用者和2個客戶端。社群版不適合生產應用。
IdentityServer4 with ASP.NET Core Identity is4aspid 新增使用ASP.NET標識進行使用者管理的基本IdentityServer。如果您自動啟動資料庫,您將得到兩個使用者:Alice和bob--都帶有密碼Pass123$。檢查SeedData.cs檔案。
IdentityServer4 Empty is4empty 在沒有UI的情況下建立一個最小的IdentityServer4專案。
IdentityServer4 with Entity Framework Stores is4ef 新增使用實體框架進行配置和狀態管理的基本IdghtyServer。如果您啟動資料庫,您將獲得一些基本的客戶端和資源註冊,請檢查SeedData.cs檔案。
IdentityServer4 with In-Memory Stores and Test Users is4inmem 新增具有UI、測試使用者和示例客戶端和資源的基本IdentityServer。顯示記憶體中的程式碼和JSON配置。
IdentityServer4 Quickstart UI (UI assets only) is4ui 將快速啟動UI新增到當前專案(例如,可以在is4empty的基礎上新增)

5.2. 選擇專案

這裡面最為簡單的專案模版就是 IdentityServer4 with In-Memory Stores and Test Users 了,它簡稱為 is4inmem ,我們下面就使用它來建立專案。

dotnet new 模板名 -n 專案名稱

5.3. 啟動應用

啟動專案後,

可以看到專案的效果跟我們之前一步步搭建的效果是一樣的,這說明我們已經建立了第一個可執行的 IdentityServer4 伺服器了。

六、說明

6.1. HS256與RS256

JWT簽名演算法中,一般有兩個選擇,一個採用HS256,另外一個就是採用RS256。

簽名實際上是一個加密的過程,生成一段標識(也是JWT的一部分)作為接收方驗證資訊是否被篡改的依據。

  1. HS256 使用金鑰生成固定的簽名,簡單地說,HS256 必須與任何想要驗證 JWT的 客戶端或 API 共享金鑰,因此必須注意確保金鑰不被洩露。
  2. RS256 生成非對稱簽名,這意味著必須使用私鑰來籤簽名 JWT,並且必須使用對應的公鑰來驗證簽名。與對稱演算法不同,使用 RS256 可以保證服務端是 JWT 的簽名者,因為服務端是唯一擁有私鑰的一方。這樣做將不再需要在許多應用程式之間共享私鑰。

因此,在開發應用的時候啟用JWT時候,使用RS256更加安全,你可以控制誰能使用什麼型別的金鑰。同時可以讓服務端是唯一擁有私鑰的一方,不需共享私鑰。

6.2 關於證書

生產環境(負載叢集)一般需要使用固定的證書籤名與驗籤,以確保重啟服務端或負載的時候 Token 都能驗籤通過。(不使用臨時證書)

6.2.1 建立證書

#生成私鑰檔案
openssl genrsa -out idsrv4.key 2048
#建立證書籤名請求檔案 CSR(Certificate Signing Request),用於提交給證書頒發機構(即 Certification Authority (CA))即對證書籤名,申請一個數字證書。
openssl req -new -key idsrv4.key -out idsrv4.csr
#生成自簽名證書(證書頒發機構(CA)簽名後的證書,因為自己做測試那麼證書的申請機構和頒發機構都是自己,crt 證書包含持有人的資訊,持有人的公鑰,以及簽署者的簽名等資訊。當用戶安裝了證書之後,便意味著信任了這份證書,同時擁有了其中的公鑰。)
openssl x509 -req -days 365 -in idsrv4.csr -signkey idsrv4.key -out idsrv4.crt
#自簽名證書與私匙合併成一個檔案
openssl pkcs12 -export -in idsrv4.crt -inkey idsrv4.key -out idsrv4.pfx

或
openssl req -newkey rsa:2048 -nodes -keyout idsrv4.key -x509 -days 365 -out idsrv4.cer
openssl pkcs12 -export -in idsrv4.cer -inkey idsrv4.key -out idsrv4.pfx

中途提示讓你輸入Export Password,這個password後面會用到。

6.2.2 專案配置

拷貝生成的證書,放到認證/授權伺服器專案中。(VS中配置檔案設定檔案始終複製),最後把證書路徑和密碼配置到 IdentityServer 中,因為我們自簽名的證書是 PKCS12 (個人數字證書標準,Public Key Cryptography Standards #12) 標準包含私鑰與公鑰)標準,包含了公鑰和私鑰。

A、在appsetting.json 配置檔案中新增如下:此處需要配置password,即生成證書的時候輸入的密碼。

{
    "Certificates": {
        "CerPath": "certificate\\idsrv4.pfx",
        "Password": "P@ssw0rd"
    }
} 

B、在starup.cs中ConfigureServices方法中配置如下即可。

var basePath = PlatformServices.Default.Application.ApplicationBasePath;
services.AddIdentityServer().AddSigningCredential(new X509Certificate2(
Path.Combine(basePath,Configuration["Certificates:CerPath"]),
Configuration["Certificates:Password"])
)

C、配置完後即可。我們啟動IDS4專案即可生成加密的token。

6.2.3 提取補充

OpenSSL 提取 pfx 證書公鑰與私鑰

提取pfx證書公鑰和私鑰
從pfx證書中提取金鑰資訊,並轉換為key格式(pfx使用pkcs12模式補足)
1. 提取金鑰對(如果pfx證書已加密,會提示輸入密碼)
openssl pkcs12 -in idsrv4.pfx -nocerts -nodes -out idsrv4.key
2. 從金鑰對提取公鑰
openssl rsa -in idsrv4.key -pubout -out idsrv4_pub.key
3. 從金鑰對提取私鑰
openssl rsa -in  idsrv4.key -out idsrv4_pri.key
4. 因為RSA演算法使用的是 pkcs8 模式補足,需要對提取的私鑰進一步處理得到最終私鑰
openssl pkcs8 -topk8 -inform PEM -in idsrv4_pri.key -outform PEM -nocrypt

注意:

將得到的token在jwt.io 網站來認證一下,需要將 crt 公鑰、key私鑰複製到驗證中,發現認證ok,則說明實現防篡改。

字尾為crt公鑰需要帶著 -----BEGIN CERTIFICATE----- 和 -----END CERTIFICATE----- 一起復制。
字尾為key私鑰私鑰需要帶著 -----BEGIN RSA PRIVATE KEY----- 和 -----END RSA PRIVATE KEY----- 一起復制。

七、總結

  1. 在本篇中我們通過手動或者官方模板的方式簡易的實現了我們的IdentityServer授權伺服器搭建,並做了相應的配置和UI配置,實現了獲取Token方式。
  2. 對於相應的配置我們需要注意的三個點就是,有哪些使用者(users)可以通過哪些客戶端(clents)來訪問我們的哪些API保護資源 (API)。
  3. 在後續會對其中的授權模式,資料庫持久化問題,以及如何應用在API資源伺服器中和配置在客戶端中,會進一步說明。
  4. 如果有不對的或不理解的地方,希望大家可以多多指正,提出問題,一起討論,不斷學習,共同進步。
  5. 專案地址

八、資料

IdentityServer4官方文件

IdentiytServer4模板

IdentityServer4介面