OAuth2介紹與使用


1.什么是OAuth2

OAuth(開放授權)是一個開放標准,允許用戶授權第三方移動應用訪問他們存儲在另外的服務提供者上的信息,而不需要將用戶名和密碼提供給第三方移動應用或分享他們數據的所有內容,OAuth2.0是OAuth協議的延續版本,但不向后兼容OAuth 1.0即完全廢止了OAuth1.0。

2.應用場景

第三方應用授權登錄:在APP或者網頁接入一些第三方應用時,時長會需要用戶登錄另一個合作平台,比如QQ,微博,微信的授權登錄。

原生app授權:app登錄請求后台接口,為了安全認證,所有請求都帶token信息,如果登錄驗證、請求后台數據。

前后端分離單頁面應用(spa):前后端分離框架,前端請求后台數據,需要進行oauth2安全認證,比如使用vue、react后者h5開發的app。

3.名詞定義

(1) Third-party application:第三方應用程序,本文中又稱"客戶端"(client),比如打開知乎,使用第三方登錄,選擇qq登錄,這時候知乎就是客戶端。

(2)HTTP service:HTTP服務提供商,本文中簡稱"服務提供商",即上例的qq。

(3)Resource Owner:資源所有者,本文中又稱"用戶"(user),即登錄用戶。

(4)User Agent:用戶代理,本文中就是指瀏覽器。

(5)Authorization server:認證服務器,即服務提供商專門用來處理認證的服務器。

(6)Resource server:資源服務器,即服務提供商存放用戶生成的資源的服務器。它與認證服務器,可以是同一台服務器,也可以是不同的服務器。

4.運行流程

(A)用戶打開客戶端以后,客戶端要求用戶給予授權。

(B)用戶同意給予客戶端授權。

(C)客戶端使用上一步獲得的授權,向認證服務器申請令牌。

(D)認證服務器對客戶端進行認證以后,確認無誤,同意發放令牌。

(E)客戶端使用令牌,向資源服務器申請獲取資源。

(F)資源服務器確認令牌無誤,同意向客戶端開放資源。

5.四種授權模式

授權碼模式(authorization code)

簡化模式(implicit)

密碼模式(resource owner password credentials)

客戶端模式(client credentials)

6.授權碼模式

授權碼模式(authorization code)是功能最完整、流程最嚴密的授權模式。

流程
說明:【A服務客戶端】需要用到【B服務資源服務】中的資源
第一步:【A服務客戶端】將用戶自動導航到【B服務認證服務】,這一步用戶需要提供一個回調地址,以備
B服務認證服務】返回授權碼使用。
第二步:用戶點擊授權按鈕表示讓【A服務客戶端】使用【B服務資源服務】,這一步需要用戶登錄B服務,也
就是說用戶要事先具有B服務的使用權限。
第三步:【B服務認證服務】生成授權碼,授權碼將通過第一步提供的回調地址,返回給【A服務客戶端】。
注意這個授權碼並非通行【B服務資源服務】的通行憑證。
第四步:【A服務認證服務】攜帶上一步得到的授權碼向【B服務認證服務】發送請求,獲取通行憑證token
第五步:【B服務認證服務】給【A服務認證服務】返回令牌token和更新令牌refresh token
使用場景
授權碼模式是OAuth2中最安全最完善的一種模式,應用場景最廣泛,可以實現服務之間的調用,常見的微
信,QQ等第三方登錄也可采用這種方式實現

7.簡化模式Implicit

說明:簡化模式中沒有【A服務認證服務】這一部分,全部有【A服務客戶端】與B服務交互,整個過程不再有
授權碼,token直接暴露在瀏覽器。
第一步:【A服務客戶端】將用戶自動導航到【B服務認證服務】,這一步用戶需要提供一個回調地址,以備
B服務認證服務】返回token使用,還會攜帶一個【A服務客戶端】的狀態標識state
第二步:用戶點擊授權按鈕表示讓【A服務客戶端】使用【B服務資源服務】,這一步需要用戶登錄B服務,也
就是說用戶要事先具有B服務的使用權限。

第三步:【B服務認證服務】生成通行令牌tokentoken將通過第一步提供的回調地址,返回給【A服務客戶端】。
使用場景
適用於A服務沒有服務器的情況。比如:純手機小程序,JavaScript語言實現的網頁插件等

8.用戶名密碼 Resource Owner Credentials

流程
第一步:直接告訴【A服務客戶端】自己的【B服務認證服務】的用戶名和密碼
第二步:【A服務客戶端】攜帶【B服務認證服務】的用戶名和密碼向【B服務認證服務】發起請求獲取
token
第三步:【B服務認證服務】給【A服務客戶端】頒發token
使用場景
此種模式雖然簡單,但是用戶將B服務的用戶名和密碼暴露給了A服務,需要兩個服務信任度非常高才能使用 

9.客戶端憑證 Client Credentials

流程
說明:這種模式其實已經不太屬於OAuth2的范疇了。A服務完全脫離用戶,以自己的身份去向B服務索取
token。換言之,用戶無需具備B服務的使用權也可以。完全是A服務與B服務內部的交互,與用戶無關了。
第一步:A服務向B服務索取token
第二步:B服務返回tokenA服務。
使用場景
A服務本身需要B服務資源,與用戶無關。

 
OAuth2.0中表結構說明
官方SQL地址:
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-securityoauth2/src/test/resources/schema.sql
 
字段名 字段說明
client_id 主鍵,必須唯一,不能為空. 用於唯一標識每一個客戶端(client); 在注冊時必須填寫(也可由服務
端自動生成). 對於不同的grant_type,該字段都是必須的. 在實際應用中的另一個名稱叫
appKey,client_id是同一個概念.
resource_ids 客戶端所能訪問的資源id集合,多個資源時用逗號(,)分隔,: “unity-resource,mobile
resource”. 該字段的值必須來源於與security.xml中標簽‹oauth2:resource-server的屬性
resource-id值一致. security.xml配置有幾個‹oauth2:resource-server標簽, 則該字段可以
使用幾個該值. 在實際應用中, 我們一般將資源進行分類,並分別配置對應
‹oauth2:resource-server,如訂單資源配置一個‹oauth2:resource-server, 用戶資源又配置
一個‹oauth2:resource-server. 當注冊客戶端時,根據實際需要可選擇資源id,也可根據不同的
注冊流程,賦予對應的資源id.
client_secret 用於指定客戶端(client)的訪問密匙; 在注冊時必須填寫(也可由服務端自動生成). 對於不同的
grant_type,該字段都是必須的. 在實際應用中的另一個名稱叫appSecret,client_secret
同一個概念.
scope 指定客戶端申請的權限范圍,可選值包括read,write,trust;若有多個權限范圍用逗號(,)分隔,:
“read,write”. scope的值與security.xml中配置的‹intercept-urlaccess屬性有關系.
‹intercept-url的配置為‹intercept-url pattern="/m/**"
access=“ROLE_MOBILE,SCOPE_READ”/>則說明訪問該URL時的客戶端必須有read權限范
. write的配置值為SCOPE_WRITE, trust的配置值為SCOPE_TRUST. 在實際應該中, 該值一
般由服務端指定, 常用的值為read,write.
authorized_grant_types 指定客戶端支持的grant_type,可選值包括
authorization_code,password,refresh_token,implicit,client_credentials, 若支持多個
grant_type用逗號(,)分隔,: “authorization_code,password”. 在實際應用中,當注冊時,該字
段是一般由服務器端指定的,而不是由申請者去選擇的,最常用的grant_type組合有:
“authorization_code,refresh_token”(針對通過瀏覽器訪問的客戶端);
“password,refresh_token”(針對移動設備的客戶端). implicitclient_credentials在實際中
很少使用.
web_server_redirect_uri 客戶端的重定向URI,可為空, grant_typeauthorization_codeimplicit, Oauth的流
程中會使用並檢查與注冊時填寫的redirect_uri是否一致. 下面分別說明:
grant_type=authorization_code, 第一步 從 spring-oauth-server獲取 'code’時客戶端發
起請求時必須有redirect_uri參數, 該參數的值必須與 web_server_redirect_uri的值一致.
二步 用 ‘code’ 換取 ‘access_token’ 時客戶也必須傳遞相同的redirect_uri. 在實際應用中,
web_server_redirect_uri在注冊時是必須填寫的, 一般用來處理服務器返回的code, 驗證
state是否合法與通過code去換取access_token.spring-oauth-client項目中, 可具體參考
AuthorizationCodeController.java中的authorizationCodeCallback方法.
grant_type=implicit時通過redirect_urihash值來傳遞access_token.
:http://localhost:7777/spring-oauth-client/implicit#access_token=dc891f4a-ac88-
4ba6-8224-a2497e013865&token_type=bearer&expires_in=43199然后客戶端通過JS等從
hash值中取到access_token.
authorities 指定客戶端所擁有的Spring Security的權限值,可選, 若有多個權限值,用逗號(,)分隔, :
"ROLE_
字段名 字段說明
access_token_validity 設定客戶端的access_token的有效時間值(單位:),可選, 若不設定值則使用默認的有效時間
(60 * 60 * 12, 12小時). 在服務端獲取的access_token JSON數據中的expires_in字段的值
即為當前access_token的有效時間值. 在項目中, 可具體參考DefaultTokenServices.java中屬
accessTokenValiditySeconds. 在實際應用中, 該值一般是由服務端處理的, 不需要客戶端
自定義.refresh_token_validity 設定客戶端的refresh_token的有效時間值(單位:),可選,
若不設定值則使用默認的有效時間值(60 * 60 * 24 * 30, 30). 若客戶端的grant_type不包
refresh_token,則不用關心該字段 在項目中, 可具體參考DefaultTokenServices.java中屬
refreshTokenValiditySeconds. 在實際應用中, 該值一般是由服務端處理的, 不需要客戶端
自定義.
additional_information 這是一個預留的字段,Oauth的流程中沒有實際的使用,可選,但若設置值,必須是JSON格式的
數據,:{“country”:“CN”,“country_code”:“086”}按照spring-security-oauth項目中對該字段
的描述 Additional information for this client, not need by the vanilla OAuth protocol
but might be useful, for example,for storing descriptive information. (詳見
ClientDetails.javagetAdditionalInformation()方法的注釋)在實際應用中, 可以用該字段來
存儲關於客戶端的一些其他信息,如客戶端的國家,地區,注冊時的IP地址等等.create_time
數據的創建時間,精確到秒,由數據庫在插入數據時取當前系統時間自動生成(擴展字段)
archived 用於標識客戶端是否已存檔(即實現邏輯刪除),默認值為’0’(即未存檔). 對該字段的具體使用請
參考CustomJdbcClientDetailsService.java,在該類中,擴展了在查詢client_detailsSQL加上
archived = 0條件 (擴展字段)
trusted 設置客戶端是否為受信任的,默認為’0’(即不受信任的,1為受信任的). 該字段只適用於
grant_type="authorization_code"的情況,當用戶登錄成功后,若該值為0,則會跳轉到讓用戶
Approve的頁面讓用戶同意授權, 若該字段為1,則在登錄后不需要再讓用戶Approve同意授權
(因為是受信任的). 對該字段的具體使用請參考OauthUserApprovalHandler.java. (擴展字
)
autoapprove 設置用戶是否自動Approval操作, 默認值為 ‘false’, 可選值包括 ‘true’,‘false’, ‘read’,‘write’.
字段只適用於grant_type="authorization_code"的情況,當用戶登錄成功后,若該值為’true’
支持的scope,則會跳過用戶Approve的頁面, 直接授權. 該字段與 trusted 有類似的功能,
spring-security-oauth2 2.0 版本后添加的新屬性. 在項目中,主要操作
oauth_client_details表的類是JdbcClientDetailsService.java, 更多的細節請參考該類. 也可
以根據實際的需要,去擴展或修改該類的實現.
 
 
oauth_client_token
字段名 字段說明
create_time 數據的創建時間,精確到秒,由數據庫在插入數據時取當前系統時間自動生成(擴展字段)
token_id 從服務器端獲取到的access_token的值.
token 這是一個二進制的字段, 存儲的數據是OAuth2AccessToken.java對象序列化后的二進
制數據.
authentication_id 該字段具有唯一性, 是根據當前的username(如果有),client_idscope通過MD5加密
生成的. 具體實現請參考DefaultClientKeyGenerator.java.
user_name 登錄時的用戶名
client_id
該表用於在客戶端系統中存儲從服務端獲取的token數據, spring-oauth-server項目中未使用到.
oauth_client_token表的主要操作在JdbcClientTokenServices.java類中, 更多的細節請參考該類.
oauth_access_token
 
字段名 字段說明
create_time 數據的創建時間,精確到秒,由數據庫在插入數據時取當前系統時間自動生成(擴展字段)
token_id 該字段的值是將access_token的值通過MD5加密后存儲的.
token 存儲將OAuth2AccessToken.java對象序列化后的二進制數據, 是真實的AccessToken
的數據值.
authentication_id 該字段具有唯一性, 其值是根據當前的username(如果有),client_idscope通過MD5
加密生成的. 具體實現請參考DefaultAuthenticationKeyGenerator.java.
user_name 登錄時的用戶名, 若客戶端沒有用戶名(grant_type=“client_credentials”),則該值等
client_id
client_id
authentication 存儲將OAuth2Authentication.java對象序列化后的二進制數據.
refresh_token 該字段的值是將refresh_token的值通過MD5加密后存儲的. 在項目中,主要操作
oauth_access_token表的對象是JdbcTokenStore.java. 更多的細節請參考該類
 
oauth_refresh_token
字段名 字段說明
create_time 數據的創建時間,精確到秒,由數據庫在插入數據時取當前系統時間自動生成(擴展字段)
token_id 該字段的值是將refresh_token的值通過MD5加密后存儲的.
token 存儲將OAuth2RefreshToken.java對象序列化后的二進制數據.
authentication 存儲將OAuth2Authentication.java對象序列化后的二進制數據.
在項目中,主要操作oauth_refresh_token表的對象是JdbcTokenStore.java. (與操作oauth_access_token表的對象
一樣);更多的細節請參考該類. 如果客戶端的grant_type不支持refresh_token,則不會使用該表.
oauth_code
字段名 字段說明
create_time 數據的創建時間,精確到秒,由數據庫在插入數據時取當前系統時間自動生成(擴展字段)
code 存儲服務端系統生成的code的值(未加密).
authentication 存儲將AuthorizationRequestHolder.java對象序列化后的二進制數據.
在項目中,主要操作oauth_code表的對象是JdbcAuthorizationCodeServices.java. 更多的細節請參考該類。 只有當
grant_type"authorization_code",該表中才會有數據產生; 其他的grant_type沒有使用該表。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM