手寫oauth2.0(附mysql表設計與具體交互流程)

鑑於 spring security 與 oauth2.0標準過於繁瑣,爲方便理解與實際實現,故手寫其實現。css

一、oauth2.0介紹

如下部分參考自理解OAuth 2.0 - 阮一峯的網絡日誌html

OAuth 2.0的運行流程以下圖,摘自RFC 6749。 image前端

(A)用戶打開客戶端之後,客戶端要求用戶給予受權。
(B)用戶贊成給予客戶端受權。
(C)客戶端使用上一步得到的受權,向認證服務器申請令牌。
(D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。
(E)客戶端使用令牌,向資源服務器申請獲取資源。
(F)資源服務器確認令牌無誤,贊成向客戶端開放資源。

1.一、oauth2.0-受權碼模式介紹

image

(A)用戶訪問客戶端,後者將前者導向認證服務器。 
(B)用戶選擇是否給予客戶端受權。 
(C)假設用戶給予受權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個臨時受權碼。 
(D)客戶端收到臨時受權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的後臺的服務器上完成的,對用戶不可見。 
(E)認證服務器覈對了臨時受權碼和重定向URI,確認無誤後,向客戶端發送訪問令牌(access token)。

1.二、oauth2.0-密碼模式介紹

image

(A)用戶向客戶端提供用戶名和密碼。
(B)客戶端將用戶名和密碼發給認證服務器,向後者請求令牌。
(C)認證服務器確認無誤後,向客戶端提供訪問令牌。

二、邏輯交互

以某個**監測服務(web端)**爲例,嘗試登錄公司的SSO帳戶。git

2.一、受權碼模式實現

2.1.一、表結構設計

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

2.1.二、各個服務

  • 認證與受權服務:joe-sso,即SSO服務
  • 用戶、權限管理服務: joe-admin
  • api資源服務: joe-resource
  • 靜態文本資源(css、js、img等)服務:joe-file
  • 監測服務:joe-client-monitoring

另:web

  • 註冊中心:joe-eureka
  • 網關:joe-zuul

2.1.三、名詞解釋

  • 客戶端:這裏指代 監測服務(web端); 其對應的client_id,在庫中爲joe_monitoring
  • 認證服務器: 這裏指代 joe-oauth服務
  • 重定向URI: 即下文中的 redirect_uri字段
  • 臨時受權碼:即下文中的 temp_authorize_code字段
  • 訪問令牌:即下文中的 accessToken字段

三、接口請求

3.一、監測服務(web端)獲取自身的client_id

GET請求,接口: joe-client-wechat/client/clientId 返回示例:redis

{
  "status": 0,
  "msg": "成功。",
  "data": "joe_monitoring"
}

3.二、前端跳轉到登錄頁面,並傳遞過來參數

  • 傳遞參數(以web瀏覽器爲例,將其以get傳參的形式,暴露在地址欄中):
參數 示例 說明
client_id joe_monitoring 客戶端id
redirect_uri http://localhost:9000/callback 需重定向的uri

eg:實際傳遞請求urispring

解釋:後端

  • passport.joe.comjoe-sso服務地址
  • /authorize/login: 受權碼模式登錄接口

正常狀況下,oauth2.0模式下,受權碼模式,字段釋義:api

response_type:表示受權類型,必選項,此處的值固定爲"code"
client_id:表示客戶端的ID,必選項
redirect_uri:表示重定向URI,可選項
scope:表示申請的權限範圍,可選項
state:表示客戶端的當前狀態,能夠指定任意值,認證服務器會原封不動地返回這個值。

eg,在新浪微博中,採用360帳號登錄,跳轉的url爲:

https://openapi.360.cn/oauth2/authorize?client_id=8819d1babbbc50a42021ee957c4b6e63&response_type=code&redirect_uri=https://account.weibo.com/set/bindsns/callback&scope=basic&display=default&state=360&relogin=sina

分析:上述uri,顯然爲oauth2.0模式下的受權碼登錄模式。

3.三、登錄頁面的登錄

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中,設置好過時時間。

3.四、監測服務(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_idclient_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中都可)。

注意:該請求過程,對於用戶來講,是無感知的。

至此,受權服務已基本完成。

3.五、微信客戶端獲取用戶信息 by accessToken

GET請求,接口: joe-sso/oauth/userInfo

  • 傳遞參數:

httpheader中添加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倉庫地址

參考連接:

相關文章
相關標籤/搜索