前言:
? ? ? ? 我也不知道這個前言怎么寫仗哨,反正我就是要加。
? ? ? ? 我為什么要寫這篇文章铅辞?前些天調(diào)用一個普通的搜索接口厌漂,居然還需要發(fā)郵件申請token。讓我不禁感觸良多斟珊。再加上平時開會天天提到的安全性和授權(quán)/鑒權(quán)苇倡。我覺得系統(tǒng)了解下這方面的知識還是很有必要的
? ? ? ? 主要參考阮一峰老師的ouath2.0的入門講解
情景分析:
? ? ? ? 阮一峰老師舉了一個快遞員進小區(qū)送貨的例子
? ??????如果小區(qū)業(yè)主把自己的門禁密碼告訴快遞員,快遞員就擁有了與小區(qū)業(yè)主同樣的權(quán)限,這樣好像不太合適雏节。萬一小區(qū)業(yè)主想取消某個快遞員進入小區(qū)的權(quán)力也很麻煩胜嗓,因為還得通知其他的快遞員。
? ? ? ? 那么把這個例子換到第三方應(yīng)用上來
? ? ? ? 比如說用戶想使用云沖洗網(wǎng)站來沖洗用戶存儲到google上的照片钩乍。用戶為了使用該服務(wù),必須要允許云沖洗讀取自己存在谷歌上照片怔锌。只有得到了用戶的授權(quán)寥粹,谷歌才會把照片交給云沖洗。
? ? ? ? 那么云沖洗是如何獲得用戶授權(quán)的呢?傳統(tǒng)方法是:用戶把賬號和密碼交給云沖洗埃元。這樣云沖洗就可以進入到谷歌中拿到數(shù)據(jù)了涝涤。但是這樣做有以下幾個嚴重的缺點
? ? ? ? 1.?云沖洗為了后續(xù)的服務(wù),會保存用戶的賬號密碼岛杀,這樣很不安全
? ? ? ? 2.?谷歌方面也不得不部署賬號和密碼登錄(單純的密碼登錄并不安全)
? ? ? ? 3.?云沖洗獲得了用戶在谷歌上所有的權(quán)限阔拳。?用戶沒辦法限制云沖洗授權(quán)范圍和有效時間
? ? ? ? 4.?如果修改密碼可以取消云沖洗的權(quán)限。但是這樣所有第三方應(yīng)用權(quán)限也會隨之消失
? ? ? ? 5.?如果其中一個第三方應(yīng)用被攻破了类嗤。就會導(dǎo)致用戶密碼泄露
? ? ? ? oauth就是為了解決上面的問題而誕生的
OAuth思路:
????????OAuth在"客戶端"與"服務(wù)提供商"之間糊肠,設(shè)置了一個授權(quán)層(authorization layer)。"客戶端"不能直接登錄"服務(wù)提供商"遗锣,只能登錄授權(quán)層货裹,以此將用戶與客戶端區(qū)分開來。"客戶端"登錄授權(quán)層所用的令牌(token)精偿,與 用戶的密碼不同弧圆。用戶可以在登錄的時候,指定授權(quán)層令牌的權(quán)限范圍和有效期笔咽。
????????"客戶端"登錄授權(quán)層以后搔预,"服務(wù)提供商"根據(jù)令牌的權(quán)限范圍和有效期,向"客戶端"開放用戶儲存的資料叶组。????????
客戶端的授權(quán)模式:
????????OAuth 2.0 的標(biāo)準是 RFC6749文件
? ??????OAuth 的核心就是向第三方應(yīng)用頒發(fā)令牌
? ??????OAuth 2.0 規(guī)定了四種獲得令牌的流程拯田。可以選擇最適合的那一種扶叉,向第三方應(yīng)用頒發(fā)令牌勿锅。
????授權(quán)碼模式:
????????授權(quán)碼模式是功能最完整、流程最嚴密的授權(quán)模式枣氧,適用于那些有后端的 Web 應(yīng)用
????????第一步:A 網(wǎng)站提供一個鏈接溢十,用戶點擊后就會跳轉(zhuǎn)到 B 網(wǎng)站,授權(quán)用戶數(shù)據(jù)給 A 網(wǎng)站使用达吞。下面就是 A 網(wǎng)站跳轉(zhuǎn) B 網(wǎng)站的一個示意鏈接张弛。
????????https://b.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
? ??????response_type:表示授權(quán)類型,必選項,此處的值固定為"code"
????????client_id:表示客戶端的ID吞鸭,必選項
????????redirect_uri:表示重定向URI寺董,可選項
????????scope:表示申請的權(quán)限范圍,可選項
????????state:表示客戶端的當(dāng)前狀態(tài)刻剥,可以指定任意值遮咖,認證服務(wù)器會原封不動地返回這個值。
????????第二步:? 用戶跳轉(zhuǎn)后造虏,B網(wǎng)站會要求用戶登錄御吞,然后詢問是否同意給予 A 網(wǎng)站授權(quán)。用戶表示同意漓藕,這時 B 網(wǎng)站就會跳回redirect_uri參數(shù)指定的網(wǎng)址陶珠。跳轉(zhuǎn)時,會傳回一個授權(quán)碼享钞,就像下面這樣揍诽。
????????https://a.com/callback?code=AUTHORIZATION_CODE
? ? ? ? code :表示授權(quán)碼,必選項栗竖。該碼的有效期應(yīng)該很短暑脆,通常設(shè)為10分鐘,客戶端只能使用該碼一次划滋,否則會被授權(quán)服務(wù)器拒絕饵筑。該碼與客戶端ID和重定向URI,是一一對應(yīng)關(guān)系处坪。
????????state:如果客戶端的請求中包含這個參數(shù)根资,認證服務(wù)器的回應(yīng)也必須一模一樣包含這個參數(shù)。
? ??????第三步:A 網(wǎng)站拿到授權(quán)碼以后同窘,就可以在后端玄帕,向 B 網(wǎng)站請求令牌。
????????https://b.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL
????????上面 URL 中想邦,client_id參數(shù)和client_secret參數(shù)用來讓 B 確認 A 的身份(client_secret參數(shù)是保密的裤纹,因此只能在后端發(fā)請求),grant_type參數(shù)的值是AUTHORIZATION_CODE丧没,表示采用的授權(quán)方式是授權(quán)碼鹰椒,code參數(shù)是上一步拿到的授權(quán)碼,redirect_uri參數(shù)是令牌頒發(fā)后的回調(diào)網(wǎng)址呕童。
????????第四步:B 網(wǎng)站收到請求以后漆际,就會頒發(fā)令牌。具體做法是向redirect_uri指定的網(wǎng)址夺饲,發(fā)送一段 JSON 數(shù)據(jù)奸汇。
? ??????上面 JSON 數(shù)據(jù)中施符,access_token字段就是令牌,A 網(wǎng)站在后端拿到即可擂找。
????隱藏式:
????????有些 Web 應(yīng)用是純前端應(yīng)用戳吝,沒有后端。這時就不能用上面的方式了贯涎,必須將令牌儲存在前端听哭。RFC 6749 就規(guī)定了第二種方式,允許直接向前端頒發(fā)令牌柬采。這種方式?jīng)]有授權(quán)碼這個中間步驟欢唾,所以稱為(授權(quán)碼)"隱藏式"(implicit)。
????????第一步:A 網(wǎng)站提供一個鏈接粉捻,要求用戶跳轉(zhuǎn)到 B 網(wǎng)站,授權(quán)用戶數(shù)據(jù)給 A 網(wǎng)站使用斑芜。
????????https://b.com/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
? ? ? ? response_type參數(shù)為token肩刃,表示要求直接返回令牌。
????????第二步:用戶跳轉(zhuǎn)到 B 網(wǎng)站杏头,登錄后同意給予 A 網(wǎng)站授權(quán)盈包。這時,B 網(wǎng)站就會跳回redirect_uri參數(shù)指定的跳轉(zhuǎn)網(wǎng)址醇王,并且把令牌作為 URL 參數(shù)呢燥,傳給 A 網(wǎng)站。
? ? ? ? (這里注意:返回的可能不是純令牌寓娩,還需要客戶端調(diào)用資源服務(wù)器返回的腳本進行提取令牌的工作)
????????https://a.com/callback#token=ACCESS_TOKEN
????????上面 URL 中叛氨,token參數(shù)就是令牌,A 網(wǎng)站因此直接在前端拿到令牌棘伴。
????????這種方式把令牌直接傳給前端寞埠,是很不安全的。因此焊夸,只能用于一些安全要求不高的場景仁连,并且令牌的有效期必須非常短,通常就是會話期間(session)有效阱穗,瀏覽器關(guān)掉饭冬,令牌就失效了。
????密碼式:
? ??????如果你高度信任某個應(yīng)用揪阶,RFC 6749 也允許用戶把用戶名和密碼昌抠,直接告訴該應(yīng)用。該應(yīng)用就使用你的密碼遣钳,申請令牌扰魂,這種方式稱為"密碼式"(password)麦乞。
????????第一步:A 網(wǎng)站要求用戶提供 B 網(wǎng)站的用戶名和密碼。拿到以后劝评,A 就直接向 B 請求令牌姐直。
????????https://oauth.b.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID
????????上面 URL 中,grant_type參數(shù)是授權(quán)方式蒋畜,這里的password表示"密碼式"声畏,username和password是 B 的用戶名和密碼。
????????第二步:B 網(wǎng)站驗證身份通過后姻成,直接給出令牌插龄。注意,這時不需要跳轉(zhuǎn)科展,而是把令牌放在 JSON 數(shù)據(jù)里面均牢,作為 HTTP 回應(yīng),A 因此拿到令牌才睹。
????????這種方式需要用戶給出自己的用戶名/密碼徘跪,顯然風(fēng)險很大,因此只適用于其他授權(quán)方式都無法采用的情況琅攘,而且必須是用戶高度信任的應(yīng)用垮庐。
????憑證式:
????????最后一種方式是憑證式(client credentials),適用于沒有前端的命令行應(yīng)用坞琴,即在命令行下請求令牌哨查。
????????第一步:A 應(yīng)用在命令行向 B 發(fā)出請求。
????????https://oauth.b.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
????????上面 URL 中剧辐,grant_type參數(shù)等于client_credentials表示采用憑證式寒亥,client_id和client_secret用來讓 B 確認 A 的身份。
????????第二步:B 網(wǎng)站驗證通過以后浙于,直接返回令牌护盈。
????????這種方式給出的令牌,是針對第三方應(yīng)用的羞酗,而不是針對用戶的腐宋,即有可能多個用戶共享同一個令牌。
令牌的使用:
????????A 網(wǎng)站拿到令牌以后檀轨,就可以向 B 網(wǎng)站的 API 請求數(shù)據(jù)了胸竞。
????????此時,每個發(fā)到 API 的請求参萄,都必須帶有令牌卫枝。具體做法是在請求的頭信息,加上一個Authorization字段讹挎,令牌就放在這個字段里面校赤。
????????curl-H"Authorization: Bearer ACCESS_TOKEN"\"https://api.b.com"
????????上面命令中吆玖,ACCESS_TOKEN就是拿到的令牌。
更新令牌:
????????令牌的有效期到了马篮,如果讓用戶重新走一遍上面的流程沾乘,再申請一個新的令牌,很可能體驗不好浑测,而且也沒有必要翅阵。OAuth 2.0 允許用戶自動更新令牌。
????????具體方法是迁央,B 網(wǎng)站頒發(fā)令牌的時候掷匠,一次性頒發(fā)兩個令牌,一個用于獲取數(shù)據(jù)岖圈,另一個用于獲取新的令牌(refresh token 字段)讹语。令牌到期前,用戶使用 refresh token 發(fā)一個請求蜂科,去更新令牌募强。
????????https://b.com/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN
????????上面 URL 中,grant_type參數(shù)為refresh_token表示要求更新令牌崇摄,client_id參數(shù)和client_secret參數(shù)用于確認身份,refresh_token參數(shù)就是用于更新令牌的令牌慌烧。
????????B 網(wǎng)站驗證通過以后逐抑,就會頒發(fā)新的令牌。
TSL/SSL:
The last but not the least. 傳輸層加密屹蚊,可以說是 OAuth 2.0 的基石厕氨,安全的根基。因為 OAuth 2.0 相比 1.0 最大的變化汹粤,就是去除了惱人的簽名步驟命斧,使得每次請求通信,都降低了安全性嘱兼,因為參數(shù)都是可以在傳輸過程中增減国葬,改變順序什么,都無法被接收方覺察到芹壕。(恐怖;闼摹)所以,其安全性踢涌,高度依賴通信信道的安全通孽,所以,在 OAuth 2.0 中睁壁,使用 HTTPS 可以說是必須的背苦,而且 client 有義務(wù)驗證證書的真假互捌,防止中間人攻擊,而 authorization server 和 resource server 都有義務(wù)申請可信任的第三方頒發(fā)的真實的 SSL 證書行剂。