Asp.Net Core 中IdentityServer4 授權中心之自定義授權模式
阿新 • • 發佈:2020-03-13
## 一、前言
上一篇我分享了一篇關於 [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