上一篇文章咱們介紹了Asp.net core中身份驗證的相關內容,並經過下圖描述了身份驗證及受權的流程:
注:改流程圖進行過修改,第三方用戶名密碼登錄後並非直接得到code/id_token/access_token,而是登陸後能夠訪問identityServer中受保護的資源(Authorize Endpoint),經過發起身份驗證請求來實現受權碼流程、隱式流程及混合流程來完成token的獲取,它與直接經過用戶名密碼來獲取token的Oauth2.0 Password GrantType方式是不同的。
在asp.net core應用程序中,經過受權碼流程可使用第三方(IdentityServer)的用戶名密碼,通過一系列的token、userinfo獲取,最後生成身份信息載體(Cookie),asp.net core應用程序使用cookie就能完成身份驗證工做。這個過程對於用戶來講,它與通常的asp.net core應用程序(特指基於asp.net core identity的應用程序)是沒有任何區別的,都是經過用戶名密碼登陸,而後就能夠進入系統。對於應用程序來講它仍然是基於cookie來完成身份驗證,只不過生成cookie所需的數據是第三方提供的而已。
可是單頁應用因爲其特殊性,其UI渲染工做及業務邏輯的處理都是由瀏覽器完成,服務器不具有相關功能(僅需靜態文件傳輸便可),其次單頁應用會存在跨域問題,因此cookie就不適合做爲單頁應用的身份信息載體,本文就介紹如何使用jwt來完成單頁應用的身份驗證。
主要內容有:
- 建立一個簡單的單頁應用項目
- 使用單頁應用完成受保護資源訪問
- oidc Client簡介
- oidc-client.js的各類用法
- 小結
建立一個簡單的單頁應用項目
一、新建一個asp.net core的web應用程序:
二、添加oidc的js組件:
能夠經過npm進行安裝或者在Github上直接下載,如下爲npm安裝方法:
npm i oidc-client
完成以後在相關目錄下可找到oidc-client相關文件:
將其複製到適合的位置便可。
添加Client時須要注意幾個關鍵信息:
- 受權類型支持受權碼類型;
- 不須要客戶端密碼;
- 容許跨域,容許客戶端跨域訪問IdentityServer;
參考以下,內存實例:
數據庫數據:
四、添加基於oidc-client的登陸、API訪問以及登出業務邏輯代碼App.js:
UserManager對象初始化:
使用UserManager實例進行登陸跳轉:
使用UserManager實例獲取用戶信息,而後經過用戶信息中的access token訪問受保護資源:
使用UserManager實例進行登出跳轉:
五、添加功能頁面Index.html,包含登陸、API訪問及登出功能:
六、添加用於處理受權碼的重定向頁面:
到此單頁應用程序已經建立完畢,後面就使用該程序要介紹它是如何完成身份驗證,並訪問受保護資源的。
使用單頁應用完成受保護資源訪問
咱們使用一個簡單的asp.net core web api項目(本系列文章用過的)來進行演示,它對於普通API項目來講要點在於:
一、添加基於JwtBearer的身份驗證處理器:
二、添加跨域處理,添加跨域策略配置:
三、在asp.net core應用請求管道中應用跨域配置:
四、受保護內容經過authorize特性進行標記:
一切準備就緒後運行三個應用程序,單頁應用運行並打開index.html頁面效果以下,一共有三個功能,登陸、調用API以及登出:
登陸:它其實是調用oidc Client的signinRedirect方法,語義上來講它是經過重定向的方式進行登陸,而它實際執行的效果以下:
跳轉到了IdentityServer的登陸頁面,而後咱們再看看它本質上是作了什麼?
爲了可以看清楚整個請求過程,本例在callback.html頁面加入了調試斷點:
斷點位於signinRedirectCallback方法以後,也就是完成回調處理以後(這個時候已經完成token等信息的獲取),跳轉到index.html頁面以前。
如下是輸入用戶名密碼提交後命中斷點時的相關請求信息:
由上圖能夠看到,當輸入用戶名密碼提交後(第一個請求),因爲經過了身份驗證,那麼繼續完成受權碼流程(第二個請求),受權碼流程完成後攜帶受權碼重定向到Client配置的重定向地址(第三個請求).
第三個請求就到了咱們的callback.html頁面,頁面的加載首先請求了oidc-client.js文件,而後由UserManager的實例化以及signinRedirectCallback方法,來完成了後續請求,後續請求包含openid的配置信息請求、獲取Token請求、獲取用戶信息(userinfo)請求以及檢查會話請求。
以上一系列的請求結果就是在瀏覽器的會話存儲中,咱們能夠找到相關的數據信息:
斷點經過後就來到了index.html頁面,並打印出登陸用戶信息:
點擊Call API按鈕後,程序將從存儲信息中獲取到access_token,攜帶access_token完成請求:
點擊登出按鈕後,程序將刪除用戶信息並跳轉到IdentityServer的登出頁面:
注:須要配置identityserver4的登出url:
oidc-client.js簡介
前面的內容是基於oidc-client.js,即JavaScript版本的oidc客戶端類庫來實現的單頁應用的,那麼oidc-client.js到底爲咱們提供了什麼功能呢?
oidc-client.js是一個支持OIDC和Oauth2.0協議的JavaScript類庫,除此以外它還提供用戶會話和Token的管理功能。類庫中的核心類型是UserManager,它提供了用戶登陸、登出、用戶信息管理等高層次的API,上面的例子中就是使用UserManager來完成的登陸、用戶信息(Access Token)獲取以及登出的。
oidc-client.js或者直接說UserManager使用上須要注意如下幾個方面:
但這裏要注意的是因爲以上代碼對用戶是可見的,因此Client的密碼就省略了。
- 方法:提供了用戶管理、登陸、登出、以及相關回調方法,除此以外還有會話狀態查詢和開啓/關閉靜默刷新(token)的方法。登陸/登出分爲三種類型:跳轉、靜默和彈出,具體如何使用後續介紹。
![](http://static.javashuo.com/static/loading.gif)
- 屬性:能夠返回UserManager的配置、事件以及元數據服務。
- 事件:UserManager包含了8個事件,如用戶登陸/登出、access token過時等:
![](http://static.javashuo.com/static/loading.gif)
oidc-client.js的各類用法
彈出式登陸/登出
彈出式登陸/登出就是字面的意思,經過彈出窗口打開IdentityServer的登陸/登出頁面完成相應功能。
下圖爲彈出式登陸(僅需調用UserManager的signinPopup方法便可):
注:回調頁面須要使用signinPopupCallback:
下圖爲彈出式登出:
靜默登陸與靜默刷新
靜默登陸和靜默刷新指的就是signinSilent和startSilentRenew兩個方法,並且須要注意的是startSilentRenew的原理其實是關注了accessTokenExpiring事件,當token即將過時時調用signinSilent進行靜默登陸。
靜默登陸方式又有兩種其一是基於會話的,其二是基於刷新token,其中刷新token的優先級較高,換句話就是刷新token存在的時候,它就默認使用刷新token進行登陸,刷新token比較好理解,可是會話是什麼呢?它實際上就是經過IdentityServer的登陸後所保持的狀態,文章最開始的流程圖中提到過,咱們之因此能夠經過受權碼流程進行受權是由於登陸以後有權訪問IdentityServer受保護的受權終結點,從而能夠獲取受權碼及相關Token,那這裏的原理就是瀏覽器保存了登陸狀態,因此能夠再次訪問受權終結點來獲取並刷新Token信息。
基於會話的靜默登陸,下圖爲點擊靜默登陸按鈕後發起的請求信息,也就是正常的請求到受權碼以後獲取token及用戶信息的過程:
須要注意的是回調頁面須要使用signinSilentCallback方法,同時再也不須要頁面跳轉:
基於刷新token的靜默登陸,在嘗試刷新token登陸以前首先須要得到刷新token,oidc中刷新token的獲取是須要client支持offline_access的scope,同時在發起獲取token時攜帶該scope:
配置完成後從新登陸獲取token便可在存儲中找到刷新token信息 :
而後再次進行靜默登陸(相應client須要支持refresh_token的受權方式):
靜默登陸發起的請求信息:
響應信息中包含了新的token:
會話監聽
會話監聽是默認開啓的,在正常登陸狀態下,經過新的瀏覽器窗口從identityserver中登出(目的是清除identityserver存儲在瀏覽器的會話信息):
信息清除後它會當即嘗試發起新的身份驗證請求,可是返回信息中包含「須要登陸」錯誤信息,能夠在接收到相關錯誤信息時清除相關Token及用戶信息,已達到單頁應用隨着IdentityServer會話結束而登出的效果:
小結
本篇文章介紹了單頁應用使用IdentityServer進行身份驗證的過程及oidc-client.js JavaScript類庫在應用中的使用,oidc-client.js爲咱們適配了oidc協議,同時還提供了豐富的功能和機制,使用這個類庫能夠大大減小實際工做中的開發量。
說到單頁應用的身份驗證,它最根本的機制無非就是得到Access Token和Refresh Token,使用Access Token做爲身份信息載體來完成身份驗證,使用Refresh Token做爲更新Access Token的鑰匙,經過保證Access Token不過時來保證用戶可以正常訪問相關資源。
但若是使用Oauth2.0協議來實現單頁應用的登陸(Password受權模式)會存在一些問題,首先是單頁應用對於受權服務器來講是不可信的,可是Password受權由單頁應用發起,屬於受權服務器的用戶信息及密碼都要通過不可信的單頁應用,這會形成一些安全問題,其次使用Oauth2.0協議完成受權後,應用與受權服務器之間實際上就沒有任何關聯了,受權服務器不保留用戶會話,也沒法實現用戶登出聯動的功能(即一方登出能夠通知另外一方),這些也正是IdentityServer4或者說OIDC協議所處理的內容。
下篇文章,咱們將繼續以IdentityServer4或者說OIDC的會話管理開始,深刻聊一聊它們的登陸與登出。
參考: