鑑於 spring security 與 oauth2.0標準過於繁瑣,爲方便理解與實際實現,故手寫其實現。css
如下部分參考自理解OAuth 2.0 - 阮一峯的網絡日誌html
OAuth 2.0的運行流程以下圖,摘自RFC 6749。 前端
(A)用戶打開客戶端之後,客戶端要求用戶給予受權。 (B)用戶贊成給予客戶端受權。 (C)客戶端使用上一步得到的受權,向認證服務器申請令牌。 (D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。 (E)客戶端使用令牌,向資源服務器申請獲取資源。 (F)資源服務器確認令牌無誤,贊成向客戶端開放資源。
(A)用戶訪問客戶端,後者將前者導向認證服務器。 (B)用戶選擇是否給予客戶端受權。 (C)假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個臨時受權碼。 (D)客戶端收到臨時受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。 (E)認證服務器覈對了臨時受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)。
(A)用戶向客戶端提供用戶名和密碼。 (B)客戶端將用戶名和密碼發給認證服務器,向後者請求令牌。 (C)認證服務器確認無誤後,向客戶端提供訪問令牌。
以某個**監測服務(web端)**爲例,嘗試登錄公司的SSO帳戶。git
DROP TABLE IF EXISTS `sys_oauth_client`; CREATE TABLE `sys_oauth_client` ( `client_id` varchar(50) NOT NULL COMMENT '客戶端id', `client_name` varchar(256) DEFAULT NULL COMMENT '應用名', `client_secret` varchar(256) DEFAULT NULL COMMENT '應用密鑰', `client_redirect_uri_host` varchar(256) DEFAULT NULL COMMENT '對應主機域名', `status` int(1) DEFAULT NULL COMMENT '狀態。0:正常;1:凍結', `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間', `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間', PRIMARY KEY (`client_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='應用client表'; BEGIN; INSERT INTO `sys_oauth_client` VALUES ('joe_monitoring', '監測服務(web端)', 'admin123', '','0', '2018-08-30 19:42:32', '2018-08-30 20:24:08'); COMMIT; DROP TABLE IF EXISTS `sys_oauth_user_authorize`; CREATE TABLE `sys_oauth_user_authorize` ( `id` int(20) NOT NULL AUTO_INCREMENT, `client_id` varchar(50) NOT NULL COMMENT '客戶端id', `oauth_user_id` varchar(50) NOT NULL COMMENT '綁定帳號的id,例如對應wx來講,就是openId', `user_id` int(11) NOT NULL COMMENT '對應user_id', `oauth_user_name` varchar(50) DEFAULT '' COMMENT '綁定帳號的名稱', UNIQUE KEY `Unique_client_idAnduser_id` (`client_id`,`user_id`) USING BTREE, UNIQUE KEY `Unique_client_idAndoauth_user_id` (`client_id`,`oauth_user_id`) USING BTREE, KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='帳號受權表'
技術選型上:springcloud
全家桶github
joe-sso
,即SSO服務joe-admin
joe-resource
joe-file
joe-client-monitoring
另:web
joe-eureka
joe-zuul
client_id
,在庫中爲joe_monitoring
joe-oauth
服務redirect_uri
字段temp_authorize_code
字段accessToken
字段監測服務(web端)
獲取自身的client_id
GET
請求,接口: joe-client-wechat/client/clientId
返回示例:redis
{ "status": 0, "msg": "成功。", "data": "joe_monitoring" }
登錄
頁面,並傳遞過來參數參數 | 示例 | 說明 |
---|---|---|
client_id | joe_monitoring | 客戶端id |
redirect_uri | http://localhost:9000/callback | 需重定向的uri |
eg:實際傳遞請求uri
spring
解釋:後端
passport.joe.com
:joe-sso
服務地址/authorize/login
: 受權碼模式登錄接口正常狀況下,oauth2.0模式下,受權碼模式,字段釋義:api
response_type:表示受權類型,必選項,此處的值固定爲"code" client_id:表示客戶端的ID,必選項 redirect_uri:表示重定向URI,可選項 scope:表示申請的權限範圍,可選項 state:表示客戶端的當前狀態,能夠指定任意值,認證服務器會原封不動地返回這個值。
eg,在新浪微博中,採用360帳號登錄,跳轉的url爲:
分析:上述uri,顯然爲oauth2.0模式下的受權碼登錄模式。
登錄
頁面的登錄GET
請求,接口: joe-sso/oauth/authorize/login
即 SSO帳戶系統的登錄系統下的「登錄」按鈕
參數 | 示例 | 說明 |
---|---|---|
client_id | joe_monitoring | 客戶端id |
redirect_uri | http://localhost:9000/callback | 需重定向的uri |
login_name | admin | 用戶名 |
password | admin | 密碼 |
temp_authorize_code
臨時受權碼 :{ "status": 0, "msg": "成功。該臨時受權碼有效期爲10分鐘", "data": { "temp_authorize_code": "joe_monitoring:28115fff54884bc0800442ffb51a3f98" } }
{ "status": 20, "msg": "失敗。joe-sso認證失敗,請檢查client_id的準確性,或該client_id已被凍結", "data": null }
{ "status": 30, "msg": "失敗。登錄名或密碼錯誤,用戶不存在", "data": null }
獲取到 臨時受權碼temp_authorize_code
後,登錄
頁面前端跳轉連接回監測服務(web端)
(經過redirect_uri)
注意:該temp_authorize_code
存儲在redis
中,設置好過時時間。
監測服務(web端)
嘗試向joe_sso
獲取accessToken上一步,咱們獲取到temp_authorize_code
。如今,將temp_authorize_code
發送給SSO服務,從而獲取accessToken。
監測服務(web端)
前端經過跳轉回的瀏覽器地址欄,獲取到對應到temp_authorize_code
後,發送GET
請求到監測服務(web端)
的後端,接口: joe-client-monitoring/client/accessToken
監測服務(web端)
的後端,將會添加本身的client_id
、client_secret
參數,一塊兒經過http
發送給joe-sso帳戶服務
,獲取accessToken。
對應接口joe-sso帳戶服務
的獲取accessToken接口爲:http://passport.joe.com/authorize/accessToken
參數 | 示例 | 說明 |
---|---|---|
client_id | joe_monitoring | 客戶端id |
client_secret | admin123 | 客戶端密鑰 |
redirect_uri | http://localhost:9000/callback | 需重定向的uri,和上一步驟一致 |
temp_authorize_code | joe_monitoring:52d1595aeba64b4fa087c9c96ab42bb2 | 臨時受權碼 |
eg:實際傳遞請求uri
返回結果:
{ "status":0, "msg":"成功。該access_token有效期爲120分鐘,下次請求將重置有效期", "data":"joe_monitoring:d29d492c678640a6b3952c4fb0dc24be" }
該accessToken有效期120分鐘,後續每次請求會重置有效期(相似session的功能)。後期考慮添加:超時1天后,強制失效從新登錄的功能。
注意:
獲取accessToken
存儲在redis
中,設置好過時時間。監測服務(web端)
須要將對應的 accessToken 自行存儲起來(jvm cache或 redis中都可)。注意:該請求過程,對於用戶來講,是無感知的。
至此,受權服務已基本完成。
微信客戶端
獲取用戶信息 by accessTokenGET
請求,接口: joe-sso/oauth/userInfo
http
的header
中添加joe_access_token
,即
參數 | 示例 | 說明 |
---|---|---|
joe_access_token | joe_monitoring:52d1595aeba64b4fa087c9c96ab42bb2 | 即第3.4步驟中,微信客戶端 嘗試獲取的accessToken |
返回結果:
{ "status": 0, "msg": "成功。", "data": { "create_time": "2018-09-11 10:16:12", "user_id": 1, "user_name": "admin", "user_nick_name": "我是用戶暱稱joe", "redirect_uri": "http://localhost:9000/callback" } }
文中所述功能均已實現。具體代碼,後期將視狀況發佈至github
上。地址爲:github倉庫地址