1. 程式人生 > >.NET Core微服務之基於IdentityServer建立授權與驗證服務

.NET Core微服務之基於IdentityServer建立授權與驗證服務

一、IdentityServer的預備知識

  要學習IdentityServer,事先得了解一下基於Token的驗證體系,這是一個龐大的主題,涉及到Token,OAuth&OpenID,JWT,協議規範等等等等,園子裡已經有很多介紹的文章了,個人覺得solenovex的這一篇文章《學習IdentityServer4的預備知識》言簡意賅,可以快速的看看。另外savaboard的《ASP.NET Core 之 Identity 入門(一)》和《ASP.NET Core 之 Identity 入門(二)》這兩篇也可以一看,對Claims和Identity的基本知識講的比較通俗易懂,深入淺出,有故事情節,哈哈。

  重點關注一下上面這張圖(也是來自solenovex的文章),對於一個User(已註冊)來說,他會首先向Authorization Server表明自己的身份(比如輸入使用者名稱和密碼),然後Authorization Server為其發放了一個token,而這個token就好比是把家裡的鑰匙配了一把(clone)新的,此後該User就可以訪問API請求獲取Orders(訂單)資料了。當然,實際中可能Authorization Server和API Server不在同一個區域內,它們可能只能遙望對方。此外,User還可以基於這個token去訪問第三方服務,第三方服務會使用這個API來訪問API Server,向其提供token比提供username&password要安全得多。

二、IdentityServer極簡介紹

  IdentityServer4(這裡只使用版本號為4)是一個基於OpenID Connect和OAuth 2.0的針對ASP.NET Core 2.0的框架。IdentityServer是將規範相容的OpenID Connect和OAuth 2.0終結點新增到任意ASP.NET Core應用程式的中介軟體。通常,你構建(或重新使用)包含登入和登出頁面的應用程式,IdentityServer中介軟體會向其新增必要的協議頭,以便客戶端應用程式可以使用這些標準協議與其對話。

  我們可以用IdentityServer來做啥?

  (1)身份驗證服務=>官方認證的OpenID Connect實現

  (2)單點登入/登出(SSO)

  (3)訪問受控的API=>為不同的客戶提供訪問API的令牌,比如:MVC網站、SPA、Mobile App等

  (4)等等等......

三、Started:第一個AuthorizationServer

1.1 建立一個ASP.NET Core空Web專案

  建立ASP.NET Core專案,使用Empty空模板。

  為了更好地檢視日誌資訊,同時考慮到IISExpress啟動起來真的很慢,修改lanuchSettings.json檔案如下:

{
  "profiles": {
    "Manulife.DNC.MSAD.IdentityServer4Test": {
      "commandName": "Project",
      "launchBrowser": false,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

1.2 安裝並配置IdentityServer4

  Step1.首先安裝IdentityServer4:

NuGet>Install-Package IdentityServer4  

  Step2.配置ASP.NET Core管道,即修改Configure方法

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();
    }

  Step3.為了要把IdentityServer註冊到容器中,需要對其進行配置,而這個配置中要包含三個資訊:

  (1)哪些API可以使用這個AuthorizationServer

  (2)哪些Client可以使用這個AuthorizationServer

  (3)哪些User可以被這個AuthrizationServer識別並授權

  這裡為了快速演示,我們寫一個基於記憶體的靜態類來快速填充上面這些資訊(實際中,可以持久化在資料庫中通過EF等ORM獲取,也可以通過Redis獲取):

    public class InMemoryConfiguration
    {
        public static IConfiguration Configuration { get; set; }
        /// <summary>
        /// Define which APIs will use this IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new[]
            {
                new ApiResource("clientservice", "CAS Client Service"),
                new ApiResource("productservice", "CAS Product Service"),
                new ApiResource("agentservice", "CAS Agent Service")
            };
        }

        /// <summary>
        /// Define which Apps will use thie IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients()
        {
            return new[]
            {
                new Client
                {
                    ClientId = "client.api.service",
                    ClientSecrets = new [] { new Secret("clientsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "clientservice" }
                },
                new Client
                {
                    ClientId = "product.api.service",
                    ClientSecrets = new [] { new Secret("productsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "clientservice", "productservice" }
                },
                new Client
                {
                    ClientId = "agent.api.service",
                    ClientSecrets = new [] { new Secret("agentsecret".Sha256()) },
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                    AllowedScopes = new [] { "agentservice", "clientservice", "productservice" }
                }
            };
        }

        /// <summary>
        /// Define which uses will use this IdentityServer
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<TestUser> GetUsers()
        {
            return new[]
            {
                new TestUser
                {
                    SubjectId = "10001",
                    Username = "[email protected]",
                    Password = "edisonpassword"
                },
                new TestUser
                {
                    SubjectId = "10002",
                    Username = "[email protected]",
                    Password = "andypassword"
                },
                new TestUser
                {
                    SubjectId = "10003",
                    Username = "[email protected]",
                    Password = "leopassword"
                }
            };
        }
    }

   Step4.對於Token簽名需要一對公鑰和私鑰,不過IdentityServer為開發者提供了一個AddDeveloperSigningCredential()方法,它會幫我們搞定這個事,並預設存到硬碟中。當切換到生產環境時,還是得使用正兒八經的證書,更換為使用AddSigningCredential()方法。

    public void ConfigureServices(IServiceCollection services)
    {
        InMemoryConfiguration.Configuration = this.Configuration;

        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddTestUsers(InMemoryConfiguration.GetUsers().ToList())
            .AddInMemoryClients(InMemoryConfiguration.GetClients())
            .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources());
    }

1.3 獲取你心心念唸的Token

  Step1.啟動剛剛我們建立的AuthorizationServer程式,這裡我們繫結的是5000埠。

  Step2.啟動Postman/SoapUI等API測試工具,通過向HTTP Body中填寫資料發起POST請求:

  

  

  Step3.傳送一個錯誤的資料,看看返回的是啥?(這裡輸入了一個不在定義列表中的client_id)

  

  Step4.檢視控制檯的日誌資訊:表示獲取Token的這個請求成功了,日誌中client_secret和password都是不會直接明文顯示的。

  

  Step5.IdentityServer中我們設定這幾個API Service的Grant_Type是ResourceOwnerPasswordAndClientCredentials(點選這裡瞭解=>資源擁有者密碼憑據許可),因此我們還可以使用ClientCredentials(點選這裡瞭解=>客戶端憑據許可),如下所示:

  

  Step6.再次檢視控制檯日誌資訊:這次沒有關於User相關的任何資訊顯示了。

  

  Step7.基本的開發結束,對於開發階段,我們使用IdentityServer為開發者提供的臨時證書即可,但是後面仍然需要生成一些正兒八經的證書。這裡我們通過OpenSSL來生成,首先去官網下載一個,這裡使用的是Win64_1.1版本。開啟Powershell或者CMD,輸入以下命令:

cmd>openssl req -newkey rsa:2048 -nodes -keyout cas.clientservice.key -x509 -days 365 -out cas.clientservice.cer

下面將生成的證書和Key封裝成一個檔案,以便IdentityServer可以使用它們去正確地簽名tokens

cmd>openssl pkcs12 -export -in cas.clientservice.cer -inkey cas.clientservice.key -out cas.clientservice.pfx

  中途會提示讓你輸入Export Password,這個password後面會用到,記住它。最終匯出後的結果如下圖所示:

  

  這裡我將其放到了專案結構資料夾中,並設定這個pfx檔案為“如果較新則複製”,確保可以在最後生成的目錄裡邊。現在就可以修改一下ConfigureServices()方法了:

    public void ConfigureServices(IServiceCollection services)
    {
        var basePath = PlatformServices.Default.Application.ApplicationBasePath;
        InMemoryConfiguration.Configuration = this.Configuration;

        services.AddIdentityServer()
            //.AddDeveloperSigningCredential()
            .AddSigningCredential(new X509Certificate2(Path.Combine(basePath,
                Configuration["Certificates:CerPath"]),
                Configuration["Certificates:Password"]))
          .AddTestUsers(InMemoryConfiguration.GetUsers().ToList())
          .AddInMemoryClients(InMemoryConfiguration.GetClients())
        .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources());
    }

  這裡我將證書的路徑和匯出密碼都寫到了配置檔案中:

{
  "Certificates": {
    "CerPath": "certificate\\cas.clientservice.pfx",
    "Password": "manulife"
  }
} 
View Code

  好,配置正兒八經的證書這一步驟Over。

四、IdentityServer QuickStart-UI

4.1 關於QuickStart UI

  複製完成後,我們的專案結構如下圖所示:

4.2 修改DI方法

  (1)使用MVC與靜態檔案(由於wwwroot下有很多靜態資原始檔)

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();
        // for QuickStart-UI
        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }

  (2)註冊MVC

    public void ConfigureServices(IServiceCollection services)
    {
        var basePath = PlatformServices.Default.Application.ApplicationBasePath;
        InMemoryConfiguration.Configuration = this.Configuration;

        services.AddIdentityServer()
            //.AddDeveloperSigningCredential()
            .AddSigningCredential(new X509Certificate2(Path.Combine(basePath,
                Configuration["Certificates:CerPath"]),
                Configuration["Certificates:Password"]))
          .AddTestUsers(InMemoryConfiguration.GetUsers().ToList())
          .AddInMemoryClients(InMemoryConfiguration.GetClients())
          .AddInMemoryApiResources(InMemoryConfiguration.GetApiResources());
        // for QuickStart-UI
        services.AddMvc();
    }

4.3 Run  

  (1)首頁(這裡由於我已經登入,所以這裡會把我的賬號顯示了出來)

  

  (2)Logout頁,剛剛說到我已經實現Login了,所以我這裡Logout一下

    

  (3)Login頁:這裡只能識別我們在之前配置的靜態User列表中那些User

  

  登入之後,顯示:"You have not given access to any applications",表示我們還沒有給他授予訪問任何API或網站模組的許可權。後續我們會建立API和MVC網站來演示如何對其進行授權和訪問。

  

五、小結

  本篇主要簡單的介紹了IdentityServer以及如何基於IdentityServer建立一個基本的AuthorizationServer,如何獲取Token,以及整合QuickStart UI實現基本的介面展示。後續還會建立API和MVC網站,來和IdentityServer進行整合,以演示如何對User授予訪問API和MVC網站的訪問許可權。

示例程式碼

參考資料

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

.NET Core服務基於IdentityServer建立授權驗證服務(續)

上一篇我們基於IdentityServer4建立了一個AuthorizationServer,並且繼承了QuickStartUI,能夠成功獲取Token了。這一篇我們瞭解下如何整合API Service和MVC Web Application。 一、整合API Service 1.1 新增ASP.NE

.NET Core服務基於IdentityServer建立授權驗證服務

一、IdentityServer的預備知識   要學習IdentityServer,事先得了解一下基於Token的驗證體系,這是一個龐大的主題,涉及到Token,OAuth&OpenID,JWT,協議規範等等等等,園子裡已經有很多介紹的文章了,個人覺得solenovex的這一篇文章《學習Id

.Net Core 認證系統基於Identity Server4 Token的JwtToken認證原始碼解析

介紹JwtToken認證之前,必須要掌握.Net Core認證系統的核心原理,如果你還不瞭解,請參考.Net Core 認證元件原始碼解析,且必須對jwt有基本的瞭解,如果不知道,請百度.最重要的是你還需要掌握identity server4的基本用法,關於identity server4因為設計到兩個協議O

.NET Core服務基於Ocelot+IdentityServer實現統一驗證授權

一、案例結構總覽  這裡,假設我們有兩個客戶端(一個Web網站,一個移動App),他們要使用系統

.NET Core服務基於Consul實現服務治理

請求轉發 1.0 asp.net AC port prefix 我們 tle nan 一、Consul基礎介紹   Consul是HashiCorp公司推出的開源工具,用於實現分布式系統的服務發現與配置。與其他分布式服務註冊與發現的方案,比如 Airbnb的Smart

.NET Core服務基於Consul實現服務治理(續)

shell pla code tst 分層 編輯 set req \n 上一篇發布之後,這一篇把上一篇沒有弄到的東西補一下,也算是給各位前來詢問的朋友的一些回復吧。一、Consul服務註冊之配置文件方式1.1 重溫Consul實驗集群  這裏我們有三個Consul Serv

基於Apollo實現.NET Core服務統一配置(測試環境-單機) .NET Core服務基於Apollo實現統一配置中心

一、前言 注:此篇只是為測試環境下的快速入門。後續會給大家帶來生產環境下得實戰開發。 具體的大家可以去看官方推薦。非常的簡單明瞭。以下介紹引用官方內容: Apollo(阿波羅)是攜程框架部門研發的分散式配置中心,能夠集中化管理應用不同環境、不同叢集的配置,配置修改後能夠實時推送到應用端,並且具

.NET Core服務基於Steeltoe使用Eureka實現服務註冊發現

一、關於Steeltoe與Spring Cloud    Steeltoe is an open source project that enables .NET developers to implement industry standard best practices when b

.NET Core服務基於Steeltoe整合Zuul實現統一API閘道器

一、關於Spring Cloud Zuul   API Gateway(API GW / API 閘道器),顧名思義,是出現在系統邊界上的一個面向API的、序列集中式的強管控服務,這裡的邊界是企業IT系統的邊界。   Zuul 是Netflix 提供的一個開源元件,致力於在雲平臺上提供動態路由,監

.NET Core服務基於Steeltoe使用Hystrix熔斷保護監控

一、關於Spring Cloud Hystrix      在微服務架構中,我們將系統拆分為很多個服務,各個服務之間通過註冊與訂閱的方式相互依賴,由於各個服務都是在各自的程序中執行,就有可能由於網路原因或者服務自身的問題導致呼叫故障或延遲,隨著服務的積壓,可能會導致服務崩潰。為了解決這一系列的問題

.NET Core服務基於Steeltoe使用Spring Cloud Config統一管理配置

一、關於Spring Cloud Config   在分散式系統中,每一個功能模組都能拆分成一個獨立的服務,一次請求的完成,可能會呼叫很多個服務協調來完成,為了方便服務配置檔案統一管理,更易於部署、維護,所以就需要分散式配置中心元件了,在Spring Cloud中,就有這麼一個分散式配置中心元件 —

NET Core服務路:自己動手實現Rpc服務框架,基於DotEasy.Rpc服務框架的介紹和整合

本篇內容屬於非實用性(拿來即用)介紹,如對框架設計沒興趣的朋友,請略過。   快一個月沒有寫博文了,最近忙著兩件事;    一:閱讀劉墉先生的《說話的魅力》,以一種微妙的,你我大家都會經常遇見的事物,來建議說話的“藝術和魅力”,對於我們從事軟體開發、不太善於溝通

NET Core服務路:自己動手實現Rpc服務框架,基於DotEasy.Rpc服務框架的介紹和整合...

本篇內容屬於非實用性(拿來即用)介紹,如對框架設計沒興趣的朋友,請略過。  快一個月沒有寫博文了,最近忙著兩件事;    一:閱讀劉墉先生的《說話的魅力》,以一種微妙的,你我大家都會經常遇見的事物,來建議說話的“藝術和魅力”,對於我們從事軟體開發、不太善

.NET Core服務基於Steeltoe使用Zipkin實現分散式追蹤

一、關於Spring Cloud Sleuth與Zipkin   在 SpringCloud 之中提供的 Sleuth 技術可以實現微服務的呼叫跟蹤,也就是說它可以自動的形成一個呼叫連線線,通過這個連線線使得開發者可以輕鬆的找到所有微服務間關係,同時也可以獲取微服務所耗費的時間, 這樣就可以進行微服

.NET Core服務基於Jenkins+Docker實現持續部署(Part 1)

一、CI, CD 與Jenkins   網際網路軟體的開發和釋出,已經形成了一套標準流程,最重要的組成部分就是持續整合(Continuous integration,簡稱 CI) => 持續整合指的是,頻繁地(一天多次)將程式碼整合到主幹。   它的好處主要有兩個: 快速發現錯

.NET Core服務基於App.Metrics+InfluxDB+Grafana實現統一效能監控

一、關於App.Metrics+InfluxDB+Grafana 1.1 App.Metrics      App.Metrics是一款開源的支援.NET Core的監控外掛,它還可以支援跑在.NET Framework上的應用程式(版本 >= 4.5.2)。官方文件地址:https://ww

.NET Core服務基於Apollo實現統一配置中心

一、關於統一配置中心與Apollo   在微服務架構環境中,專案中配置檔案比較繁雜,而且不同環境的不同配置修改相對頻繁,每次釋出都需要對應修改配置,如果配置出現錯誤,需要重新打包釋出,時間成本較高,因此需要做統一的配置中心,能做到自動更新配置檔案資訊,解決以上問題。   Apollo(阿波羅)是攜

.NET Core服務基於Ocelot實現API閘道器服務

一、啥是API閘道器?   API 閘道器一般放到微服務的最前端,並且要讓API 閘道器變成由應用所發起的每個請求的入口。這樣就可以明顯的簡化客戶端實現和微服務應用程式之間的溝通方式。以前的話,客戶端不得不去請求微服務A(假設為Customers),然後再到微服務B(假設為Orders),然後是微服

.NET Core服務基於Exceptionless實現分散式日誌記錄

一、Exceptionless極簡介紹   Exceptionless 是一個開源的實時的日誌收集框架,它可以應用在基於 ASP.NET,ASP.NET Core,Web API,Web Forms,WPF,Console,ASP.NET MVC 等技術開發的應用程式中,並且提供了REST介面可以應

.NET Core服務基於MassTransit實現資料最終一致性(Part 2)

一、案例結構與說明   在上一篇中,我們瞭解了MassTransit這個開源元件的基本用法,這一篇我們結合一個小案例來了解在ASP.NET Core中如何藉助MassTransit+Quartz.Net來實現資料的最終一致性。當然,實現資料的最終一致性有很多方案,這裡只是舉一種我所學到的比較簡單易於學習