上一篇文章實現了IdentityServer4與Asp.net core Identity的集成,可使用經過identity註冊功能添加的用戶,以Password的方式獲取Access token,可是不管是Client Credentials仍是Password流程它都是OAuth2.0的流程,本篇文章就來先介紹一下關於OpenIDConnect的基本概念和用法。
本文有如下內容:
OpenIDConnect介紹及基本概念
另外從下面的回答能夠看出OAuth2.0是一個身份驗證/受權框架,而OpenID Connect基於這些提供了身份標識功能,身份標識就是「是誰」的 問題。
以及兩個表,OIDC身份驗證流程表:
OIDC身份驗證請求對應的相應類型(Response_Type)表:
還有一個流程圖:
從以上關鍵詞能夠得到下面的信息:
- ID Token:是一個包含特定聲明(Claim)的jwt,特定的聲明指的是身份驗證服務器驗證終端用戶時候產生的供客戶端使用的信息,如發行人(issuer)、最終用戶標識(sub)、客戶端id(aud)、過時時間(exp)、Token的發佈時間(iat)、用戶身份驗證時間(auth_time)等,另外也能夠包含其它的聲明。ID Token由身份驗證服務器(IdentityServer4,OP)頒發,交由客戶端(RP)進行驗證。
- Authentication:由IdentityServer4(OP)提供的身份驗證(登陸),最終用戶經過IdentityServer4(OP)的身份驗證(登陸)後,就能夠發起Authentication Request,或者說若是在發起Authentication Request時用戶未進行身份驗證時將重定向到身份驗證界面進行身份驗證。
- Authentication Request:向IdentityServer4(OP)的受權終結點發起的,用於獲取ID Token、受權碼(Authorization Code)甚至是訪問Token(Access Token)的請求。
- Authorization Code Flow、Implicit Flow、Hybrid Flow:Authentication Request的三種不一樣請求流程。
- Response_Type:Authentication Request的參數之一,根據設定該參數來決定使用哪種請求流程。
- Authorization Endpoint:受權終結點,用於接收Authentication Request。
- Token Endpoint:令牌終結點,用於接收訪問令牌(Access Token)獲取請求。
從兩個表格能夠知道:三種身份驗證流程的特性,如各Token從哪一個終結點返回、是否向用戶代理(如瀏覽器)透漏Token、是否支持刷新Token等。三種身份驗證流程經過指定Response_Type來決定,如參數值爲
code時進行受權碼流程,
Id_token以及id_token token時進行隱式流程,包含
code以及token時爲混合流程。
流程圖能夠了解到OpenIDConnect的整個身份驗證及受權步驟,而最終具體的實現就直接對應到受權碼流程、隱式流程和混合流程。
OIDC受權碼流程及實現
下面以受權碼流程爲例進行詳細解說,首先受權碼流程步驟以下:
受權碼流程一共有八個步驟,簡單來講就是由客戶端向身份驗證服務器發起身份驗證請求(響應類型爲code),身份驗證服務器向用戶進行身份驗證及用戶容許和受權操做後,將受權碼發送給客戶端,客戶端經過受權碼向身份驗證服務器的Token中階段獲取ID和Access Token,而後對ID Token進行驗證並獲取用戶的ID信息。
接下來使用以前建立的IdentityServer來實現基於受權碼流程的身份驗證與受權。
上一篇文章已經對IdentityServer添加了用戶及Asp.net Core Identity組件的支持,目前無需再進行任何修改,換句話說如今的IdentityServer已經可以頒發ID Token了,完成受權碼流程僅須要Client的支持,Client咱們使用以前文章中添加的Web API來演示,把原有的基於Jwt Bearer的身份驗證代碼註釋掉,添加基於cookie以及OIDC的身份驗證服務(注:添加OIDC的時候Client信息須要與IdentityServer中數據庫一致,而且相應的Client配置的重定向地址須要與該應用程序匹配):
確保「interactive」這個客戶端的重定向地址爲「應用程序地址/signin-oidc」,這裏須要注意的是這個重定向地址其實是客戶端(WebApi)經過方法.AddOpenIdConnect添加的用於處理odic身份驗證的身份驗證處理器:git
![](http://static.javashuo.com/static/loading.gif)
就會跳轉到身份驗證服務器的登陸頁面:
注:IdentityServer4的默認登陸地址爲/account/login,可是asp.net core Identity生成的登陸頁面是/identity/account/login,爲了保證正確跳轉需加入如下配置:github
![](http://static.javashuo.com/static/loading.gif)
下面是登陸頁面url信息:web
![](http://static.javashuo.com/static/loading.gif)
能夠看到三個參數:
一、第一個參數是由於客戶端向Identity服務器發起身份驗證請求(Authentication Request),但因爲終端用戶還未登陸,因此先跳轉登陸頁面,當完成登錄後將返回/connect/authorize/callback。
二、第三個參數是響應類型,值爲code,表明當前
使用受權碼流程。
三、第二個參數重定向uri是完成受權後,將攜帶受權碼重定向的地址,也就是web Api程序的oidc身份驗證地址。
對於受權碼流程的八個步驟來講,它完成了前三個,目前處於終端用戶身份驗證(未完成-還未輸入用戶名密碼)階段:
輸入用戶名密碼登陸後,就能夠看到受保護的內容了:
這裏完成受權碼流程的後四個步驟:
整個過程主要是應用程序(Client)和身份驗證服務器進行交互並完成,相關的受權碼、ID token以及Access Token均「未」發送到瀏覽器中,因此受權碼流程也是最爲安全的流程。
如何在客戶端得到相應的Access Token呢?經過HttpContext.GetTokenAsync("token name");便可得到相應的Token:
ID Token:
Access Token:數據庫
![](http://static.javashuo.com/static/loading.gif)
能夠經過HttpContext獲取Token的緣由是在添加oidc身份驗證服務時,將SaveTokens選項設置爲true,當身份驗證成功後程序會自動將各種Token存儲到AuthenticationProperties中,最終加密寫入Cookie裏面,因此雖然數據保存在瀏覽器,但因爲加密緣故,因此以前才說他們均「未」發送到瀏覽器中:
那麼受權碼流程最後一步要如何實現呢?這裏有兩種方法,其一是經過獲取access token以後直接在程序中訪問身份驗證服務器的UserInfo Endpoint獲取,另外就是將oidc選項的GetClaimsFromUserInfoEndpoint設置爲true便可:
未獲取UserInfo的User Claims信息:
獲取UserInfo後的User Claims信息,能夠看到多了一個name的claim(關於爲何只有一個claim後續文章中再進行說明):
OIDC隱式流程及實現
既然最複雜的受權碼流程已經可以實現了,那麼簡單的隱式流程確定沒問題,下面就演示一下如何經過隱式流程將token直接獲取到瀏覽器中。
首先建立一個支持隱式流程的client:
注:數據庫中建立client複製已有的數據修改便可,client密碼是加密存儲的,複製後使用被複制的client密碼便可,另外由於須要將token信息發送到瀏覽器,因此須要將client信息中的「AllowAccessTokenViaBrowser」設置爲1。
將client的信息配置到client應用上:
隱式流程要求響應類型爲id_token或id_token及token。
配置完成後運行程序並攜帶如下參數,直接訪問IdentityServer的受權終結點:
登陸成功後程序將自動跳轉到參數redirect_uri指定的路徑,而且攜帶token及相關信息:
將整個url格式化後得到如下結果:
小結
本篇文章介紹了OpenIDConnect的基本概念,並經過已有的IdentitySever程序演示了基於受權碼和隱式流程,其中受權碼模式是一種較爲安全的模式,全部的關鍵的數據包括受權碼以及各種token均在client的後臺完成,若是須要能夠把相關的token加密後以cookie的方式放到客戶端以供後續使用。而隱式模式能夠將各種token返回到瀏覽器中,這種模式能夠在單頁應用中使用,將token交由js來進行管理並用於受保護資源的訪問。
另外到目前爲止咱們能夠看到的是IdentityServer或者說IdentityServer4的做用就是校驗Client信息、終端用戶的用戶名密碼信息,而後生成受權碼以及各種token,而token的驗證和使用實際上仍是在Client中進行的。
最後OIDC是一個身份驗證協議,那麼身份驗證和受權在Asp.net core應用程序中是如何體現的呢?下篇文章就來聊聊這個問題。
參考: