前言
哈嘍~~~ 大家周一好!夏天到了,大家舒服了沒有,熟話說,打敗你的不是天真,是天真熱!??
過去的一周里,發生了兩件事跟大家分享下:
①、有兩個小伙伴給我提供了 Working Online 的工作,簡單說了說,感覺應該不太適合,至少我不適合,前期雙方試探的成分太多了,我是不喜歡,同時也建議正在找OnLine工作的小伙伴需多多考慮可行性。
②、我決定開始《微講堂》了,具體可以參考右側公告欄,因為有些基礎比較薄弱的小伙伴,單單提供思路還是無法入門,所以提供在線手把手教學吧,這個我是完全無所謂,看你心情吧。
這幾天通過晚上對 IdentityServer4 的學習和研究,發現這個就是一個“大坑”(不是說功能不好,是里邊有很多很多的內容需要學習),之前看官網, 關于 IdentityServer4 的教程,洋洋灑灑就過去了,感覺還挺簡單,發現要真是落地到項目里了,自我感覺又有了壓迫感,文末結語中,我簡單的說了幾點問題,大家可以慢慢往下走,不過知識嘛,無外乎就是自己開心學習 和 自己學習掙錢,這兩個心理,加油吧。
當然平時工作之余,還是要照顧下前后端分離項目的一些東西的,基礎不能丟,主要是三塊地方做了修改,這里簡單的列一下,就不單獨的寫文章了,希望一直在看第一個項目的小伙伴,有緣可以看到吧,不過,就算是看不到也沒事兒,遇到了自然就知道了:
1、Blog.Vue 首頁的閃屏處理;// 知名博主@張飛洪提出的問題,不知道我是否修改對了;http://core-dotnet.com:8077
2、Blog.Admin 后臺框架調整優化;// ①登錄頁樣式改版,②Tabs 導航條優化,③兼容手機屏幕等;http://core-dotnet.com:2364
3、Blog.Core 后端項目增加 Wiki 頁;// 為了讓剛接觸框架的小伙伴能快速一覽,特地在 Github 上,創建了 Wiki ,只不過現在才打了個目錄,內容慢慢填,如果還有其他的不足之處,歡迎提建議;https://github.com/anjoy8/Blog.Core/wiki
image
突然轉話題,上次咱們第一次對項目進行持久化操作《三║ 詳解授權持久化 & 用戶數據遷移》,不知道小伙伴都看了多少,這里再把幾個重要問題提一下,希望不要忘記了才好:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">1、Ids4 一共用到了幾個上下文,分別的用處是什么? 2、在遷移中,數據庫生成了多少表,各個模塊又是干什么的? 3、Ids4 的良好擴展性,體現在哪里?豐富性又體現在哪里? 4、ApplicationUser 類是起到什么作用的?</pre>
如果腦子里有些東西,那就恭喜了,如果第一次看,或者完全不知道我在說什么的話,請看上一集,今天會說說我在研究遇到的兩個 Flag ??,也就是兩個問題,希望有心的小伙伴,可以幫忙思考下,歡迎找我討論,廢話不多說,開車,馬上講解今天的內容!????
零、今天要實現綠色的部分
(知識結構圖,注意這是我自己的講解結構,和Ids4知識圖解無關)
一、用戶數據處理 —— Identity
咱們在上篇文章中,簡單的將 IdentityServer4 的結構進行持久化處理,并把前后端項目中的用戶數據進行遷移處理,最后修改了登錄頁的樣式,基本滿足了登錄和登出的操作,作為一個授權服務中心,僅僅只有登錄是完全解決不了什么問題的,至少應該對用戶數據進行常規操作處理,比如 CURD 等基礎操作。
正好,我們使用了 NetCore 自帶的 Identity 機制,可以幫助我們做一部分工作,因為它自己也封裝了一些方法,我們可以根據他們的方法,實當的做些擴展,從而達到相應的目的,具體有哪些操作,請往下看:
1、用戶數據展示(有權限)
既然有數據處理,肯定得有展示出來,當然,這個不是一定的,只是做下處理,如果你擔心會有數據安全問題的話,要么不顯示數據,要么只顯示無關痛癢的兩列,甚至可以直接加上權限,只有超級管理員或者技術人員可以看到就行。我這里僅僅是加了個登錄權限,只有登錄的用戶才能看的到:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">// 注入用戶管理
private readonly UserManager<ApplicationUser> _userManager;
[HttpGet]
[Route("account/users")]
[Authorize]//可以自定義規則 public IActionResult Users(string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl; var users = _userManager.Users.Where(d => !d.tdIsDelete).OrderBy(d => d.UserName).ToList();//Identity 已經對內部的一些方法做了封裝,直接使用即可,如果你對 Net 自帶的 Identity 使用過的話,應該很容易上手。
return View(users);
}</pre>
注意下上邊的紅色標注的地方,下文會說到為啥這里用到了 isDelete 。
我們簡單的對 User 頁面做了授權處理,必須登錄狀態下才能有權訪問,如果是沒有登錄,會直接跳轉到登錄頁面:
(帶權限的用戶展示頁)
2、注冊
關于注冊其實我們之前已經說過了,為什么呢,因為我們在之前導入用戶數據的時候,就已經用到了這個方法,只不過這里單拎出來了,但是這里有一個問題需要我們好好的思考思考,那就是角色的獲取!這里就是我下邊要說的第一個“Flag”??,為什么重要呢,不知道現在讀的你是否使用過 IdentityServer4 ,我也這幾天在考慮這個問題,授權中心肯定需要有用戶管理的,那很自然的,就會出現 “ 區分控制 ” 的問題,這里簡單說下會出現的兩個情況:
1、前臺展示項目:如果我們的vue 項目,是一個前臺網站,比如 電商類 的或者 Blog.Vue 這樣的,很簡單,我們只需要在 api 上加上 [Authorize] 這個無具體規則的授權特性就行,大家先不要往下看,先停一分鐘想一想是不是這個情況。商城嘛,只需要用戶登錄一下就可以購買了,我們不需要特地的區分商城用戶有什么區別,有什么三六九等,大家都是一樣,登錄了,就可以任何操作,無論是買東西,還是寫文章,亦或者投票等等;
2、后臺管理項目:但是!還有另一種情況,那就是后臺管理,一個對用戶身份要求特別嚴格的一個系統,我們肯定不能僅僅在 api 接口地址上,加上 [Authorize] 這個簡單的特性就完事兒了,就比如我們的 Blog.Admin 項目,肯定需要一套復雜的授權策略機制,那就不得不用到用戶的角色信息,或者其他的模塊信息,這就是我上邊說的 “區分控制”;(至于是基于角色的策略,還是模塊化,我還在考慮中,目前先嘗試角色管理)
3、猜想:你是不是想說使用基于角色+策略授權的** Hybrid Flow 混合模式**?別著急,以后的問題會說到,這里提出這個問題,就是向給大家一個思路的過程。
如果是第二種情況的話,我們在用戶注冊的時候,就需要帶上 “角色” 這個信息,比如我這里先默認是一個 test 系統測試管理員的角色(這個暫時這么處理,后期我會再深入研究下,是不是這個模式,或者如果正再看的你很懂的話,歡迎指導下,不勝感激!),當然,如果你的項目不需要對用戶的權限進行劃分,就比如我上邊的第一種情況,電商類,博客類,只要不是后臺管理這種的前臺系統,都很簡單,只需要在 api 上加上 [Authorize] ,然后授權中心是不需要角色這個概念的。
我們學術討論嘛,當然是從復雜的著手,就把角色給考慮進去了,現在先寫死一個角色,我們以后的文章中會進一步討論這個復雜的情況:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;"> [HttpPost]
[Route("account/register")]
[ValidateAntiForgeryToken] public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null, string rName = "AdminTest")
{
ViewData["ReturnUrl"] = returnUrl;
IdentityResult result = new IdentityResult(); // 模型校驗
if (ModelState.IsValid)
{ // 判斷用戶名是否存在,說明:如果是DDD設計思想,這中查重應該是寫在領域模型的。
var userItem = _userManager.FindByNameAsync(model.LoginName).Result; if (userItem == null)
{ // 轉成我們的實體模型,說明:這種多個實體轉換,可以使用 Dto
var user = new ApplicationUser
{
Email = model.Email,
UserName = model.LoginName,
LoginName = model.RealName,
sex = model.Sex,
age = model.Birth.Year - DateTime.Now.Year,
birth = model.Birth,
addr = "",
tdIsDelete = false }; // 創建用戶,注意密碼的規范,比如必須有大小寫字母+數字+符號
result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded)
{ // 用戶添加成功后,就需要添加聲明了,看自己需要多少吧,可以自定義擴展
result = await _userManager.AddClaimsAsync(user, new Claim[]{ // 這個 Name ,就是 Jwt 的唯一名字,也是頁面里展示的名稱,比如是“測試賬號”,而不是登錄名的“test1”
new Claim(JwtClaimTypes.Name, model.RealName), new Claim(JwtClaimTypes.Email, model.Email), // 是否需要進行 Email 郵件驗證
new Claim(JwtClaimTypes.EmailVerified, "false", ClaimValueTypes.Boolean), // 這里就是角色聲明
new Claim(JwtClaimTypes.Role, rName)
}); if (result.Succeeded)
{ // 添加成功,可以直接登錄,這個就比如是我們的博客項目或者電商項目,我們在授權中心注冊成功后,直接登錄了,跳轉到前臺了。 //await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
}
} else {
ModelState.AddModelError(string.Empty, $"{userItem?.UserName} already exists");
} // 收集全部異常數據,返回前臺
AddErrors(result);
} return View(model);
}</pre>
上邊的就是注冊的主要代碼,大家可以自己任意的擴展,然后重要的部分,我已經標紅,也寫上了詳細的注釋,特別簡單,都能看懂。
這一 Part 都很平常,最重要的一個問題還是那個角色這一塊,希望讀到這里的都能看懂,想一想到底你的項目里需不需要這樣的 Claim,不懂的歡迎來討論。
3、更新 與 邏輯刪除(有權限)
上邊咱們說到了展示和添加,那下邊就是說到更新了(這個操作我帶上了最高的權限,必須是超級管理員才能操作 [Authorize(Roles = "SuperAdmin")] ),你會問,為啥要把刪除和更新放到一起呢?其實我個人感覺邏輯是一樣的,平時開發肯定也都知道,邏輯刪除其實就是把“是否刪除” 這個字段設置成 True 就行了,但是真的是這樣么,我們慢慢往下看。
首先更新用戶這個很簡單的,我就不多說什么了,具體的可以看看代碼,主要的邏輯就是平時的三步走:
1、查詢出當前人Model;
2、用視圖模型修改Model;
3、執行更新操作 _userManager.UpdateAsync(userItem); // 這里要說下就是,Identity 自帶了很多擴展方法,大家需要自己好好的研究下,從而達到自己的相應目的。
更新說完了,下邊說說刪除,刪除其實本身就有兩種情況:
1、邏輯刪除,很自然,就是將數據更新下狀態,比如我們可以用上邊的方法,把當前操作人的 IsDeleted=True 即可,很簡單;
2、物理刪除,這個還是需要好好研究研究,我在官方的代碼里,沒有找到如何物理刪除的方法,可能還是需要開發者自己定義擴展吧;
這就是我說的第二個 “Flag”?? ,需要好好的思考思考,如果你已經忘了第一個 Flag 的話,請向上看,用戶注冊章節里的角色問題。
(更新 & 刪除 有權限 動圖)
4、重置密碼
這個是目前為止稍微復雜一點的,需用用到流程,首先看動圖吧:
(重置/更新密碼 動圖)
這個過程其實很簡單,也是項目中必須使用到的功能,我相信任何一個網站,必須要用到這個重置和找回密碼的功能吧,當然生產環境很復雜,可能需要郵箱或者手機等來處理動態鏈接,我這里只是提供一個思路,總結來說,流程說明如下:
1、輸入當時注冊郵箱;
2、獲取包含動態 Code 的安全鏈接(可通過發郵件的形式);
3、根據安全鏈接,設置新密碼;
4、重新登錄;
核心代碼(節選):
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">// 1、判斷郵箱
var user = await _userManager.FindByEmailAsync(model.Email); // 2、生成重置密碼回調鏈接
var code = await _userManager.GeneratePasswordResetTokenAsync(user); var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, code, Request.Scheme); var ResetPassword = $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>"; // 3、重置密碼
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);</pre>
5、其他情況處理?
通過上邊的簡單說明,AccountController 這個控制器的內容, 咱們說完了,是不是就沒有問題了呢,不是!我們要研究,就要研究透徹,大家肯定注意到了這個項目中,基本都說到了,但是在核心的快速啟動文件夾 Quickstart 中,還有幾個控制器沒有說到:
不光如此,在平時的開發中,我們還會遇到下邊這幾個業務邏輯操作:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">1、如何找回注冊郵箱? 2、如何通過發送郵件,從而達到郵件確認的目的? 3、如何實現FaceBook、Google登錄? 4、如何更新用戶的角色等Claims?
5、如何刷新 Token ?</pre>
上邊紅框中的那幾個控制器都是什么意思?
下邊四條業務邏輯又該如何實現?
當前項目是不是還有其他不為我們知道的秘密?以后的章節再慢慢展開,請關注。
不過我們既然已經完成用戶的基本操作,我們就先停下上邊的疑惑問題,往下走走,看看 IdentityServer4 到底是如何通過 OpenID Connect 來操作的。
二、簡單授權模式 —— Implicit Flow OpenID
0、OpenID Connect授權模式
OPID 認證流程主要是由 OAuth2 的五種授權流程延伸而來的,它有以下 3 種:
- Authorization Code Flow(授權碼模式):基于OAuth2的授權碼來換取Id Token和Access Token。
- Implicit Flow(簡化模式):基于OAuth2的Implicit流程獲取Id Token和Access Token。
- Hybrid Flow:混合Authorization Code Flow+Implici Flow獲取Id Token和Access Token。
注:OpenID Connect 為什么沒有基于OAuth2的Resource Owner Password Credentials Grant和Client Credentials Grant擴展,Resource Owner Password Credentials Grant是需要應用提供賬號密碼的,賬號密碼都有了在獲取Id Token意義不大。Client Credentials Grant沒有用戶的參與所以獲取Id Token 也沒意義。這也能反映授權和認證的差異,以及只使用OAuth2來做身份認證的事情是遠遠不夠的,也是不合適的。
1、概念
簡化模式用于獲取訪問令牌(但它不支持令牌的刷新,之所以所以稱為簡化模式,和授權碼模式比少了獲取授權碼的步驟),并對運行特定重定向URI的公共客戶端進行優化,而這一些列操作通常會使用腳本語言在瀏覽器中完成,令牌對訪問者是可見的,且客戶端也不需要驗證。
簡化模式,主要有下邊三個特點:
1、用于“公共”客戶端;
2、客戶端應用直接從瀏覽器訪問資源;
3、沒有顯式的客戶端身份認證;
2、結構圖
為了配合大家理解,我這里有兩個場景,大家腦子里先有個畫面,然后往下看四個角色和流程圖:
場景一:博客園登錄,需要獲取騰訊的某一個QQ用戶的頭像和昵稱等資源;
場景二:前后端分離,Vue 項目需要獲取 Core 項目的 當前test1賬號的 數據;
首先先理解下四個角色:
1、Resource Owner(資源擁有者) —— 資源所有者,就比如我們授權登錄中的,QQ用戶,他才是資源的擁有者。3143422472 /** test1賬號**
2、Resource Server(資源服務器) —— 資源服務器,用來存儲用戶資源(頭像,昵稱等)的服務器,比如騰訊QQ。騰訊QQ服務器 / Blog.Core
3、Client(客戶端) —— 第三方客戶端,比如博客園;https://www.cnblogs.com /** Blog.Vue**
4、Authorization Server(授權服務器)—— 授權服務器,用來作為認證第三方平臺的服務,比如騰訊的QQ互聯平臺。https://graph.qq.com/oauth2.0/show?whic...... / Blog.Idp
然后咱們看看具體的流程是怎樣的:
(流程1:參考網上畫的,可能不是很明了)
(流程2:自己根據官網圖片做了下修改)
Tips:Web-Hosted Client Resource 服務器相當于是一個存儲 accessToken 的地方,通常指瀏覽器中的存儲(cookie、localStorage、SessionStorge、js變量等),一般這個頁面是看不到的,而且一般情況是和 Client 客戶端寫在一起的,當然也有分開的。
步驟解析:
客戶端攜帶客戶端標識以及重定向URI到授權服務器;
用戶確認是否要授權給客戶端;
授權服務器得到許可后,跳轉到指定的重定向地址,并將令牌也包含在了里面;
客戶端不攜帶上次獲取到的包含令牌的片段,去請求資源服務器;
資源服務器會向瀏覽器返回一個腳本;
瀏覽器會根據上一步返回的腳本,去提取在C步驟中獲取到的令牌;
瀏覽器將令牌推送給客戶端。
(A步驟)中需要用到的參數,注意在這里要使用"application/x-www-form-urlencoded"格式:
response_type 必選項,此值必須為"token"
client_id 必選項
redirect_uri 可選項
scope 可選項
-
state 建議選項
例如:
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
(C步驟)中返回的參數包含:
access_token 必選項
token_type 必選項
expires_in 建議選項
scope 可選項
-
state 必選項
例如:
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
上邊我們簡單的說了說 Implicit Flow 模式的相關知識點,不知道大家有沒有一點點感覺,如果不是很懂,正好感覺配合著下邊的代碼研究下,二者結合會更好。
三、前后端項目授權聯調
因為我們用到了前后端分離項目,所以一定是要三方處理,如果你現在使用的是 MVC 模式的話,我們以后的章節也會說到 授權碼授權模式(Authorization Code Flow),這里先把簡化模式調通了:
1、授權服務端 —— Implicit(Blog.Idp)
這個配置很簡單,在 Blog.Idp 項目中,大家別看是在 Config.cs 文件里,其實它已經在我們上一篇文章中,生成到了數據庫中,不懂的請回看上一篇文章
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;"> new Client {
ClientId = "blogvuejs",//客戶端id
ClientName = "Blog.Vue JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:6688/callback" },//回調頁面
PostLogoutRedirectUris = { "http://localhost:6688" },
AllowedCorsOrigins = { "http://localhost:6688" },
// 允許的前端獲取的作用域
AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile, "roles", "blog.core.api" }
}</pre>
2、資源服務端 —— Bearer(Blog.Core)
這里的配置是在 Blog.Core 我們的資源服務器中,在啟動文件 Startup.cs 中,大家自行查看,注意如果使用這個的話,請把 Jwt 認證給注釋掉:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options => {
options.Authority = "http://localhost:5002";//授權服務器地址
options.RequireHttpsMetadata = false;//是否Https
options.ApiName = "blog.core.api";//我們在 Blog.Idp 中配置的資源服務器名
});</pre>
添加過程中,可能會需要引用擴展包 : IdentityServer4.AccessTokenValidation 這都是小問題,大家自行檢查即可。
3、請求客戶端 —— Oidc(Blog.Vue)
上邊我們已經在兩個服務端做好了配置,客戶端如何處理,這個地方才是今天的重頭戲,無論是什么客戶端,JS 或者 Vue、React、Ng 等等前端框架,都需要用到 oidc-client 這個插件庫:
1、安裝
執行命令:npm install oidc-client --save
2、封裝
注意這個是一個js庫,我們就像之前將 SignalR 那樣,直接使用就行,不用在 main.js 中引用,但是還是需要先實例化一個用戶管理類 ApplicationUserManager 并配置構造函數,請注意這些參數都要和 Blog.Idp 授權服務器配置一致。
在 src 文件夾下 新建 Auth 文件夾,并添加 applicationusermanager.js 來封裝我們的連接管理:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">import { UserManager } from 'oidc-client'
class ApplicationUserManager extends UserManager {
constructor () {
super({
authority: 'http://localhost:5002',// 授權服務中心地址
client_id: 'blogvuejs',// 客戶端 id
redirect_uri: 'http://localhost:6688/callback',// 登錄回調地址
response_type: 'id_token token',
scope: 'openid profile roles blog.core.api',// 作用域也要一一匹配
post_logout_redirect_uri: 'http://localhost:6688' //登出后回調地址 })
} async login () { await this.signinRedirect() return this.getUser()
} async logout () { return this.signoutRedirect()
}
}</pre>
同時為了配合其他頁面使用,我們封裝幾個常用的方法,在 Auth 文件夾下,新建 UserAuth.js 來封裝用戶的一些基本信息:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">import applicationUserManager from "./applicationusermanager"; const userAuth = {
data() { return {
user: {
name: "",
isAuthenticated: false }
};
},
methods: { async refreshUserInfo() {//獲取用戶信息 const user = await applicationUserManager.getUser(); if (user) { this.user.name = user.profile.name; this.user.isAuthenticated = true;
} else { this.user.name = ""; this.user.isAuthenticated = false;
}
}
}, async created() { await this.refreshUserInfo();
}
};
export default userAuth;</pre>
3、發起 登錄/登出 請求
我們封裝好了方法,下邊就是直接設計業務邏輯了,過程很簡單,在 App.vue 組件中:
1、每次路由跳轉需異步獲取用戶數據;
2、發起異步登錄請求;
3、發起異步登出請求;
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">import applicationUserManager from "./Auth/applicationusermanager";
import userAuth from "./Auth/UserAuth";
export default {
name: "app",
mixins: [userAuth],
data: function() { return {};
},
watch: {
root.
store.commit("saveToken", "");
} catch (error) {
console.log(error); this.emit("show-snackbar", { message: error });
}
}
}
};</pre>
4、回調
在上邊的用戶管理配置中,我們用到了一個回調頁面,這個很重要,因為我們在登錄成功后,需要調整到客戶端,并且需要將信息給存儲下來,就是上邊流程圖中,我們說到的 客戶端資源
具體怎么寫的,很簡單,在 views 視圖頁面文件夾下,新建一個 LoginCallbackView.vue 頁面:
<pre style="color: rgb(0, 0, 0); font-family: "Courier New"; font-size: 12px; margin: 5px 8px; padding: 5px;">import applicationUserManager from '../Auth/applicationusermanager' export default { async created () { try { // 核心的就是這里了
await applicationUserManager.signinRedirectCallback()
let user = await applicationUserManager.getUser() // 將 token 存儲在客戶端
this.router.push({name: 'home'})
} catch (e) {
console.log(e) this.emit('show-snackbar', { message: e })
}
}
}</pre>
四、結語
本文還是延續上篇文章的快速講解的風格,簡單連貫的把用戶管理和前后端聯調的內容通了一遍,總結一下:
1、分析了用戶是否需要角色等策略的緣由;
2、實現了對用戶的基本操作——CURD+重置密碼;
3、授權項目中還遺留了一片未知的知識塊,亟待探索;
4、實現了客戶端、資源服務器、授權服務器的第一次聯調;
5、重點講解了五大模式中的 Implicit Flow 簡化模式的概念和應用場景;
6、同時也把 Hybrid Flow 混合模式給引申出來,因為它基于 角色+策略 的授權;
當然,通過這一篇的學習,又開拓出了更多的未知領域,IdentityServer4 沒有我們想想的那么難,但是肯定也不是一個 Demo 就能說的完的簡單,
如何解決文章中提到的,打算提到的,未提到的各種問題呢,請持續關注吧。