參考
知乎 OAuth 授權的工作原理是怎樣的酪捡?足夠安全嗎耕肩?
阮一峰 理解OAuth 2.0
一典奉、第三方應用如何授權才安全
1.例一
有一個"云沖印"的網(wǎng)站悼沿,可以將用戶儲存在Google的照片屿笼,沖印出來牺荠。用戶為了使用該服務,必須讓"云沖印"讀取自己儲存在Google上的照片驴一。問題是只有得到用戶的授權志电,Google才會同意"云沖印"讀取這些照片。那么蛔趴,"云沖印"怎樣獲得用戶的授權呢挑辆?
傳統(tǒng)方法是,用戶將自己的Google用戶名和密碼孝情,告訴"云沖印"鱼蝉,后者就可以讀取用戶的照片了。這樣的做法有以下幾個嚴重的缺點箫荡。
- "云沖印"為了后續(xù)的服務魁亦,會保存用戶的密碼,這樣很不安全羔挡。
- Google不得不部署密碼登錄洁奈,而我們知道,單純的密碼登錄并不安全绞灼。
- "云沖印"擁有了獲取用戶儲存在Google所有資料的權力利术,用戶沒法限制"云沖印"獲得授權的范圍和有效期。
- 用戶只有修改密碼低矮,才能收回賦予"云沖印"的權力印叁。但是這樣做,會使得其他所有獲得用戶授權的第三方應用程序全部失效。
- 只要有一個第三方應用程序被破解轮蜕,就會導致用戶密碼泄漏昨悼,以及所有被密碼保護的數(shù)據(jù)泄漏。
OAuth就是為了解決上面這些問題而誕生的跃洛。
2.例二
新浪微博就是你的家率触。偶爾你會想讓一些人(第三方應用)去你的家里幫你做一些事,或取點東西汇竭。你可以復制一把鑰匙(用戶名和密碼)給他們葱蝗,但這里有三個問題:
- 別人拿了鑰匙后可以去所有的房間
- 別人拿到你的鑰匙后也許會不小心丟到,甚至故意送到它人手里韩玩。這樣你都不知到誰有你家鑰匙。
- 過一段時間你也許會想要回自己的鑰匙陆馁,但別人不還怎么辦找颓?
OAuth 是高級鑰匙:
- 你可以配置不同權限的鑰匙。有些只能進大廳(讀取你的微博流)叮贩。有些鑰匙可以進儲藏柜(讀取你的相片)
- 鑰匙上帶著指紋驗證的(指紋 = appkey)击狮。 收到鑰匙的人只能自己用,不能轉讓
- 你可以遠程廢除之前發(fā)出的鑰匙
二益老、流程
假如我有一個網(wǎng)站彪蓬,你是我網(wǎng)站上的訪客,看了文章想留言表示「朕已閱」捺萌,留言時發(fā)現(xiàn)有這個網(wǎng)站的帳號才能夠留言档冬,此時給了你兩個選擇:一個是在我的網(wǎng)站上注冊擁有一個新賬戶,然后用注冊的用戶名來留言桃纯;一個是使用 github 帳號登錄酷誓,使用你的 github 用戶名來留言。前者你覺得過于繁瑣态坦,于是慣性地點擊了 github 登錄按鈕盐数,此時 OAuth 認證流程就開始了。
需要明確的是伞梯,即使用戶剛登錄過 github玫氢,我的網(wǎng)站也不可能向 github 發(fā)一個什么請求便能夠拿到訪客信息,這顯然是不安全的谜诫。就算用戶允許你獲取他在 github 上的信息漾峡,github 為了保障用戶信息安全,也不會讓你隨意獲取喻旷。所以操作之前灰殴,我的網(wǎng)站與 github 之間需要要有一個協(xié)商。
1. 網(wǎng)站和 Github 之間的協(xié)商
Github 會對用戶的權限做分類,比如讀取倉庫信息的權限牺陶、寫入倉庫的權限伟阔、讀取用戶信息的權限、修改用戶信息的權限等等掰伸。如果我想獲取用戶的信息皱炉,Github 會要求我,先在它的平臺上注冊一個應用狮鸭,在申請的時候標明需要獲取用戶信息的哪些權限合搅,用多少就申請多少,并且在申請的時候填寫你的網(wǎng)站域名歧蕉,Github 只允許在這個域名中獲取用戶信息灾部。
此時我的網(wǎng)站已經(jīng)和 Github 之間達成了共識,Github 也給我發(fā)了兩張門票惯退,一張門票叫做 Client Id赌髓,另一張門票叫做 Client Secret。
2. 用戶和 Github 之間的協(xié)商
用戶進入我的網(wǎng)站催跪,點擊 github 登錄按鈕的時候锁蠕,我的網(wǎng)站會把上面拿到的 Client Id 交給用戶,讓他進入到 Github 的授權頁面懊蒸,Github 看到了用戶手中的門票荣倾,就知道這是我的網(wǎng)站讓他過來的,于是它就把我的網(wǎng)站想要獲取的權限擺出來骑丸,并詢問用戶是否允許我獲取這些權限舌仍。
// 用戶登錄 github,協(xié)商
GET //github.com/login/oauth/authorize
// 協(xié)商憑證
params = {
client_id: "xxxx",
redirect_uri: "http://my-website.com"
}
如果用戶覺得我的網(wǎng)站要的權限太多通危,或者壓根就不想我知道他這些信息抡笼,選擇了拒絕的話,整個 OAuth 2.0 的認證就結束了黄鳍,認證也以失敗告終推姻。如果用戶覺得 OK,在授權頁面點擊了確認授權后框沟,頁面會跳轉到我預先設定的 redirect_uri 并附帶一個蓋了章的門票 code藏古。
// 協(xié)商成功后帶著蓋了章的 code
Location: http://my-website.com?code=xxx
這個時候,用戶和 Github 之間的協(xié)商就已經(jīng)完成忍燥,Github 也會在自己的系統(tǒng)中記錄這次協(xié)商拧晕,表示該用戶已經(jīng)允許在我的網(wǎng)站訪問上直接操作和使用他的部分資源。
3. 告訴 Github 我的網(wǎng)站要來拜訪了
第二步中梅垄,我們已經(jīng)拿到了蓋過章的門票 code厂捞,但這個 code 只能表明,用戶允許我的網(wǎng)站從 github 上獲取該用戶的數(shù)據(jù),如果我直接拿這個 code 去 github 訪問數(shù)據(jù)一定會被拒絕靡馁,因為任何人都可以持有 code欲鹏,github 并不知道 code 持有方就是我本人。
還記得之前申請應用的時候 github 給我的兩張門票么臭墨,Client Id 在上一步中已經(jīng)用過了赔嚎,接下來輪到另一張門票 Client Secret。
// 網(wǎng)站和 github 之間的協(xié)商
POST //github.com/login/oauth/access_token
// 協(xié)商憑證包括 github 給用戶蓋的章和 github 發(fā)給我的門票
params = {
code: "xxx",
client_id: "xxx",
client_secret: "xxx",
redirect_uri: "http://my-website.com"
}
拿著用戶蓋過章的 code 和能夠標識個人身份的 client_id胧弛、client_secret 去拜訪 github尤误,拿到最后的綠卡 access_token。
// 拿到最后的綠卡
response = {
access_token: "e72e16c7e42f292c6912e7710c838347ae178b4a"
scope: "user,gist"
token_type: "bearer",
refresh_token: "xxxx"
}
4. 用戶開始使用 github 帳號在我的頁面上留言
上一步 github 已經(jīng)把最后的綠卡 access_token 給我了结缚,通過 github 提供的 API 加綠卡就能夠訪問用戶的信息了损晤,能獲取用戶的哪些權限在 response 中也給了明確的說明,scope 為 user 和 gist红竭,也就是只能獲取 user 組和 gist 組兩個// 訪問用戶數(shù)據(jù)
//綠卡 access_token
GET //api.github.com/user?access_token=e72e16c7e42f
292c6912e7710c838347ae178b4a
// 告訴我用戶的名字和郵箱
response = {
username: "barretlee",
email: "barret.china@gmail.com"
}小組的權限尤勋,user 組中就包含了用戶的名字和郵箱等信息了。
整個 OAuth2 流程在這里也基本完成了德崭,文章中的表述很粗糙斥黑,比如 access_token 這個綠卡是有過期時間的揖盘,如果過期了需要使用 refresh_token 重新簽證眉厨。
三、詳解
1.名詞解釋
- Third-party application:
第三方應用程序兽狭,又稱"客戶端"(client)憾股,即例子中的"云沖印"或網(wǎng)站。 - HTTP service:
HTTP服務提供商箕慧,本文中簡稱"服務提供商"服球,即上一節(jié)例子中的Google或GitHub。 - Resource Owner:
資源所有者颠焦,又稱"用戶"(user)斩熊。 - User Agent:
用戶代理,本文中就是指瀏覽器伐庭。 - Authorization server:
認證服務器粉渠,即服務提供商專門用來處理認證的服務器。 - Resource server:
資源服務器圾另,即服務提供商存放用戶生成的資源的服務器霸株。它與認證服務器,可以是同一臺服務器集乔,也可以是不同的服務器去件。
2.授權模式
客戶端必須得到用戶的授權(authorization grant),才能獲得令牌(access token)。OAuth 2.0定義了四種授權方式尤溜。
- 授權碼模式(authorization code)
- 簡化模式(implicit)
- 密碼模式(resource owner password credentials)
- 客戶端模式(client credentials)
3.授權碼模式
授權碼模式(authorization code)是功能最完整倔叼、流程最嚴密的授權模式。它的特點就是通過客戶端的后臺服務器靴跛,與"服務提供商"的認證服務器進行互動缀雳。它的步驟如下:
(A)用戶訪問客戶端,后者將前者導向認證服務器梢睛。
(B)用戶選擇是否給予客戶端授權肥印。
(C)假設用戶給予授權,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI)绝葡,同時附上一個授權碼深碱。
(D)客戶端收到授權碼,附上早先的"重定向URI"藏畅,向認證服務器申請令牌敷硅。這一步是在客戶端的后臺的服務器上完成的,對用戶不可見愉阎。
(E)認證服務器核對了授權碼和重定向URI绞蹦,確認無誤后,向客戶端發(fā)送訪問令牌(access token)和更新令牌(refresh token)榜旦。
A步驟中幽七,客戶端申請認證的URI,包含以下參數(shù):
- response_type:表示授權類型溅呢,必選項澡屡,此處的值固定為"code"
- client_id:表示客戶端的ID,必選項
- redirect_uri:表示重定向URI咐旧,可選項
- scope:表示申請的權限范圍驶鹉,可選項
- state:表示客戶端的當前狀態(tài),可以指定任意值铣墨,認證服務器會原封不動地返回這個值室埋。
下面是一個例子。
GET /authorize?response_type=code&client_id=s6BhdRkqt3
&state=xyz &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
HTTP/1.1 Host: server.example.com
C步驟中伊约,服務器回應客戶端的URI姚淆,包含以下參數(shù):
- code:表示授權碼,必選項碱妆。該碼的有效期應該很短肉盹,通常設為10分鐘,客戶端只能使用該碼一次,否則會被授權服務器拒絕。該碼與客戶端ID和重定向URI,是一一對應關系也殖。
- state:如果客戶端的請求中包含這個參數(shù)窍蓝,認證服務器的回應也必須一模一樣包含這個參數(shù)腋颠。
下面是一個例子。
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
D步驟中吓笙,客戶端向認證服務器申請令牌的HTTP請求淑玫,包含以下參數(shù):
- grant_type:表示使用的授權模式,必選項面睛,此處的值固定為"authorization_code"絮蒿。
- code:表示上一步獲得的授權碼,必選項叁鉴。
- redirect_uri:表示重定向URI土涝,必選項,且必須與A步驟中的該參數(shù)值保持一致幌墓。
- client_id:表示客戶端ID但壮,必選項。
下面是一個例子常侣。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
E步驟中蜡饵,認證服務器發(fā)送的HTTP回復,包含以下參數(shù):
- access_token:表示訪問令牌胳施,必選項溯祸。
- token_type:表示令牌類型,該值大小寫不敏感巾乳,必選項您没,可以是bearer類型或mac類型鸟召。
- expires_in:表示過期時間胆绊,單位為秒。如果省略該參數(shù)欧募,必須其他方式設置過期時間压状。
- refresh_token:表示更新令牌,用來獲取下一次的訪問令牌跟继,可選項种冬。
- scope:表示權限范圍,如果與客戶端申請的范圍一致舔糖,此項可省略娱两。
下面是一個例子。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
四金吗、應用
參考
android 新浪微博Oauth2.0認證以及自定義webview認證
android新浪微博Oauth2.0認證以及登錄
Android中的OAuth2.0——QQ第三方授權登錄