前一篇 Identity Server 4 - Hybrid Flow - MVC用戶端身份驗證: https://www.cnblogs.com/cgzl/p/9253667.html
Claims
我不知道怎麼樣翻譯這個詞比較好, 是以我一般就不翻譯了.
在前一篇文章裡, MVC用戶端配置身份認證的時候有這麼一句話(Startup的ConfigureServices):
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
官方文檔是這樣介紹的: “我們關閉了JWT的Claim 類型映射, 以便允許well-known claims.”
如果我把這句話删掉, 然後再看看User.Claims的類型和值:
現在有些claim的類型與ID Token裡面的類型名稱是不一樣, 也有一些claim不見了:
而加上這句話之後, 現在User claim類型的名字就和ID Token裡面一樣了:
再看一下ID Token:
有一些claims并沒有出現在User.Claims裡面. 這是因為這個中間件預設情況下會過濾掉一些它認為我們不需要的claim, 例如nbf, amr等.
就先看下面這兩種情況吧:
1. 避免claims被預設過濾掉
如果我想讓中間件不要過濾掉nbf和, 也就是把nbf和amr從被過濾掉集合裡移除, 就可以使用這個方法:
然後再看About頁面列印的UserClaims:
這樣nbf和amr就不會被過濾掉了(從過濾掉的集合移除了).
2. 删除某些Claims
假如說我這個MVC用戶端不需要sid和idp, 那麼我可以使用下面的方法:
這是一個擴充方法, 一定要注意它和Remove方法的差別.........
再次操作後, 可以看到這些Claims不見了:
ClaimActions還有其他幾個方法, 請自行探索.
使用者資訊端點 UserInfo Endpoint
盡管ID Token裡面可以包含很多使用者的claims, 但是盡量讓ID Token小一點比較好. 是以當MVC用戶端需要更多使用者資訊的時候可以手動請求使用者資訊端點, 這樣做也可以獲得使用者最新的其他資訊.
UserInfo Endpoint的官方文檔在這:
http://openid.net/specs/openid-connect-core-1_0.html#UserInfo它要求使用GET或者POST進行請求, 但建議使用GET. 此外請求還需要使用Access Token.
這是一個例子:
成功請求的響應結果是一個JSON對象.
首先在IDP裡面再添加一個email scope:
然後在配置的Client裡面添加這個scope:
最後為TestUser添加email的claim:
回到MVC用戶端的Startup, 這裡也需要添加email這個scope,
而且還要保證這個email不會出現在claims Identity裡面, 這樣我在請求使用者資訊端點的時候才會得到email而不是從User.Claims裡面得到:
再次操作後, 可以看到User.Claims裡沒有出現email:
下面我需要手動發送請求到使用者資訊端點來擷取其他資訊:
identity sever 4的這部分文檔在:
https://identityserver4.readthedocs.io/en/release/endpoints/userinfo.html#identitymodel,
https://github.com/IdentityModel/IdentityModel2文檔提到, 需要為MVC用戶端安裝IdentityModel這個庫:
dotnet add package IdentityModel
随後, 我把擷取使用者email的代碼還是放在About Action裡:
首先通過IDP的URI獲得discovery document, 然後從中取出UserInfo端點, 從Cookie裡得到access token, 并用access token從使用者資訊端點獲得claims, 從這些claims裡面取得email并傳遞到About.cshtml.
相應的修改一下About.html:
重新操作後看About頁面:
對MVC用戶端使用基于角色對授權
首先需要在IDP那裡對兩個使用者添加role這個claim:
分别是管理者角色和注冊使用者角色.
OpenID Connect并沒有定義關于角色role相關的scope, 是以我還需要自定義一個scope:
第一個參數是scope的名字, 第二個參數是scope的顯示名, 第三個參數是它所包含的claim類型, 這裡就是“role”.
然後還需要用戶端允許請求“roles”這個scope:
IDP這邊配置完了, 下面是MVC用戶端的配置, 打開MVC的startup, 添加“roles”這個scope:
下面測試, 可以看到在同意頁面确實請求了角色“roles”這個scope:
然後同意後卻無法從User.Claims裡看到角色role 這個claim:
這是因為ASP.NET預設對UserInfo傳回的JSON資料裡一些常用的頂層claim進行了映射, 以便它們能夠出現在User.Claims裡面.
我也隻需要把JSON裡面的role claim, 映射到User.Claims裡即可:
再次操作後, 就可以在User.Claims看到角色了:
然後我便可以在MVC用戶端的任意地方通過角色來控制使用者的通路權限了, 例如:
但是如何把role claim映射成ASP.NET Core MVC可以識别的角色Roles呢?
可以在MVC裡這樣配置:
該參數主要是配置驗證Token的一些東西, 然而它還可以指定用戶端的Name 和 Role Claim的類型.
操作後用兩個使用者分别測試一下, Nick 管理者, 可以通路About:
另一個使用者, Dave 注冊使用者, 則不可以通路About:
這說明角色已經被MVC用戶端識别了.
但是對于Dave這個使用者來說, 沒有權限通路About時, 頁面顯示非常不友好, 是以下面解決這個問題.
首先建立一個AuthroizationController:
然後建立相關的view:
最後在Startup裡面配置, 如果沒有權限就跳轉到這個Action上:
再次操作後, Dave點選About後就會因為權限不足而跳轉到該頁面:
今天先到這, 我自己幾乎不用MVC, 我主要是做Web API的, 這部分的内容大部分來自官方文檔和其他一些資料綜合出來的.
代碼:
https://github.com/solenovex/Identity-Server-4-Tutorial-Code02部分
下面是我的關于ASP.NET Core Web API相關技術的公衆号--草根專欄: