鍍金池/ 教程/ Java/ 跨客戶端身份憑證
本地安裝的應(yīng)用程序中使用 OAuth 2.0
設(shè)備中使用 OAuth 2.0
使用 OAuth 2.0 來訪問谷歌 API
Web 服務(wù)器應(yīng)用程序中使用 OAuth 2.0
服務(wù)類應(yīng)用中使用 OAuth 2.0
跨客戶端身份憑證
客戶端應(yīng)用程序中使用 OAuth 2.0
谷歌應(yīng)用程序默認(rèn)憑證

跨客戶端身份憑證

當(dāng)開發(fā)者構(gòu)建軟件時(shí),會(huì)經(jīng)常包含一些模塊,例如,運(yùn)行 Web 服務(wù)的模塊,依賴瀏覽器的模塊,運(yùn)行 native 移動(dòng)應(yīng)用的模塊。開發(fā)人員和使用軟件的人,通常認(rèn)為這些模塊應(yīng)該是應(yīng)用程序的一部分。

谷歌的 OAuth 2.0 支持上述習(xí)慣。你必須在谷歌開發(fā)者面板中構(gòu)建軟件。谷歌開發(fā)者面板中的單位組織叫做 project,可以對(duì)應(yīng)于一個(gè)多組件的應(yīng)用程序。對(duì)每一個(gè)工程,你可以寫上一些品牌信息,你必須指定應(yīng)用程序?qū)?huì)訪問的應(yīng)用接口。開發(fā)者面板會(huì)生成一個(gè)獨(dú)一無二的字符串 client ID,用來標(biāo)志每一個(gè)多組件應(yīng)用程序的組件。

跨客戶端授權(quán)的目標(biāo)

被一個(gè)或多個(gè) scope 字符串標(biāo)識(shí)的應(yīng)用程序,當(dāng)其使用 OAuth 2.0 授權(quán)時(shí),它將代替用戶來請(qǐng)求一個(gè) OAuth 2.0 的訪問令牌來訪問資源。通常要由用戶來批準(zhǔn)應(yīng)用程序的訪問。

當(dāng)應(yīng)用程序被用戶授予特定 scope 內(nèi)的訪問權(quán)限時(shí),用戶會(huì)留意到用戶準(zhǔn)許界面,這個(gè)準(zhǔn)許界面包含了你在谷歌開發(fā)者面板中構(gòu)建的工程的版本號(hào)和產(chǎn)品品牌信息。(關(guān)于如何構(gòu)建同意(協(xié)議)界面的更多信息,請(qǐng)查看在開發(fā)者控制面板的 Setting up OAuth 2.0 )。因此,谷歌認(rèn)為在一個(gè)項(xiàng)目中,當(dāng)用戶授權(quán)任何訪問特定 scopeclient ID 時(shí),既表示用戶信任整個(gè) scope 的申請(qǐng)。

效果就是,無論何時(shí),當(dāng)應(yīng)用程序的組件被谷歌授權(quán)服務(wù)系統(tǒng)可靠地授權(quán)后,就不會(huì)多次提醒用戶批準(zhǔn)同一個(gè)應(yīng)用訪問資源。目前支持上訴效果的有 Web 客戶端, JavaScript 的客戶端和 Android 應(yīng)用程序。

跨客戶端訪問令牌

依賴于運(yùn)行代碼的平臺(tái),軟件能夠通過多種多樣的途徑獲取 OAuth 2.0 的訪問令牌。更多信息,請(qǐng)查看 Using OAuth 2.0 to Access Google APIsGoogle Play Services Authorization。通常應(yīng)用程序獲取一個(gè)訪問令牌需要得到用戶審批。

幸運(yùn)的是,無論何時(shí),在同一個(gè)項(xiàng)目中給其他組件授權(quán),谷歌授權(quán)服務(wù)系統(tǒng)都能夠使用到與用戶批準(zhǔn)授權(quán)的,給定項(xiàng)目?jī)?nèi)的 client ID 的相關(guān)信息。

效果就是,在同一個(gè)項(xiàng)目的同一個(gè)范圍中,如果安卓應(yīng)用請(qǐng)求了一個(gè)訪問令牌,而且用戶早就給 Web 組件授權(quán)了,用戶就不會(huì)被再次詢問授權(quán)。如下途徑也是適用的:在安卓應(yīng)用上,如果訪問的范圍已經(jīng)被授權(quán)過了,用戶就不用再次授權(quán) Web 組件。

安卓 ID 令牌

跨客戶端身份標(biāo)志的一個(gè)好處就是,無需用戶登錄,僅利用它以及 ID 令牌,就可以讓安卓應(yīng)用和他們的主服務(wù)端溝通。

例子

假設(shè)開發(fā)者控制面板中有一個(gè)項(xiàng)目,這個(gè)項(xiàng)目包含了一個(gè)客戶 ID 為 9414861317621.apps.googleusercontent.com 的服務(wù)端控件(一個(gè)應(yīng)用程序)。 再假設(shè)在這個(gè)項(xiàng)目中還有一個(gè)原生安卓應(yīng)用。

這個(gè)安卓應(yīng)用能夠代替設(shè)備(手機(jī))上任意一個(gè)谷歌賬號(hào)調(diào)用 GoogleAuthUtil.getToken() 方法,調(diào)用時(shí), audience:server:client_id: 這個(gè)前綴會(huì)通過 Web 組件的客戶 ID 來進(jìn)行修正補(bǔ)全,也就是 scope 參數(shù)設(shè)置為 audience:server:client_id:9414861317621.apps.googleusercontent.com

在這個(gè)方案中,GoogleAuthUtil 這個(gè)對(duì)象將會(huì)察覺到在同一個(gè)項(xiàng)目中的安卓應(yīng)用和 Web 組件的客戶 ID ,不用用戶同意,就可以提供谷歌驗(yàn)證過的 ID 令牌給應(yīng)用。 這個(gè) ID 令牌包含了 一些字段,其中一些比較重要的字段如下:

  • iss : 總是 accounts.google.com

  • aud : 項(xiàng)目中 Web 組件的客戶 ID

  • azp : 項(xiàng)目中安卓應(yīng)用的客戶 ID

  • email : 用來標(biāo)識(shí)用戶請(qǐng)求令牌的電子郵件

ID 令牌被設(shè)計(jì)成通過 HTTPS 傳輸,所以使用 web 組件必須按如下步驟進(jìn)行:

  1. 驗(yàn)證加密簽名。因?yàn)榱钆频男问绞且粋€(gè) JSON Web 令牌或者是 JWT,并且還有大多數(shù)流行的編程語言庫(kù)來驗(yàn)證 JWT,這是簡(jiǎn)單而有效的。

  2. 確保 aud 字段的值是屬于你自己的客戶 ID。

完成相關(guān)操作后, web 組件的令牌就有下列必然的特征:

  1. 令牌是通過谷歌發(fā)布的。

  2. 令牌被放置在 email 字段,然后發(fā)送到設(shè)備。

Web 組件可以通過安卓應(yīng)用程序鑒定放置在 azp 字段的客戶 ID。然而非兼容的或者高權(quán)限的安卓設(shè)備或許會(huì)偽造 azp 字段。

效果就是,Web 組件把來自安卓客戶端的數(shù)據(jù)當(dāng)做來自項(xiàng)目中的用戶的數(shù)據(jù),使用 ID 令牌來代替用戶來訪問和更新用戶數(shù)據(jù),而不用多次提醒用戶進(jìn)行身份驗(yàn)證。

安卓應(yīng)用的 Web 端獲得離線訪問權(quán)限

再次假設(shè)一個(gè)包含了客戶 ID 為 9414861317621.apps.googleusercontent.com 的 Web 組件,在這個(gè)事例中想代替用戶訪問兩個(gè)不同的資源,但此時(shí)用戶并不在線。然而,軟件訪問資源通常是通過一個(gè)安卓應(yīng)用的交互來實(shí)現(xiàn)的。讓我們更深入地假設(shè),資源是被 Google Drive scope 內(nèi)的字符串 https://www.googleapis.com/auth/drive.fileGoogle+ scope 內(nèi)的登陸字符串 https://www.googleapis.com/auth/plus.login 標(biāo)志的,我們將上述兩個(gè)字符串標(biāo)記為 resource-1resource-2。

在這個(gè)場(chǎng)景中,安卓應(yīng)用就像是在開發(fā)者面板項(xiàng)目中的 web 組件那樣,在設(shè)備上指定的任何的谷歌賬戶,都能夠調(diào)用 GoogleAuthUtil.getToken() 方法,其 scope 參數(shù)的之為 oauth2:server:client_id:9414861317621.apps.googleusercontent.com:api_scope:resource-1 resource-2.。

在這個(gè)案例中,用戶已經(jīng)授權(quán)這個(gè)項(xiàng)目訪問前面所說的那兩個(gè)范圍, GoogleAuthUtil.getToken() 方法將首次請(qǐng)求那兩個(gè)范圍的令牌。如果他可以這么做,那么這個(gè)方法并不會(huì)返回 OAuth 令牌,但是會(huì)放回一個(gè)臨時(shí)的授權(quán)令牌,用來更新訪問令牌和刷新令牌。

安卓應(yīng)用能通過 HTTPS 來發(fā)送授權(quán)碼給自己的 web 組件。web 組件可以這個(gè)授權(quán)令牌返回訪問令牌和刷新令牌,在 Handling the response 中有相關(guān)描述。以下規(guī)則適用于 web 組件:

  • 當(dāng) web 組件通過授權(quán)碼交換令牌時(shí),在 POST 請(qǐng)求中不應(yīng)該包含 redirect_uri 參數(shù)。

  • 當(dāng) web 組件接收到令牌時(shí),必須檢查 ID 令牌。接受來自谷歌安全通道的令牌,但是請(qǐng)求中并不含有簽名檢查。所以 web 組件還必須作如下操作:

    • 核實(shí)來自谷歌的 ID 令牌中的 aud 字段,是否與 谷歌開發(fā)者面板 中的客戶 ID 一致。

    • 核實(shí)來自谷歌的 ID 令牌中的 sub 字段,是否與從客戶端接受到的 ID 令牌中的 sub 字段一致。
  • 當(dāng)刷新令牌還未過期時(shí), web 組件的任務(wù)就是安全地保存刷新令牌,使其能夠長(zhǎng)期使用。

  • 重要的是,安卓應(yīng)用本身不會(huì)企圖使用授權(quán)碼來更換刷新令牌。這將需要應(yīng)用存儲(chǔ)服務(wù)端的客戶 ID 和客戶密鑰。這會(huì)導(dǎo)致你的安卓應(yīng)用有安全漏洞,因?yàn)閼?yīng)用會(huì)極其簡(jiǎn)單地被破解。

你能夠在一個(gè)較短的時(shí)間內(nèi),大概一個(gè)鐘,使用訪問令牌來訪問請(qǐng)求的范圍。刷新令牌不會(huì)過期,除非被明確地取消,你可以使用刷新令牌隨時(shí)隨地地來獲取新的訪問令牌。

建議的流程

為了有效使用資源減少不必要的工作,當(dāng)安卓程序通過自己的后端開啟一個(gè)網(wǎng)絡(luò)會(huì)話時(shí),我們推薦如下的程序流程:

  1. 所有的請(qǐng)求都使用 HTTP 的 POST 請(qǐng)求,每個(gè) POST 請(qǐng)求主體都要包含 ID 令牌。你獲取的是在之前章節(jié)描述的 ID 令牌,要告知給用戶的后端。

  2. 會(huì)話的首次請(qǐng)求,不論它是否擁有在線訪問必要范圍的適當(dāng)?shù)燃?jí),通常都會(huì)有查詢后端對(duì)其進(jìn)行校驗(yàn)。

  3. web 后端必須知道他是否擁有一個(gè)有效的刷新令牌。如果它沒有刷新令牌或者發(fā)現(xiàn)了它的刷新令牌已經(jīng)失效(你可以使用刷新令牌來獲取新的訪問令牌來測(cè)試其是否失效),web 后端就會(huì)傳遞缺少刷新令牌的信息給客戶端。

  4. 如果客戶端接收到了來自后端的信息,得知了后端沒有有效的刷新令牌。在安卓應(yīng)用獲取了授權(quán)令牌,就像前面說的那樣,會(huì)將這個(gè)授權(quán)令牌傳送回 web 后端來獲取有效的刷新令牌。

  5. 客戶端和服務(wù)器繼續(xù)他們之間的會(huì)話。

在這些步驟中,控制請(qǐng)求離線訪問的功能是通過服務(wù)端的代碼來維護(hù)的,最好能夠知道什么時(shí)候需要離線訪問。并且,如果應(yīng)用總是請(qǐng)求刷新令牌,卻不去檢查服務(wù)端是否已經(jīng)擁有了刷新令牌,這將導(dǎo)致有限的刷新令牌被消耗,這反倒可以突出用戶/應(yīng)用程序組合是優(yōu)秀的。

上訴效果就是,用戶只要經(jīng)過少數(shù)的確認(rèn),就可以讓項(xiàng)目的移動(dòng)應(yīng)用的組件,為其他組件取得永久的訪問離線資源的權(quán)限.