Asp.Net Core 中IdentityServer4 授權原理及刷新Token的應用

来源:https://www.cnblogs.com/jlion/archive/2020/03/19/12501195.html
-Advertisement-
Play Games

客戶端請求Api資源網關(受保護的資源)時,第一次收到請求會到授權中心(ids4服務網關)獲取驗證公鑰,並保持到記憶體中,後面的請求不會再到授權中心去獲得驗證公鑰,而是Api資源網關(受保護的資源)中直接通過保存下來的驗證公鑰進行驗證,從而通過授權 ...


一、前言

上面分享了IdentityServer4 兩篇系列文章,核心主題主要是密碼授權模式自定義授權模式,但是僅僅是分享了這兩種模式的使用,這篇文章進一步來分享IdentityServer4的授權流程及refreshtoken

系列文章目錄(沒看過的先看這幾篇文章再來閱讀本文章):

為了繼續保持IdentityServer4 系列博客分享上下文一致,我這裡再把上回授權中心拆分後的圖貼出來,如圖:

圖中的授權中心就是通過IdentityServer4實現的授權服務中心,我下麵就直接用授權中心代替IdentityServer4的授權服務來繼續述說,也感謝大家對我的支持,一直閱讀我的文章。

二、授權流程

2.1 客戶端驗證流程圖

流程圖中,客戶端僅僅會到授權中心 請求一次,並拿到驗證公鑰返回給Api資源擁有端,後面客戶端再次嘗試請求Api資源時候就不會再到授權中心去獲取驗證公鑰,會直接用之前獲取到的公鑰進行驗證,驗證通過則授權通過。

2.2 授權及刷新refresh_token 流程圖

然而通過授權中心 獲取到的access_token 是有有效時間的,如果失效則需要通過refresh_token 重新到授權中心去刷新獲取最新的access_token,整體的流程圖如下:

客戶端攜帶上一次獲取到的access_token 請求受保護的Api資源時,通過公鑰進行驗證時發現access_token已經過期,則客戶端再攜帶refresh_token授權中心再次發起請求,刷新access_token以獲得最新的access_tokenrefresh_token,用最新的access_token 去獲取受保護的Api資源,這樣可以減少客戶端多次跳轉登錄授權頁面,提高用戶體驗。

三、應用實戰

說到例子,我這裡不從零開始擼代碼, 還是在之前的代碼基礎上繼續改造代碼,在原有的定義客戶端的代碼中新增刷新access_token的相關配置,代碼如下:

public static IEnumerable<Client> GetClients()
{
     return new List<Client>
     {
         new Client()
         {
             ClientId =OAuthConfig.UserApi.ClientId,
             AllowedGrantTypes = new List<string>()
             {
                 GrantTypes.ResourceOwnerPassword.FirstOrDefault(),//Resource Owner Password模式
                 GrantTypeConstants.ResourceWeixinOpen,
             },
             ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) },
             AllowOfflineAccess = true,//如果要獲取refresh_tokens ,必須把AllowOfflineAccess設置為true
             AllowedScopes= {
                 OAuthConfig.UserApi.ApiName,
                 StandardScopes.OfflineAccess,
             },
             AccessTokenLifetime = OAuthConfig.ExpireIn,
         },

      };
 }

如果你需要刷新access_token,則需要把AllowOfflineAccess設置true,同時添加StandardScopes.OfflineAccess 這個Scopes,主要代碼如下:

AllowOfflineAccess = true,//如果要獲取refresh_tokens ,必須把AllowOfflineAccess設置為true
AllowedScopes= {
     OAuthConfig.UserApi.ApiName,
     StandardScopes.OfflineAccess,//如果要獲取refresh_tokens ,必須在scopes中加上OfflineAccess
},

授權中心,完整代碼如下:

OAuthMemoryData 代碼如下:

/// <summary>
/// 
/// </summary>
public class OAuthMemoryData
{
        /// <summary>
        /// 資源
        /// </summary>
        /// <returns></returns>
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource(OAuthConfig.UserApi.ApiName,OAuthConfig.UserApi.ApiName),
            };
        }

        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                new Client()
                {
                    ClientId =OAuthConfig.UserApi.ClientId,
                    AllowedGrantTypes = new List<string>()
                    {
                        GrantTypes.ResourceOwnerPassword.FirstOrDefault(),//Resource Owner Password模式
                        GrantTypeConstants.ResourceWeixinOpen,
                    },
                    ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) },
                    AllowOfflineAccess = true,//如果要獲取refresh_tokens ,必須把AllowOfflineAccess設置為true
                    AllowedScopes= {
                        OAuthConfig.UserApi.ApiName,
                        StandardScopes.OfflineAccess,
                    },
                    AccessTokenLifetime = OAuthConfig.ExpireIn,
                },

            };
        }

        /// <summary>
        /// 測試的賬號和密碼
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser>
            {
                new TestUser()
                {
                     SubjectId = "1",
                     Username = "test",
                     Password = "123456"
                },
            };
        }

        /// <summary>
        /// 微信openId 的測試用戶
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetWeiXinOpenIdTestUsers()
        {
            return new List<TestUser>
            {
                new TestUser(){
                  SubjectId="owerhwroogs3902openId",
                }
            };
        }
    }

Startup 完整代碼如下:

 public class Startup
 {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            #region 記憶體方式
            //services.AddIdentityServer()
            //    .AddDeveloperSigningCredential()
            //    .AddInMemoryApiResources(OAuthMemoryData.GetApiResources())
            //    .AddInMemoryClients(OAuthMemoryData.GetClients())
            //    .AddTestUsers(OAuthMemoryData.GetTestUsers());
            #endregion

            #region 資料庫存儲方式
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(OAuthMemoryData.GetApiResources())
                //.AddInMemoryClients(OAuthMemoryData.GetClients())
                .AddClientStore<ClientStore>()
                .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
                .AddExtensionGrantValidator<WeiXinOpenGrantValidator>();//添加微信端自定義方式的驗證
            #endregion
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseIdentityServer();

            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

授權中心代碼基本上已經改造完成,我們用postman 訪問授權中心 試一試,如下圖:

訪問結果中已經包含了refresh_tokenaccess_token等相關信息。

我們再來通過access_token 訪問Api資源(上兩篇有相關代碼,未閱讀上兩篇先去查閱)這裡我就直接攜帶access_token去訪問,如圖:

訪問成功!!

我們再來刷新下refresh_token ,訪問如圖:

刷新refresh_token成功。
我們到這裡再來做一個小小的測試,測試上面的授權流程中的,第4,5 步,上面說到第4步主要是客戶端第一次請求Api資源時會向ids4服務網關去請求獲取驗證公鑰,
獲取成功返回給Api資源並存儲在記憶體中,後續不再會到ids4服務去獲取驗證公鑰

我們把上面的授權中心 (ids4服務網關)停止運行,再來用之前的access_token請求Api資源,如下圖:

現在已經確定授權中心(ids4服務網關)確實停止了,不能訪問了,那我們再來通過之前未過期的access_token來請求Api資源網關,結果如下圖:

完美,請求還是成功,這完全證明:客戶端請求Api資源網關(受保護的資源)時,第一次收到請求會到授權中心(ids4服務網關)獲取驗證公鑰,並保持到記憶體中,後面的請求不會再到授權中心去獲得驗證公鑰,而是Api資源網關(受保護的資源)中直接通過保存下來的驗證公鑰進行驗證,從而通過授權


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基於 Roslyn 實現一個簡單的條件解析引擎 Intro 最近在做一個勛章的服務,我們想定義一些勛章的獲取條件,滿足條件之後就給用戶頒發一個勛章,定義條件的時候會定義需要哪些參數,參數的類型,獲取勛章的時候會提供鎖需要的參數,有一些內置的參數,內置的參數解析器(ParamResolver)。 最後 ...
  • 作業:輸入某年某月某日,判斷這一天是這一年的第幾天?。要求:需寫一個函數,給定年月 日,求的該天處於該年的第幾天。然後在Main函數中測試。 思路: ①需要有兩個函數。一個主函數,一個Date函數用來計算天數。 ②在主函數裡面利用控制台輸入年月日,然後在調用Date函數. 由於調用函數了就傳值了,調 ...
  • asp.net core應用常常要通過nginx來反向代理, 普通的web api配置asp.net core反向代理比較常見, 如果在應用中集成了signalr, 如何使用nginx來反代呢? ...
  • 使用UUID或者GUID產生的ID沒有規則 Snowflake演算法是Twitter的工程師為實現遞增而不重覆的ID實現的 概述 分散式系統中,有一些需要使用全局唯一ID的場景,這種時候為了防止ID衝突可以使用36位的UUID,但是UUID有一些缺點,首先他相對比較長,另外UUID一般是無序的。有些時 ...
  • 帶著問題去思考!大家好。 修飾符 修飾符有什麼作用呢?它是什麼東西呢? 首先修飾符有四種 private[ˈpraɪvət] protected [prə'tektɪd] internal [ɪnˈtɜːnl] public [ˈpʌblɪk] 他們的特效依次是: private 修飾符用於設置類或 ...
  • Humanizer 能夠滿足您所有.Net關於操作和展示以下類型的需求,包括字元串、枚舉、日期、時間、時間跨度、數字和數量。它採用 MIT 進行授權分發。 ...
  • using System.Security.Cryptography; static void Main(string[] args) { string rawString = "Make every second count."; string encryptedString = Encrypt3 ...
  • 近期公司重構了些界面,因為換膚和界面定製的緣故,需要把樣式和邏輯分開;所以記錄下關鍵的操作;主要是利用命令代替事件... 1 <Window x:Class="Demo_MVVM.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...