微服務系列之授權認證(一) OAuth 2.0 和 OpenID Connect

1.傳統架構的授權認證

  傳統應用架構,用戶使用帳號密碼登錄後,可以使用前端cookie存儲登錄狀態,也可以使用後端session方式存儲登錄狀態,小應用這麼做其實很高效實用,當應用需要橫向擴展時,就需要共享登錄狀態,這時候session的基於asp.net state這種當前伺服器進程方式存儲就失效了,需要換成sqlserver或者redis作為session共享存儲,這些都不是問題,這些前提都是單體應用架構的方案,但是在微服務架構里,服務拆分零散且前後端分離,後端以API方式提供服務的前提下,這種認證授權方式用不了拉,這時候就需要一個安全的、跨分散式的、高性能的認證授權方案來解決。 

  這些年圍繞著授權鑒權(authorization)和身份驗證(authentication)誕生了很多規範和協議。這裡只討論最主流的最新的規範和協議:OAuth2.0、OpenID Connect、JWT。8

2.OAuth 2.0

  OAuth 2.0是關於授權鑒權的,一句話解釋「OAuth 2.0是一種框架,其中服務的用戶可以允許第三方應用程式訪問他/她在服務中託管的數據,而無需嚮應用程式透露他/她的憑據」。

  說一下Oauth2.0相關的名詞:

  • Resource Owner:資源所有者,就是某個應用的用戶;
  • Client:客戶端,一個想要用這個資源用戶的名義去做一些事情的應用」;
  • Authorization Server:授權服務,前提是用戶信任這個服務並且該服務擁有用戶資訊,用於頒發令牌給應用;
  • Resource Server: 一個應用(API或者服務);
  • Redirect URI: 一個網址URL,當Resource Owner在Authorization Server上授權了Client後,Authorization Server將會把Resource Owner重定向到的地方,也稱「Callback URL」;
  • Authorization Code: 用戶授權給client後通過RedirectUrl回調回去攜帶的code,用於client通過客戶端模式向授權服務換取token;
  • Access Token: Client和Resource Server交互所使用的令牌,攜帶的訪問許可權範圍,是你授權時通過勾選給client的,然後client拿著這個用戶名義的token就可以訪問你的資源了; 一般使用的是JWT格式;
  • Response Type: Client希望從Authorization Server收到的資訊的類型,最常見的Response Type是code,也就是Client希望收到一個Authorization Code,也有Implicit隱藏式,password密碼模式,Client Credential客戶端憑證模式。  

  下面說一下幾種常用授權類型的實際交互是怎麼樣的

(1) 授權碼模式Authorization Code

  

(2)Implicit隱藏式

  這種模式,跳過獲取code的步驟,在客戶端重定向到授權服務時,講responseType換成token。

(3)password密碼模式

  這種是啥呢,需要用戶非常非常信任client的時候,才使用這種模式,需要用戶在clinet上輸入帳號密碼,client拿著用戶的帳號密碼去授權服務獲取access token。

(4)Client Credential客戶端憑證模式

  這是client與client之間的通訊,與用戶沒啥關係,這種用於,流程是,A客戶端使用clientId和secret通過授權服務,獲取訪問B客戶端的token。我們實戰中,是業務系統,在中台認證中心裡獲取一個長期的可以訪問中台某些服務的token,業務服務直接通訊中台服務,於用戶無關。

3.OpenID Connect

  OpenID Connect實際上就是對於client來說,在OAuth 2協議上完善了身份認證的東西,並不是說Oauth 2.0沒有提供認證能力,只是對於client來說,沒有知道用戶的認證過程,沒有拿到用戶認證資訊而已,OIDC就是讓OAuth把認證結果也告訴client,讓client也知道了用戶是認證過的。這樣在授權碼過程中如下圖:

  

 HTTP/1.1 302 Found
  Location: https://server.example.com/authorize?
    response_type=code
    &scope=openid%20profile%20email
    &client_id=s6BhdRkqt3
    &state=af0dasd
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb

在scope中增加了openid

 HTTP/1.1 200 OK
  Content-Type: application/json
  Cache-Control: no-store
  Pragma: no-cache

  {
   "access_token": "dasdqwdqd",
   "token_type": "Bearer",
   "refresh_token": "casdqwfw",
   "expires_in": 3600,
   "id_token": "dsadwqdqdqwdqV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
     NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
     fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
     AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
     Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
     NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
     QyHE5lcMiKPXfEIQILVq0pcgqeqgeqwhethrDSAdqwwqrt43t3"
  }

  在返回的時候增加了id_token。

  那麼問題來了,OAouth2.0 給客戶端辦法的access token中的Payload中是可以自定義的,並且也可以防篡改,直接把認證的身份資訊自定義里多好啊。?或者說,通過access_token去oidc提供的一個endpoint(get/userinfo)去請求用戶資訊?

  原因以下幾點:

  1)payload里可是明文傳輸的,增加了傳輸頻寬,也增加了用戶資訊泄露的風險;

  2)access_token本身定義就是授權訪問令牌,不關心用戶資訊,只關心是否能訪問,功能耦合;

  3)通過endpoint請求用戶資訊,增加了不少額外的API開銷。

下一節,我們會大至說一下.net core服務中基於OAuth2.0和OpenId Connect實現的框架 identiy server 4

  

  

 

Tags: