簡介

OAuth 2 是一種授權框架,允許第三方應用通過用戶授權的形式訪問服務中的用戶信息,最常見的場景是授權登錄;再複雜一點的比如第三方應用通過 Github 給開發者提供的介面訪問許可權內的用戶信息或倉庫信息。OAuth2 廣泛應用於 web 、桌面應用、移動 APP 的第三方服務提供了授權驗證機制,以此實現不同應用間的數據訪問許可權。 下面分別從不同角色、授權類型、使用場景及流程的緯度詳細介紹 OAuth2

OAuth Roles

OAuth 定義了四種角色

  • 資源擁有者 (Resource Owner)
  • 客戶端 (Client)
  • 資源伺服器 (Resource Server)
  • 授權伺服器 (Authorization Server)

資源擁有者其實就是真實的用戶,用戶授權給第三方應用訪問在其他系統的用戶信息。第三方應用訪問授權用戶的信息範圍 scope 屬於申請接入服務時選擇的許可權之內(例如:讀或寫訪問許可權)

資源服務控制用戶的信息,授權服務驗證用戶提供的信息是否正確並返回 access token 給第三方應用。 站在第三方開發者的角度看,被接入的系統提供的服務 API 同時實現了資源和授權角色。在這裡把資源服務端和授權服務端統一為「服務角色或 API 角色」。

客戶端就是要求接入的第三方應用,獲取用戶在提供服務的系統的賬戶信息。對於客戶端而言,最終獲取到用戶在服務端的賬戶信息首先需要用戶授權,用戶授權後傳給提供服務端驗證成功之後返回 access token ,在通過 access token 請求提供服務的系統(在這裡我們成為 API ,下文也是)獲取用戶在 API 中的賬戶信息。

授權流程

接下來文中提到的客戶端均為第三方應用,服務端均為被接入的服務。譬如拉勾網有微博登錄功能,那麼拉勾網就是客戶端,微博就是服務端。

上一節解釋了 OAuth 系統中角色的概念,接下來可以解釋整個授權的流程。

流程圖解釋:

  1. 用戶點擊客戶端提供的授權請求
  2. 客戶端請求服務的授權頁面呈現給用戶,用戶點擊確認授權後服務端返回授權許可憑證給客戶端
  3. 客戶端通過步驟二接收到的授權許可憑證及在服務端註冊的應用信息請求服務端
  4. 如果步驟三驗證通過服務端則返回 access token 給客戶端
  5. 客戶端通過第四步獲取的 access token 請求服務端獲取資源
  6. 如果服務端校驗 access token 成功,則返回指定資源給客戶端

以上步驟是 OAuth2 授權登錄的步驟,當然不同類型的授權許步驟會不一樣,下文會詳細逐一討論。

第三方應用創建

第三方接入某平臺的 OAuth 2 服務之前,通常需要在平臺提供的註冊網站(通常叫做 developer" or "API")新建一個應用,註冊成功之後平臺會生成應用的 ID 和密碼。 讀者可以訪問 Github 的開發中心看看,國內寫的規範的有 coding developer

在平臺的註冊頁面至少得提供如下信息

  • 應用名稱
  • 應用網址
  • 回調鏈接

回調域名的作用:用戶點擊同意按鈕之後,服務端向客戶端返回授權碼或 access token ,當然如果是禁止操作也需回調告知客戶端結果。

在 OAuth 2 服務提供平臺新建一個應用之後,平臺會提供一對客戶端 ID 和密碼作為客戶端憑證。客戶端 ID 是可以公開的字元串,用以構建授權請求鏈接;用戶授權之後,客戶端使用服務端的授權碼和平臺分配的密碼獲取 access token 。密碼應當妥善保管以免泄漏。

授權許可

在第一張授權流程圖中,前四步包含了獲取授權許可獲取 access token ,授權許可有四種類型,服務端返回哪種類型取決於客戶端在請求鏈接中構建的 response_type 參數。四種類型的授權許可有不同的應用場景:

  • 授權碼:通過授權碼,服務端通過 Ajax 把 access token 返回給客戶端
  • 隱式:用於移動 APP 或 web 應用(應用運行在用戶的設備上)
  • 用戶密碼憑證:同一個公司不同系統之間內部賬戶互聯互通,比如國內某社區的代碼託管系統通過社區的賬戶也可以登錄。
  • 客戶端憑證:第三方應用自身服務訪問提供 OAuth2 服務提供的平臺資源

授權碼 (Grant Type: Authorization Code)

授權碼是 OAuth2 授權最廣泛的方式,得益於平臺給第三方應用分配的 ID 和密碼都是隱藏在第三方應用的後端代碼中。因為授權碼是基於重定向的方式,要想使用授權碼的方式,第三方應用必須能夠調用用戶系統中的應用(譬如瀏覽器)、和提供一個介面接收平臺服務的回調獲取授權碼。

一步步解釋授權碼的流程圖

步驟一:構建獲取授權碼請求鏈接

下文提到的例子都是基於 digiterocean 的 OAuth2

第一步是構建一個請求 Auth Server 獲取授權碼的鏈接,向服務端發起請求

https://cloud.digitalocean.com/v1/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read

分解請求鏈接:

  • cloud.digitalocean.com/ 表示服務端授權 endpoint
  • client_id 平臺分配給第三方應用的 ID
  • redirect_uri=CALLBACK_URL 第三方開發者在平臺新建第三方應用時填寫的回調 URL
  • response_type=code 指定服務端返回授權碼
  • scope=read 指定第三方應用請求許可權類型

步驟二:用戶授權給第三方應用

當用戶點擊第一步構建的鏈接之後,在用戶已經登錄服務端之後才能點擊確認授權(譬如想通過微信登錄某個第三方網址,你必須首先已經登錄微博)。這是平臺會給用戶提供一個頁面給用戶確認是否授權。

步驟三:服務端給客戶端返回授權碼

當用戶點擊同意授權之後,服務端發起一個請求重定向到第三方平臺填寫的回調鏈接,且請求鏈接中同時包含了服務端生成的授權碼。

https://dropletbook.com/callback?code=AUTHORIZATION_CODE

步驟四:第三方應用請求服務端,獲取 access token

客戶端獲取到服務端返回的授權碼之後,接著使用授權碼和平臺分配的密碼請求服務端獲取服務端的 access token 。第三方應用後端代碼拼接的 URL 格式形似:

https://cloud.digitalocean.com/v1/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL

在這裡需注意兩個參數,其一是 client_secret 沒有暴露出去,在第三方應用後端代碼中拼接請求鏈接;另一是 redirect_uri ,這裡不是在平臺新建應用時填寫的回調鏈接,而是第三方應用已經實現的另一個 action 處理服務端返回 access token 的請求。

步驟五:第三方應用接收 access token

如果第四部客戶端發送的信息被服務端校驗成功,服務端則返回 access token ,有一些平臺同時也同時傳遞 refresh token 。返回的 json 信息形似:

{"access_token":"ACCESS_TOKEN","token_type":"bearer","expires_in":2592000,"refresh_token":"REFRESH_TOKEN","scope":"read","uid":100101,"info": { "name":"Mark E. Mark", "email":"[email protected]" }}

至此,已經走完 oauth 2 授權碼的方式所有流程。在 access_token 沒有失效的前提下,可通過 access_token 可以訪問平臺服務端提供的資源。另外如果還提供了 refresh_token ,在 access_token 失效的情況下,可以通過 refresh_token 再次去獲取有效的 access_token 。

隱式 (Grant Type: Implicit)

相比授權碼的授權許可這種後端實現,隱式授權類型在應用於前端實現(移動客戶端或者瀏覽器),其缺陷就是並不保證平臺分配給第三方平臺的密碼憑證足夠安全。隱式授權同樣也是基於重定向的方式,但是 access_token 通過網頁重定向返回給第三方平臺而不是通過介面調用的方式 暴露了 access_token 在重定向鏈接中,這點和授權碼不同。另外,也不支持服務端校驗客戶端第三方應用密碼,只是依賴在平臺新建應用是填寫的回調鏈接。

隱式授權不支持 refresh_token

授權大概流程如下:用戶請求授權,同意授權後服務端把 access_token 拼接到回調鏈接上通過瀏覽器重定向到客戶端,然後客戶端獲取到 access_token 。

通過流程圖可看出在第三步和授權碼不用的是服務端重定向到網頁而不是通過介面把 access_token 返回給客戶端。

步驟一:構建隱式授權請求鏈接

與授權碼的步驟一差不多一致,只是 response_type 欄位的參數值為 token

步驟二:用戶授權給第三方

與授權碼授權的步驟二完全一致

步驟三:通過服務端重定向鏈接,User-agent (瀏覽器或者 APP) 獲取 access_token

與授權碼不同的是,用戶點擊授權之後服務端通過把 access_token 通過網頁重定向到回調鏈接,客戶端通過重定向鏈接才能獲取到 access_token ;而授權碼獲取 access_token 是通過服務端通過 ajax 請求的形式直接訪問第三方應用的後端介面,把 access_token 傳給第三方後端。

第四步:前端根據重定向調整

前端瀏覽器重定向請求第三方平臺的後端

第五步:第三方應用後端通過腳本獲取在重定向鏈接中的 access_token

第三方應用後端通過腳本獲取在重定向鏈接上的 access_token

第六步:User-Agent 執行第三方應用後端返回的腳本把 access_token 返回給第三方平臺後端。

用戶密碼憑證

用戶直接給第三方應用提供在提供服務端賬號密碼,獲取服務端的 access_token 。這種授權方式常用於一個企業不同服務之間的賬號互聯互通。 用戶給第三方應用提供賬號密碼之後,客戶端發送 POST 請求給服務端獲取 access_token

https://oauth.example.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID

如果服務端校驗客戶端(第三方應用)傳過來的賬戶密碼正確,則把 access_token 返回給客戶端,用戶授權完成。

客戶端憑證

這種授權方式常用於第三方應用想要更改自身在服務提供方註冊的應用信息,比如更改應用描述或回調鏈接地址。

第三方應用通過發送服務端分配的 ID 和密碼給後端校驗,POST 的 URL 格式形似:

https://oauth.example.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

Access Token 和 Refresh Token

第三方應用從服務提供平臺獲取到有效的 access_token 之後,即可根據平臺提供的介面訪問服務端的資源。

curl -X POST -H "Authorization: Bearer ACCESS_TOKEN""https://api.digitalocean.com/v2/$OBJECT"

如果服務提供平臺支持 refresh_token ,那麼第三方應用的 access_token 失效之後,可通過 refresh_token 再次獲取有效的 access_token

例如 digitalocean 支持第三方應用通過 POST 請求再此獲取有效的 access_token

https://cloud.digitalocean.com/v1/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN

推薦閱讀:

相關文章