1. 程式人生 > >Asp.Net Core 中IdentityServer4 授權中心之自定義授權模式

Asp.Net Core 中IdentityServer4 授權中心之自定義授權模式

## 一、前言 上一篇我分享了一篇關於 [Asp.Net Core 中IdentityServer4 授權中心之應用實戰](https://www.cnblogs.com/jlion/p/12447081.html) 的文章,其中有不少博友給我提了問題,其中有一個博友問我的一個場景,我給他解答的還不夠完美,之後我經過自己的學習查閱並閱讀了相關原始碼,發現 `IdentityServer4` 可以實現自定義`GrantType` 授權方式。 *宣告*:看這篇文章時如果你沒有閱讀我上一篇 [Asp.Net Core 中IdentityServer4 授權中心之應用實戰](https://www.cnblogs.com/jlion/p/12447081.html) 的文章,那請先移步看上面的文章,再來看這篇文章會更加清晰,感謝支援,感謝關注! ## 二、場景模擬 上篇文章已經把電商系統從單一閘道器架構升級到多閘道器架構,架構圖如下: ![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200310111100212-1434441217.png) 然而上面的`授權中心` 使用的是`密碼授權模式`,但是對於`微信小程式`、`微信公眾號商城`端使用的授權還不是很合適; `微信小程式`和`微信公眾號`微商城客戶端的場景如下: 使用者訪問小程式商城或者微信公眾號商城後會到`微信服務端`獲得授權拿到相關的使用者`openId`、`unionId`、`userName` 等相關資訊,再攜帶`openId`、`unionId`、`userName`等資訊訪問`授權中心`閘道器,進行授權,如果不存在則自動註冊使用者,如果存在則登入授權成功等操作。那這個場景後我該如何改造`授權中心`服務閘道器呢?經過研究和探討,我把上面的架構圖細化成如下的閘道器架構圖: ![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200312110224389-2025910734.png) ## 三、授權中心改造升級 上一篇文章中我們的解決方案中已經建立了三個專案: - `Jlion.NetCore.Identity.Service`:`授權中心` 閘道器 - `WebApi` 專案 - `Jlion.NetCore.Identity.UserApiService` :`使用者業務閘道器` -`WebApi`專案 - `Jlion.NetCore.Identity` :`基礎類庫`,主要用於把公共的基礎設施層放到這一塊 通過上面的需求場景分析,我們目前的`授權中心`還不夠這種需求,故我們可以通過`IdentityServer4` 自定義授權方式進行改造升級來滿足上面的場景需求。 經過檢視原始碼我發現我們可以通過實現`IExtensionGrantValidator`抽象介面進行自定義授權方式來實現,並且實現`ValidateAsync` 方法, 現在我在之前的解決方案`授權中心`專案中新增`WeiXinOpenGrantValidator`類程式碼如下: ``` public class WeiXinOpenGrantValidator : IExtensionGrantValidator { public string GrantType => GrantTypeConstants.ResourceWeixinOpen; public async Task ValidateAsync(ExtensionGrantValidationContext context) { try { #region 引數獲取 var openId = context.Request.Raw[ParamConstants.OpenId]; var unionId = context.Request.Raw[ParamConstants.UnionId]; var userName = context.Request.Raw[ParamConstants.UserName]; #endregion #region 通過openId和unionId 引數來進行資料庫的相關驗證 var claimList = await ValidateUserAsync(openId, unionId); #endregion #region 授權通過 //授權通過返回 context.Result = new GrantValidationResult ( subject: openId, authenticationMethod: "custom", claims: claimList.ToArray() ); #endregion } catch (Exception ex) { context.Result = new GrantValidationResult() { IsError = true, Error = ex.Message }; } } #region Private Method /// /// 驗證使用者 ///
/// /// /// private async Task> ValidateUserAsync(string openId, string unionId) { //TODO 這裡可以通過openId 和unionId 來查詢使用者資訊(資料庫查詢), //我這裡為了方便測試還是直接寫測試的openId 相關資訊使用者 var user = OAuthMemoryData.GetWeiXinOpenIdTestUsers(); if (user == null) { //註冊使用者 } return new List() { new Claim(ClaimTypes.Name, $"{openId}"), }; } #endregion } ``` `GrantTypeConstants` 程式碼是靜態類,主要用於定義`GrantType`的自定義授權型別,可能後續還有更多的自定義授權方式所以,統一放這裡面進行管理,方便維護,程式碼如下: ``` public static class GrantTypeConstants { /// /// GrantType - 微信端授權 ///
public const string ResourceWeixinOpen = "weixinopen"; } ``` `ParamConstants` 類主要是定義自定義授權需要的引數,程式碼如下: ``` public class ParamConstants { public const string OpenId = "openid"; public const string UnionId = "unionid"; public const string UserName = "user_name"; } ``` 好了上面得自定義驗證器已經實現了,但是還不夠,我們還需要讓客戶端支援自定義的授權型別,我們開啟`OAuthMemoryData`程式碼中的`GetClients`,程式碼如下: ``` public static IEnumerable GetClients() { return new List { new Client() { ClientId =OAuthConfig.UserApi.ClientId, AllowedGrantTypes = new List() { GrantTypes.ResourceOwnerPassword.FirstOrDefault(),//Resource Owner Password模式 GrantTypeConstants.ResourceWeixinOpen,//新增的自定義微信客戶端的授權模式 }, ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) }, AllowedScopes= {OAuthConfig.UserApi.ApiName}, AccessTokenLifetime = OAuthConfig.ExpireIn, }, }; } ``` 客戶端`AllowedGrantTypes` 配置新增了我剛剛自定義的授權方式`GrantTypeConstants.ResourceWeixinOpen`, 現在客戶端的支援也已經配置好了,最後我們需要通過`AddExtensionGrantValidator<>`擴充套件方法把`自定義授權驗證器`註冊到`DI`中,程式碼如下: ``` public void ConfigureServices(IServiceCollection services) { services.AddControllers(); #region 資料庫儲存方式 services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(OAuthMemoryData.GetApiResources()) //.AddInMemoryClients(OAuthMemoryData.GetClients()) .AddClientStore() .AddResourceOwnerValidator() .AddExtensionGrantValidator(); #endregion } ``` 好了,簡單的`授權中心`程式碼升級已經完成,我們分別通過命令列執行`授權中心`和`使用者業務閘道器` ,之前的`使用者業務閘道器`無需改動任何程式碼,執行圖分別如下: > Jlion.NetCore.Identity.Server 授權中心執行如下 ![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200312121225481-1589130470.png) > Jlion.NetCore.Identity.UserApiServer 使用者業務閘道器執行如下 ![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200312121325942-1250590227.png) 我們現在用postman模擬`openId`、`unionId`、`userName`引數來請求`授權中心`獲得`AccessToken`,請求如下: ![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200312122031827-336835352.png) 我們再通過postman 攜帶授權資訊訪問`使用者業務閘道器`資料,結果圖如下: ![](https://img2020.cnblogs.com/blog/824291/202003/824291-20200312122209943-1033059972.png) 好了,自定義授權模式已經完成,簡單的`授權中心`也已經升級完成,上面`WeiXinOpenGrantValidator `驗證器中我沒有直接走資料庫方式進行驗證和註冊,簡單的寫了個Demo ,大家有興趣可以 把TODO那一快資料庫的操作去實現,程式碼我已經提交到 github上了,這裡再次分享下我部落格同步實戰的demo 地址 https://github.com/a312586670/IdentityServerDemo ## 四、思考與總結 本篇我介紹了自定義授權方式,通過檢視原始碼及查閱資料學習了`IdentityServer4` 可以通過`自定義授權`方式進行擴充套件。這樣`授權中心`可以擴充套件多套授權方式,比如今天所分享的 自定義微信openId 授權、簡訊驗證碼授權等其他自定義授權,一套`Api資源`可以兼併多套授權模式,靈活擴充套件,靈活升級。本篇涉及的知識點不多,但是非常重要,因為我們在使用`授權中心`統一身份認證時經常會遇到多種認證方式的結合,和多套不同應用使用者的使用,在掌握了授權原理後,就能在不同的授權方式中切換的遊刃有餘,到這裡有的博友會問`AccentToken` 有過期時間,會過期怎麼辦?難道要重新授權一次嗎?這些問題我會安排下一篇文章分享。 #### 靈魂一問: 上面的`授權中心` 例子主要是為了讓大家更好的理解自定義授權的使用場景及它的靈活性,真實的場景這樣直接把 `openId`等相關資訊來驗證授權安全嗎?大家可以可以思考下,如果不安全大家又有什麼好的解決方案呢?自我提升在於不停的自我思考,大家可以敬請的發揮自己的思考,把答案留在留言板中,以供大家參考學習,感謝