OAuth是一個開發標準,容許用戶受權第三方網站或應用訪問他們存儲在另外的服務提供者上的信息,而不須要將用戶名和密碼提供給第三方網站或分享他們數據的內容。web
OAuth 2.0不兼容1.0。shell
RO (resource owner): 資源全部者,對資源具備受權能力的人。瀏覽器
RS (resource server): 資源服務器,它存儲資源,並處理對資源的訪問請求。安全
Client: 第三方應用,它得到RO的受權後即可以去訪問RO的資源。服務器
AS (authorization server): 受權服務器,它認證RO的身份,爲RO提供受權審批流程,並最終頒發受權令牌(Access Token)。app
在開放受權中,第三方應用(Client)多是一個Web站點,也多是在瀏覽器中運行的一段JavaScript代碼,還多是安裝在本地的一個應用程序。這些第三方應用都有各自的安全特性。對於Web站點來講,它與RO瀏覽器是分離的,它能夠本身保存協議中的敏感數據,這些密鑰能夠不暴露給RO;對於JavaScript代碼和本地安全的應用程序來講,它原本就運行在RO的瀏覽器中,RO是能夠訪問到Client在協議中的敏感數據。 OAuth2.0爲了支持這些不一樣類型的第三方應用,提出了下面四種受權類型:性能
受權碼 (Authorization Code Grant),適用於有server端的應用受權。網站
隱式受權 (Implicit Grant),適用於經過客戶端訪問的應用受權。加密
資源全部者密碼憑證許可 (Resource Owner Password Credentials Grant),OAuth簡化版,經常使用於移動應用認證,稱爲xAuth。spa
受保護資源的客戶端受權 (Client Credentials Grant)。
流程 | Response Type(第一次請求) | Grant Type(第二次請求) | 可帶Refresh Token | 說明 |
---|---|---|---|---|
受權碼 | code | authorization_code | 是 | 常規流程 |
Implicit | token | - | 否 | 適用於純JS程序 |
用戶認證 | - | password | 是 | 客戶端高度可信,且受權碼流程不方便實施 |
客戶端 | - | client_credentials | 否 | 客戶端高度可信,擁有被操做資源(自用型),或操做非敏感資源 |
Authorization code 受權適用於PC,無線客戶端等須要和第三方server進行交互的應用場景。使用Authorization code受權,第三方可以集中處理用戶的受權請求和受權結果,適用於有server端的應用。
Authorization code受權模式分爲兩步,首先獲取authorization code,而後用code獲取acces token。 示意圖:
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI ---->| | | User- | | Authorization | | Agent -+----(B)-- User authenticates --->| Server | | | | | | -+----(C)-- Authorization Code ---<| | +-|----|---+ +---------------+ | | ^ v (A) (C) | | | | | | ^ v | | +---------+ | | | |>---(D)-- Authorization Code ---------' | | Client | & Redirection URI | | | | | |<---(E)----- Access Token -------------------' +---------+ (w/ Optional Refresh Token) Note: The lines illustrating steps (A), (B), and (C) are broken into two parts as they pass through the user-agent.
交互圖:
+--------+ +---------------+ | |--(A)------- Authorization Grant --------->| | | | | | | |<-(B)----------- Access Token -------------| | | | & Refresh Token | | | | | | | | +----------+ | | | |--(C)---- Access Token ---->| | | | | | | | | | | |<-(D)- Protected Resource --| Resource | | Authorization | | Client | | Server | | Server | | |--(E)---- Access Token ---->| | | | | | | | | | | |<-(F)- Invalid Token Error -| | | | | | +----------+ | | | | | | | |--(G)----------- Refresh Token ----------->| | | | | | | |<-(H)----------- Access Token -------------| | +--------+ & Optional Refresh Token +---------------+
一、獲取Authorization Code請求參數
client_id 必須 分配給應用的appid
redirect_uri 必須 受權回調地址,必須和應用註冊的地址一致
response_type 必須 受權類型,此值固定爲「code」
state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功受權後回調時會原樣帶回。請務必嚴格按照流程檢查用戶與state參數狀態的綁定。
scope 可選 授予權限範圍
其餘參數
若是用戶成功受權,則會跳轉到指定的回調地址,並在redirect_uri地址後帶上Authorization Code和原始的state值 二、經過Authorization Code獲取Access Token請求參數
client_id 必須 分配給應用的appid
grant_type 必須 受權類型,此值爲:authorization_code
client_secret 必須 分配給應用的secret
state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功受權後回調時會原樣帶回。請務必嚴格按照流程檢查用戶與state參數狀態的綁定。
redirect_uri 必須 與上面一步中傳入的redirect_uri保持一致
code 必須 上一步返回的Authorization Code值(必須設定此code的有效時間)
返回參數
access_token 必須 受權令牌
expires_in 必須 該access_token的有效期
refresh_token 可選 在受權自動續期步驟中,獲取新的Access_Token時須要提供的參數
其餘參數 可選
三、[可選] 權限自動續期,獲取access_token Access_token通常須要根據應用特性設定有效期,過時後須要用戶從新受權或採用自動續期的方式。請求參數
grant_type 必須 受權類型,在本步驟中,此值爲「refresh_token」
client_id 必須 分配給應用的appid
refresh_token 必須 第二步返回的refresh_token
client_secret 必須 分配給應用的secret
若是受權成功,則會返回和步驟二一樣的結果。
Implicit受權通常適用於沒有server端的客戶端應用,由客戶端發起受權請求,保存和處理access_token,但有些應用(如web應用等)爲了提升用戶體驗,簡化受權過程,也會常採用Implicit受權方式(注意,這種受權方式沒有返回refresh_token。)
示意圖:
+----------+ | Resource | | Owner | | | +----------+ ^ | (B) +----|-----+ Client Identifier +---------------+ | -+----(A)-- & Redirection URI --->| | | User- | | Authorization | | Agent -|----(B)-- User authenticates -->| Server | | | | | | |<---(C)--- Redirection URI ----<| | | | with Access Token +---------------+ | | in Fragment | | +---------------+ | |----(D)--- Redirection URI ---->| Web-Hosted | | | without Fragment | Client | | | | Resource | | (F) |<---(E)------- Script ---------<| | | | +---------------+ +-|--------+ | | (A) (G) Access Token | | ^ v +---------+ | | | Client | | | +---------+ Note: The lines illustrating steps (A) and (B) are broken into two parts as they pass through the user-agent.
交互圖:
+----------+ | Resource | | Owner | | | +----------+ v | Resource Owner (A) Password Credentials | v +---------+ +---------------+ | |>--(B)---- Resource Owner ------->| | | | Password Credentials | Authorization | | Client | | Server | | |<--(C)---- Access Token ---------<| | | | (w/ Optional Refresh Token) | | +---------+ +---------------+
請求參數
response_type 必須 受權類型,在本步驟中,此值爲「token」
client_id 必須 分配給應用的appid
redirect_uri 必須 受權回調地址,必須和應用註冊的地址一致
scope 可選 授予權限範圍
state 必須 client端的狀態值。用於第三方應用防止CSRF攻擊,成功受權後回調時會原樣帶回。請務必嚴格按照流程檢查用戶與state參數狀態的綁定。
其餘參數 可選
若是成功受權,則會跳轉到redirect_uri指定的回調地址,並帶上access_token、expires_in、state以及與應用相關的參數。注意,這種受權方式沒有返回refresh_token。
該受權方式獲取access token通常只有一步,相似以下GET/POST請求:https://open.xxx.com/oauth2/access_token?client_id=xxxx&client_secret=xxxxx&grant_type=password&username=xxx&password=xxx
服務器角色區分:受權服務器和資源服務器
區別不一樣的用戶類型、受權場景和受權流程
將token分爲頻繁傳輸使用可是有效時長較短的Access Token和用於更新Access Token的Refresh Token
定義多種token,下降資源請求的構造難度
受權過程不簽名,可根據須要採用HTTPS加密傳輸、驗證客戶端密鑰(經過簽名)、客戶端註冊時預先指定callback地址等手段。
明確引入客戶端註冊流程:肯定Client Type、callback URL以及其它信息
引入可選的state參數,幫助客戶端防範CSRF和管理狀態
引入scope參數,能夠進行受權範圍控制
token type等可被擴展: bearer(HTTPS), mac(HTTP+sign), etc.
只支持HTTPS(bears),不支持簽名(簽名是走之前老的受權方式)
受權過程指定的callback URL必須與註冊的callback URL在同一個域名,或者爲um:ietf:wg:oauth:2.0:oob(表示只顯示受權碼,不回調callback URL)
接口分不一樣級別(R1, R2, W1, W2),同一Token對不一樣級別接口有不一樣的有效期
接口權限劃分(item, promotion, user, etc.)
說明 爲什麼引入authorization_code?
協議設計中,爲何要使用authorization_code來交換access_token?這是讀者容易想到的一個問題。也就是說,在協議的第3步,爲何不直接將access_token經過重定向方式返回給Client呢?好比: [shell] HTTP/1.1 302 Location: https://www.facebook.com/?access_token=ya29.AHES6ZSXVKYTW2VAGZtnMjD&token_type=Bearer&expires_in=3600 [/shell] 若是直接返回access_token,協議將變得更加簡潔,並且少一次Client與AS之間的交互,性能也更優。那爲什麼不這麼設計呢?協議文檔[1]中並無給出這樣設計的理由,但也不難分析:在咱們理解了上述安全性考慮以後,讀者也許會有豁然開朗的感受,懂得了引入authorization_code的妙處。那麼,是否是必定要引入authorization_code才能解決這些安全問題呢?固然不是。筆者將會在另外一篇博文給出一個直接返回access_token的擴展受權類型解決方案,它在知足相同安全性的條件下,使協議更簡潔,交互次數更少。
瀏覽器的redirect_uri是一個不安全信道,此方式不適合於傳遞敏感數據(如access_token)。由於uri可能經過HTTP referrer被傳遞給其它惡意站點,也可能存在於瀏覽器cacher或log文件中,這就給攻擊者盜取access_token帶來了不少機會。另外,此協議也不該該假設RO用戶代理的行爲是可信賴的,由於RO的瀏覽器可能早已被攻擊者植入了跨站腳本用來監聽access_token。所以,access_token經過RO的用戶代理傳遞給Client,會顯著擴大access_token被泄露的風險。 但authorization_code能夠經過redirect_uri方式來傳遞,是由於authorization_code並不像access_token同樣敏感。即便authorization_code被泄露,攻擊者也沒法直接拿到access_token,由於拿authorization_code去交換access_token是須要驗證Client的真實身份。也就是說,除了Client以外,其餘人拿authorization_code是沒有用的。 此外,access_token應該只頒發給Client使用,其餘任何主體(包括RO)都不該該獲取access_token。協議的設計應能保證Client是惟一有能力獲取access_token的主體。引入authorization_code以後,即可以保證Client是access_token的惟一持有人。固然,Client也是惟一的有義務須要保護access_token不被泄露。
引入authorization_code還會帶來以下的好處。因爲協議須要驗證Client的身份,若是不引入authorization_code,這個Client的身份認證只能經過第1步的redirect_uri來傳遞。一樣因爲redirect_uri是一個不安全信道,這就額外要求Client必須使用數字簽名技術來進行身份認證,而不能用簡單的密碼或口令認證方式。引入authorization_code以後,AS能夠直接對Client進行身份認證(見步驟4和5),並且能夠支持任意的Client認證方式(好比,簡單地直接將Client端密鑰發送給AS)。