系列導航
SpringSecurity系列
- SpringSecurity系列學習(一):初識SpringSecurity
- SpringSecurity系列學習(二):密碼驗證
- SpringSecurity系列學習(三):認證流程和源碼解析
- SpringSecurity系列學習(四):基於JWT的認證
- SpringSecurity系列學習(四-番外):多因子驗證和TOTP
- SpringSecurity系列學習(五):授權流程和源碼分析
- SpringSecurity系列學習(六):基於RBAC的授權
SpringSecurityOauth2系列
- SpringSecurityOauth2系列學習(一):初認Oauth2
- SpringSecurityOauth2系列學習(二):授權服務
- SpringSecurityOauth2系列學習(三):資源服務
- SpringSecurityOauth2系列學習(四):自定義登陸登出接口
- SpringSecurityOauth2系列學習(五):授權服務自定義異常處理
初認Oauth2
hello!我又來啦!
之前我們學習了前后端分離的SpringSecurity架構,但是在微服務滿天飛的今天,前面學習的這種架構已經不適用了。
誒那么有沒有一種適用於微服務的安全框架呢?
當然就是SpringSecurityOauth2了。
有的小伙伴一看,這不還是SpringSecurity嘛,后面加了一個Oauth2后綴,啥是Oauth2啊?
別急,我們先來看看Oauth2的概念
Oauth2的概念
先說OAuth,OAuth是Open Authorization的簡寫。
OAuth協議為用戶資源的授權提供了一個安全的、開放而又簡易的標准。與以往的授權方式不同之處是
OAuth的授權不會使第三方觸及到用戶的帳號信息(如用戶名與密碼),即第三方無需使用用戶的用戶名與
密碼就可以申請獲得該用戶資源的授權,因此OAuth是安全的。
OAuth2.0是OAuth協議的延續版本,但不向前兼容(即完全廢止了OAuth1.0)。
使用場景
假設,A網站是一個打印照片的網站,B網站是一個存儲照片的網站,二者原本毫無關聯。
如果一個用戶想使用A網站打印自己存儲在B網站的照片,那么A網站就需要使用B網站的照片資源才行。
按照傳統的思考模式,我們需要A網站具有登錄B網站的用戶名和密碼才行,但是,現在有了OAuth2,只需要A網
站獲取到使用B網站照片資源的一個通行令牌即可!這個令牌無需具備操作B網站所有資源的權限,也無需永久有
效,只要滿足A網站打印照片需求即可。
這么聽來,是不是有點像單點登錄?NONONO!千萬不要混淆概念!單點登錄是用戶一次登錄,自己可以操作其
他關聯的服務資源。OAuth2則是用戶給一個系統授權,可以直接操作其他系統資源的一種方式。
但SpringSecurity的OAuth2也是可以實現單點登錄的!
總結一句:SpringSecurity的OAuth2可以做服務之間資源共享,也可以實現單點登錄!
角色說明
- 應用(客戶端):客戶端就是一個要訪問用戶賬號的應用,需要得到用戶的允許后才可以得到授權
- API服務(資源服務):資源服務通常提供API用於訪問用戶的授權客戶端訪問的信息
- 授權服務:讓用戶批准或拒絕請求的服務,嚴格來說,認證不屬於這個服務的職責,雖然往往認證和授權都在一個服務。當然授權服務也可以是資源服務
- 用戶(資源所有者):授權客戶端訪問資源服務器的主體
通常,作為作為OAuth2的客戶端 ,需要上傳這幾個字段:
Application name
:應用名HomepageURL
:主頁,主要是域名Authorization callback URL
:回調地址,授權成功后返回的URL
然后系統對於每個客戶端會生成Client ID
(必要,應用工具唯一標識)和Client Secret
(非必要,可以理解為應用的密碼),請求授權要求客戶端傳入這兩個值進行授權
OAuth2.0中主流的四種授權方式
為了說明四種模式先准備一張圖
授權碼模式(authorization code)
- 流程
說明:【A服務客戶端】需要用到【B服務資源服務】中的資源
-
第一步:【A服務客戶端】將用戶自動導航到【B服務認證服務】,這一步用戶需要提供一個回調地址,以備【B服務認證服務】返回授權碼使用。
-
第二步:用戶點擊授權按鈕表示讓【A服務客戶端】使用【B服務資源服務】,這一步需要用戶登錄B服務,也就是說用戶要事先具有B服務的使用權限。
-
第三步:【B服務認證服務】生成授權碼,授權碼將通過第一步提供的回調地址,返回給【A服務客戶端】。
注意這個授權碼並非通行【B服務資源服務】的通行憑證。
-
第四步:這個時候,通常會給用戶彈出一個頁面,詢問用戶是否同意授權給A服務,用戶點擊同意,然后【A服務認證服務】攜帶上一步得到的授權碼向【B服務認證服務】發送請求,獲取通行憑證token。
-
第五步:【B服務認證服務】給【A服務認證服務】返回令牌token和更新令牌refresh token。
- 使用場景
授權碼模式是OAuth2中最安全最完善的一種模式,應用場景最廣泛,可以實現服務之間的調用,常見的微
信,QQ等第三方登錄也可采用這種方式實現。
簡化模式(implicit)
- 流程
說明:簡化模式中沒有【A服務認證服務】這一部分,全部又【A服務客戶端】與B服務交互,整個過程不再有授權碼,token直接暴露在瀏覽器。
-
第一步:【A服務客戶端】將用戶自動導航到【B服務認證服務】,這一步用戶需要提供一個回調地址,以備【B服務認證服務】返回token使用,還會攜帶一個【A服務客戶端】的狀態標識state。
-
第二步:用戶點擊授權按鈕表示讓【A服務客戶端】使用【B服務資源服務】,這一步需要用戶登錄B服務,也就是說用戶要事先具有B服務的使用權限。
-
第三步:【B服務認證服務】生成通行令牌token,token將通過第一步提供的回調地址,返回給【A服務客戶端】。
-
使用場景
適用於A服務沒有服務器的情況。比如:純手機小程序,JavaScript語言實現的網頁插件等。
密碼模式(resource owner password credentials)
- 流程
-
第一步:直接告訴【A服務客戶端】自己的【B服務認證服務】的用戶名和密碼
-
第二步:【A服務客戶端】攜帶【B服務認證服務】的用戶名和密碼向【B服務認證服務】發起請求獲取token。
-
第三步:【B服務認證服務】給【A服務客戶端】頒發token。
-
使用場景
此種模式雖然簡單,但是用戶將B服務的用戶名和密碼暴露給了A服務,需要兩個服務信任度非常高才能使用。
客戶端模式(client credentials)
-
流程
說明:這種模式其實已經不太屬於OAuth2的范疇了。A服務完全脫離用戶,以自己的身份去向B服務索取token。換言之,用戶無需具備B服務的使用權也可以。完全是A服務與B服務內部的交互,與用戶無關了。
-
第一步:A服務向B服務索取token。
-
第二步:B服務返回token給A服務。
-
使用場景
A服務本身需要B服務資源,與用戶無關。
JWS/JWK
Oauth2中返回的token其實也有很多種類型,SpringSecurityOauth2中授權服務器如果不做配置,那么默認返回的其實只是一串UUID。
那么我們使用怎樣的token呢?當然還是JWT啦!
SpringSecurityOauth2中授權服務器簽發的token還是使用非對稱加密進行簽名,但是其內部已經實現了相關邏輯,不再需要我們自己去寫邏輯,配置好之后直接使用即可。
不過這里還需要了解一個術語:JWS/JWK
JWT火爆之后,人們對於其安全性做了很多討論,其簽名也是人們討論的話題之一。JWT支持使用不同的算法進行簽名,但是沒有一個統一的方式。
JWS就是JWT簽名的驗證數據完整性的不同的加密機制
JWK就是簽名加密密鑰的JSON結構。一般情況下,對於簽名需要有一個不對稱加密,需要有密鑰對進行加密。
公鑰和私鑰。公鑰加密需要私鑰來解密,同樣的私鑰加密需要公鑰來解密。
一般公鑰和私鑰放在不同的地方,私鑰保存在服務器上面,而公鑰保存在客戶端。公鑰可以公開,私鑰保密。
簽發token使用私鑰加密,簽名。token的內容是公開的,但是token的簽名驗證需要公鑰去解密驗證,沒有私鑰是偽造不出來私鑰加密的簽名的。只要驗證成功,說明這個token是使用私鑰簽發的,是可以信任的
流程:
- 客戶端請求Access Token,資源服務器返回一個使用JWS簽名的一個JWT,這里的JWS包含一個Kid,其為一種加密形式的唯一標識,表示了應該使用說明方式進行加密。
- 客戶端請求資源,將使用JWS簽名的一個JWT傳遞給資源服務器,資源服務器會向授權服務器請求一個公鑰,授權服務器會把JWK(即Kid對應的這種密鑰結構)返回給資源服務器,之后資源服務器就使用這個公鑰去驗證簽名,去驗證權限。
加密流程
加密流程也就是創建JWT的過程
拿私鑰進行非對稱加密,將kid
和其kid value
寫入jws的header中,然后在進行Claims
聲明進行編碼
然后將jws header放入簽名這個字段里面去,進行編碼
最后就形成了有header,有cliams,有簽名的一個jwt
解密流程
拿到JWT之后,去請求一個公鑰,對這個JWT進行一個解析
解析完成之后,得到簽名,然后取出其中Kid
為key對應的Kid value
然后將Kid value
設置到簽名當中
然后在去驗證簽名是否正確