使用 OAuth 2 和 JWT 爲微服務提供安全保障 - 基本概念

Part 1 - 理論相關

做者 freewolfjavascript

關鍵詞

微服務Spring CloudOAuth 2.0JWTSpring SecuritySSOUAA前端

寫在前面

做爲從業了十多年的IT行業和程序的老司機,今天若是你說你不懂微服務,都很差意思說本身的作軟件的。SOA喊了多年,無人不知,但又有多少系統開發真正的SOA了呢?可是好像一晚上之間全部人都投入了微服務的懷抱。java

做爲目前最主流的「微服務框架」,Spring Cloud發展速度很快,成爲了最全面的微服務解決方案。無論什麼軟件體系,什麼框架,安全永遠是不可能繞開的話題,我也把它做爲我最近一段時間研究微服務的開篇。web

老話題!「如何才能在微服務體系中保證安全?」,爲了達成目標,這裏採用一個簡單而可行方式來保護Spring Cloud中服務的安全,也就是創建統一的用戶受權中心。數據庫

這裏補充說一下什麼是Authentication(認證)Authorization(鑑權),其實很簡單,認證關心你是誰,鑑權關心你能幹什麼。舉個你們一致都再說的例子,若是你去機場伺機,你持有的護照表明你的身份,這是認證,你的機票就是你的權限,你能幹什麼。後端

學習微服務並非一個簡單的探索過程,這不得學習不少新的知識,其實不論是按照DDD(Domain Driven Design)領域驅動設計中領域模型的方式,仍是將微服務拆分紅更小的粒度。都會遇到不少新的問題和之前一直都沒解決很好的問題。隨着不斷的思考,隨着熟悉Facebook/GitHub/AWS這些機構是如何保護內部資源,答案也逐漸浮出水面。安全

爲了高效的實現這個目標,這裏採用OAuth 2JWT(JSON Web Tokens)技術做爲解決方案,服務器

爲何使用OAuth 2

儘管微服務在現代軟件開發中還算一個新鮮事物,可是OAuth 2已是一個普遍使用的受權技術,它讓Web開發者在本身提供服務中,用一種安全的方式直訪問Google/Facebook/GitHub平臺用戶信息。但在我開始闡述細節以前,我將揭開聚焦到本文真正的主題:雲安全架構

那麼在雲服務中對用戶訪問資源的控制,咱們通常都怎麼作呢?然我舉一些你們彷佛都用過的但又不是很完美的例子。app

咱們能夠設置邊界服務器或者帶認證功能的反向代理服務器,假設全部訪問請求都發給它。經過認證後,轉發給內部相應的服務器。通常在Spring MVC Security開發中幾乎都會這樣作的。但這並不安全,最重要的是,一旦是有人從內部攻擊,你的數據毫無安全性。

其餘方式:咱們爲全部服務創建統一的權限數據庫,並在每次請求前對用戶進行鑑權,聽起來某些方面的確有點愚蠢,但實際上這確實是一個可行的安全方案。

更好的方式: 用戶經過受權服務來實現鑑權,把用戶訪問Session映射成一個Token。全部遠程訪問資源服務器相關的API必須提供Token。而後資源服務器訪問受權服務來識別Token,得知Token屬於哪一個用戶,並瞭解經過這個Token能夠訪問什麼資源。

這聽起來是個不錯的方案,對不?可是如何保證Token的安全傳輸?如何區分是用戶訪問仍是其餘服務訪問?這確定是咱們關心的問題。

因此上述種種問題讓咱們選擇使用OAuth 2,其實訪問Facebook/Google的敏感數據和訪問咱們本身後端受保護數據沒什麼區別,而且他們已經使用這樣的解決方案不少年,咱們只要遵循這些方法就行了。

OAuth 2是如何工做的

若是你瞭解OAuth 2相關的原理,那麼在部署OAuth 2是很是容易的。
讓咱們描述下這樣一個場景,「某App但願得到TomFacebook上相關的數據」

OAuth 2 在整個流程中有四種角色:

  • 資源擁有者(Resource Owner) - 這裏是Tom
  • 資源服務器(Resource Server) - 這裏是Facebook
  • 受權服務器(Authorization Server) - 這裏固然仍是Facebook,由於Facebook有相關數據
  • 客戶端(Client) - 這裏是某App

Tom試圖登陸Facebook某App將他重定向到Facebook的受權服務器,當Tom登陸成功,而且許可本身的Email和我的信息被某App獲取。這兩個資源被定義成一個Scope(權限範圍),一旦准許,某App的開發者就能夠申請訪問權限範圍中定義的這兩個資源。

+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(b)-- authorization="" grant="" ---|="" |="" +---------------+="" |--(c)--="" --="">| Authorization |
| Client |                               |     Server    |
|        |<-(d)----- access="" token="" -------|="" |="" +---------------+="" |--(e)-----="" ------="">|    Resource   |
|        |                               |     Server    |
|        |<-(f)--- protected="" resource="" ---|="" |="" +--------+="" +---------------+<="" code="">
  
  
  

 
  
  
  

 
  
  
  

 複製代碼

Tom容許了權限請求,再次經過重定向返回某App,重定向返回時攜帶了一個Access Token(訪問令牌),接下來某App就能夠經過這個Access TokenFacebook直接獲取相關的受權資源(也就是Email和我的信息),而無需從新作Tom相關的鑑權。並且每當Tom登陸了某App,均可以經過以前得到的Access Token,直接獲取相關受權資源。

到目前爲止,咱們如何直接將以上內容用於實際的例子中?OAuth 2十分友好,並容易部署,全部交互都是關於客戶端和權限範圍的。

  • OAuth 2中的客戶端權限範圍和咱們平時的用戶和權限是否相同?
  • 我須要將受權映射到權限範圍中或將用戶映射到客戶端中?
  • 爲何我須要客戶端?

你也許在以前在相似的企業級開發案例中嘗試映射過相關的角色。這會很棘手!

任何類型的應用都提供用戶登陸,登陸結果是一個Access Token,全部的以後的API調用都將這個Access Token加入HTTP請求頭中,被調用服務去受權服務器驗證Access Token並獲取該Token可訪問的權限信息。這樣一來,全部服務的訪問都會請求另外的服務來完成鑑權。

權限範圍和角色,客戶端和用戶

OAuth 2中,你能夠定義哪一個應用(網站、移動客戶端、桌面應用、其餘)能夠訪問那些資源。這裏只有一個尺寸,來自哪裏的哪一個用戶能夠訪問那些數據,固然也是哪一個應用或者服務能夠訪問那些資源。換一種說法,權限範圍就是控制那些端點對客戶端可見,或者用戶根據他的權限來獲取相關的數據。

在一個在線商店中,前端能夠看作一個客戶端,能夠訪問商品、訂單和客戶信息,但後端能夠關於物流和合同等,另外一方面,用戶能夠訪問一個服務但並非所有的數據,這能夠是由於用戶正在使用Web應用,當他不能的時候,其餘用戶卻能夠。服務之間的訪問時咱們要討論的另外一個維度。若是你熟悉數學,我能夠說在OAuth 2中,客戶端-權限範圍關係是線性獨立於用戶-權限關係。

爲何是JWT

OAuth 2並不關心去哪找Access Token和把它存在什麼地方的,生成隨機字符串並保存Token相關的數據到這些字符串中保存好。經過一個令牌端點,其餘服務可能會關心這個Token是否有效,它能夠經過哪些權限。這就是用戶信息URL方法,受權服務器爲了獲取用戶信息轉換爲資源服務器。

當咱們談及微服務時,咱們須要找一個Token存儲的方式,來保證受權服務器能夠被水平擴展,儘管這是一個很複雜的任務。全部訪問微服務資源的請求都在Http Header中攜帶Token,被訪問的服務接下來再去請求受權服務器驗證Token的有效性,目前這種方式,咱們須要兩次或者更屢次的請求,但這是爲了安全性也沒什麼其餘辦法。但擴展Token存儲會很大影響咱們系統的可擴展性,這是咱們引入JWT(讀jot)的緣由。

+-----------+                                     +-------------+
|           |       1-Request Authorization       |             |
|           |------------------------------------>|             |
|           |     grant_type&username&password    |             |--+
|           |                                     |Authorization|  | 2-Gen
|  Client   |                                     |Service      |  |   JWT
|           |       3-Response Authorization      |             |<-+ |="" |<------------------------------------|="" private="" key="" access_token="" refresh_token="" token_type="" expire_in="" jti="" +-----------+="" +-------------+<="" code="">
  
  
  

 複製代碼

簡短來講,響應一個用戶請求時,將用戶信息和受權範圍序列化後放入一個JSON字符串,而後使用Base64進行編碼,最終在受權服務器用私鑰對這個字符串進行簽名,獲得一個JSON Web Token,咱們能夠像使用Access Token同樣的直接使用它,假設其餘全部的資源服務器都將持有一個RSA公鑰。當資源服務器接收到這個在Http Header中存有Token的請求,資源服務器就能夠拿到這個Token,並驗證它是否使用正確的私鑰簽名(是否通過受權服務器簽名,也就是驗籤)。驗籤經過,反序列化後就拿到OAuth 2的驗證信息。

驗證服務器返回的信息能夠是如下內容:

  • access_token - 訪問令牌,用於資源訪問
  • refresh_token - 當訪問令牌失效,使用這個令牌從新獲取訪問令牌
  • token_type - 令牌類型,這裏是Bearer也就是基本HTTP認證
  • expire_in - 過時時間
  • jti - JWT ID

因爲Access TokenBase64編碼,反編碼後就是下面的格式,標準的JWT格式。也就是HeaderPayloadSignature三部分。

{ 
  "alg":"RS256",
  "typ":"JWT"
}
{
  "exp": 1492873315,
  "user_name": "reader",
  "authorities": [
    "AURH_READ"
  ],
  "jti": "8f2d40eb-0d75-44df-a8cc-8c37320e3548",
  "client_id": "web_app",
  "scope": [
    "FOO"
  ]
}
&:lƧs)ۡ-[+
F"2"Kآ8ۓٞ:u9ٴ̯ޡ 9Q32Zƌ޿$ec{3mxJh0DF庖[!뀭N)㥔knVVĖV|夻ׄE㍫}Ŝf9>'<蕱굤Bۋеϵov虀DӨ8C4 K}Emޢ YVcaqIW&*uʝub!׏*Ť\՟-{ʖX܌WTq複製代碼

使用JWT能夠簡單的傳輸Token,用RSA簽名保證Token很難被僞造。Access Token字符串中包含用戶信息和權限範圍,咱們所需的所有信息都有了,因此不須要維護Token存儲,資源服務器也沒必要要求Token檢查。

+-----------+                                    +-----------+
|           |       1-Request Resource           |           |
|           |----------------------------------->|           |
|           | Authorization: bearer Access Token |           |--+
|           |                                    | Resource  |  | 2-Verify
|  Client   |                                    | Service   |  |  Token
|           |       3-Response Resource          |           |<-+ |="" |<-----------------------------------|="" public="" key|="" +-----------+="" +-----------+<="" code="">
  
  
  

 複製代碼

因此,在微服務中使用OAuth 2,不會影響到總體架構的可擴展性。淡然這裏還有一些問題沒有涉及,例如Access Token過時後,使用Refresh Token到認證服務器從新獲取Access Token等,後面會有具體的例子來展開討論這些問題。

若是您感興趣,後面還會有實現部分,敬請期待~

因爲 asciiflow.com/ 流程圖使用中文就沒法對齊了,本文中流程圖都是英文了~

相關文章
相關標籤/搜索