本系列針對Security-Oauth2架構的剖析,包括:oauth2.0認證架構詳解、架構源碼解讀、核心結構配置。
本篇是對oauth2認證流程的概述,喜歡的多多pick!
內容引用書籍:The OAuth 2.0 Authorization Framework
1.1 角色
OAuth定義了四個角色:
資源所有者一個能夠授權訪問受保護資源的實體。當資源所有者是一個人時,它被稱為最終用戶。
資源服務器
托管受保護資源的服務器能夠使用訪問令牌接受和響應受保護的資源請求。
客戶
代表資源所有者及其授權的應用程序進行受保護的資源請求。術語客戶端並不意味着任何特定的實現特征(例如,應用程序是在服務器,台式機還是其他設備上執行的)。
授權服務器
服務器在成功認證資源所有者並獲得授權后向客戶端發放訪問令牌。
授權服務器和資源服務器之間的交互超出了本規范的范圍。授權服務器可以是與資源服務器相同的服務器或獨立的實體。一個授權服務器可能會發出多個資源服務器接受的訪問令牌。
1.2 協議流程
圖1中所示的抽象OAuth 2.0流程描述了四個角色之間的交互,並包含以下步驟:

(A)
客戶端請求資源所有者的授權。授權請求可以直接給資源所有者(如圖所示),或者優選間接地通過授權服務器作為中介。
(B)
客戶端接收授權許可,這是一種代表資源所有者授權的憑證,使用本規范中定義的四種授權類型之一或使用擴展授權類型表示。授權授予類型取決於客戶端用於請求授權的方法以及授權服務器支持的類型。
(C)
客戶端通過向授權服務器進行認證並攜帶授權來請求訪問令牌。
(D)
授權服務器對客戶端進行身份驗證並驗證授權,並且如果有效則發出訪問令牌。
(E)
客戶端從資源服務器請求受保護的資源並通過攜帶訪問令牌進行認證。
(F)
資源服務器驗證訪問令牌,並且如果有效,則為該請求提供服務。
客戶從資源所有者(步驟(A)和(B)中描述)獲得授權許可的首選方法是使用授權服務器作為中介
2 模式
oauth2根據使用場景不同,分成了4種模式
● 客戶端模式(client credentials)
● 密碼模式(resource owner password credentials)
● 授權碼模式(authorization code)
● 簡化模式(implicit)
Oauth基於客戶端與認證服務器驗證的能力定義了兩種客戶端類型(以及,維護客戶端認證信息的能力): 客戶端模式、密碼模式。
基礎參數定義:
grant_type (發放令牌類型)、
client_id (客戶端標識id)
username(用戶帳號)
password (用戶密碼)
client_secret(客戶端標識密鑰)
refresh_token (刷新令牌)
scope(表示權限范圍,可選項)
2.1 客戶端模式
認證服務器給客戶端下發客戶端標識--一個代表了注冊信息的唯一字符串。客戶端標識不是秘密;它被暴露給資源擁有者,並且不能單獨用來客戶端驗證。客戶端標識對認證服務器來說是唯一的。(A)客戶端直接向認證服務器獲取令牌介。
(B)認證服務器確認無誤后,向客戶端提供訪問令牌。
(C) 客戶端攜帶令牌訪問資源端
常用於訪問公共資源(無需登錄):網站首頁
該模式沒有refresh_token,過期可以直接認證獲取匿名令牌。
樣例:
請求參數
grant_type:client_credentials
client_id:46582ae7217343a8b252e3977e7cc421
client_secret:cgGvf5Rotv7D76m9JaArfY3YG6fDec47
結果
{
"access_token": "9fae1382-8d9c-4c64-a01c-d67817137fd4",
"token_type": "bearer",
"expires_in": 27689,
"scope": "read write"
}
2.2 密碼端模式
密碼模式在客戶端基礎上,從用戶方獲取帳號密碼,再訪問授權服務器認證授權。
(A)客戶端從用戶方獲取帳號密碼。
(B)客戶端攜帶用戶信息向認證服務器獲取令牌介。
(B)認證服務器確認無誤后,向客戶端提供訪問令牌。
(c) 客戶端攜帶令牌訪問資源端
常用於訪問個人資源(必須登錄):個人資料
樣例:
請求參數
grant_type:password
client_id:46582ae7217343a8b252e3977e7cc421
username:18565783136
password:AC1DAdo9ZcY4dKAdtyPRzoICWZlkR7WDgtO06S5fVCUS6A/67rMxeW+2mKKbo2N1FQ==
client_secret:cgGvf5Rotv7D76m9JaArfY3YG6fDec47
結果
{
"access_token": "41d74d86-bd30-4935-a6f1-c61614a1b72b",
"token_type": "bearer",
"refresh_token": "1ba402f7-394b-420b-9805-39578d6176f8",
"expires_in": 30063,
"scope": "read write"
}
2.3 授權碼模式
授權碼模式(authorization code)是功能最完整、流程最嚴密的授權模式。它的特點就是通過客戶端的后台服務器,與"服務提供商"的認證服務器進行互動。 (A)用戶訪問客戶端,后者將前者導向認證服務器(一個獲取授權的頁面)。
(B)用戶選擇是否給予客戶端授權。
(C)假設用戶給予授權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個授權碼。
(D)客戶端收到授權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的后台的服務器上完成的,對用戶不可見。
(E)認證服務器核對了授權碼和重定向URI,確認無誤后,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。
常用於 第三方登錄,例如:QQ登錄網易音樂。
樣例:
GET oauth-server/authorize?response_type=code&client_id=cgGvf5Rotv7D76m9JaArfY3YG6fDec47&state=userId
&redirect_uri=www.baidu.com
state:表示客戶端的當前狀態,可以指定任意值,認證服務器會原封不動地返回這個值。(常用:用戶標識)
重定向:
www.baidu.com?code=SplxlOBeZQQYbYS6WxSbIA&state=userId
獲取code
GET oauth-server/grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=www.baidu.com
結果
{
"access_token": "41d74d86-bd30-4935-a6f1-c61614a1b72b",
"token_type": "bearer",
"refresh_token": "1ba402f7-394b-420b-9805-39578d6176f8",
"expires_in": 30063,
"scope": "read write"
}
2.4 簡化模式
不通過第三方應用程序的服務器,直接在瀏覽器中向認證服務器申請令牌,跳過了"授權碼"這個步驟,即沒有code,直接返回令牌。
(A)客戶端將用戶導向認證服務器。
(B)用戶決定是否給於客戶端授權。
(C)假設用戶給予授權,認證服務器將用戶導向客戶端指定的"重定向URI",並在URI的Hash部分包含了訪問令牌。
(D)客戶端(第三方服務器)獲取到令牌。
樣例:
GET oauth-server/authorize?response_type=token&client_id=cgGvf5Rotv7D76m9JaArfY3YG6fDec47&state=userId
&redirect_uri=www.baidu.com
重定向:www.baidu.com?access_token=41d74d86-bd30-4935-a6f1-c61614a1b72b&state=userId
3 刷新令牌
當訪問令牌過期時候,刷新重新獲取令牌。
樣例:
請求參數
grant_type:refresh_token
client_id:46582ae7217343a8b252e3977e7cc421
client_secret:cgGvf5Rotv7D76m9JaArfY3YG6fDec47
refresh_token:1ba402f7-394b-420b-9805-39578d6176f8
結果
{
"access_token": "6d8cffd1-a90e-4846-838f-176050ed49b4",
"token_type": "bearer",
"refresh_token": "1ba402f7-394b-420b-9805-39578d6176f8",
"expires_in": 43199,
"scope": "read write"
}
依賴
pom引入security-oauth2依賴<dependency> <groupId>com.happylifeplat</groupId> <artifactId>security-crypto</artifactId> <version>1.0-RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency>
案例基於JdbcTokenStore,需要配置數據庫
CREATE TABLE `oauth_access_token` ( `authentication_id` varchar(128) NOT NULL COMMENT '身份驗證ID', `token_id` varchar(128) DEFAULT NULL COMMENT '令牌ID', `token` blob COMMENT '令牌', `user_name` varchar(256) DEFAULT NULL COMMENT '用戶名', `client_id` varchar(128) DEFAULT NULL COMMENT '客戶端ID', `authentication` blob COMMENT '認證體', `refresh_token` varchar(256) DEFAULT NULL COMMENT '刷新令牌', PRIMARY KEY (`authentication_id`), KEY `PK_token_id` (`token_id`) USING BTREE, KEY `PK_refresh_token` (`refresh_token`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth_approvals` ( `userId` varchar(128) DEFAULT NULL, `clientId` varchar(128) DEFAULT NULL, `scope` varchar(256) DEFAULT NULL, `status` varchar(10) DEFAULT NULL, `expiresAt` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `lastModifiedAt` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `id` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth_client` ( `id` varchar(128) NOT NULL COMMENT '客戶端id', `name` varchar(256) DEFAULT NULL COMMENT '客戶端名稱', `disabled` bit(1) NOT NULL DEFAULT b'0', `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客戶端表'; CREATE TABLE `oauth_client_details` ( `client_id` varchar(128) NOT NULL COMMENT '客戶端id', `resource_ids` varchar(256) DEFAULT NULL COMMENT '客戶端所能訪問的資源id集合', `client_secret` varchar(256) DEFAULT NULL COMMENT '客戶端訪問密匙', `scope` varchar(256) DEFAULT NULL COMMENT '客戶端申請的權限范圍', `authorized_grant_types` varchar(256) DEFAULT NULL COMMENT '授權類型', `web_server_redirect_uri` varchar(256) DEFAULT NULL COMMENT '客戶端重定向URI', `authorities` varchar(256) DEFAULT NULL COMMENT '客戶端權限', `access_token_validity` int(11) DEFAULT NULL COMMENT 'access_token的有效時間(單位:秒)', `refresh_token_validity` int(11) DEFAULT NULL COMMENT 'refresh_token的有效時間(單位:秒)', `additional_information` varchar(4096) DEFAULT NULL COMMENT '預留字段,JSON格式', `autoapprove` varchar(256) DEFAULT NULL COMMENT '否自動Approval操作', PRIMARY KEY (`client_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客戶端詳情'; CREATE TABLE `oauth_client_token` ( `authentication_id` varchar(128) NOT NULL COMMENT '身份驗證ID', `token_id` varchar(128) DEFAULT NULL COMMENT '令牌ID', `token` blob COMMENT '令牌', `user_name` varchar(256) DEFAULT NULL COMMENT '用戶名', `client_id` varchar(256) DEFAULT NULL COMMENT '客戶端ID', PRIMARY KEY (`authentication_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth_code` ( `code` varchar(256) DEFAULT NULL, `authentication` blob, `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth_refresh_token` ( `token_id` varchar(128) DEFAULT NULL COMMENT '令牌ID', `token` blob COMMENT '令牌', `authentication` blob COMMENT '認證體', `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1539 DEFAULT CHARSET=utf8mb4; CREATE TABLE `oauth_resource` ( `id` varchar(128) NOT NULL, `name` varchar(256) DEFAULT NULL, `alias` varchar(256) DEFAULT NULL, `describe` varchar(256) DEFAULT NULL, `disabled` bit(1) NOT NULL DEFAULT b'0', `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='資源表';