- 原文地址:Implementing linkedPurchaseToken correctly to prevent duplicate subscriptions
- 原文作者:Emilie Roberts
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:yuwhuawang
- 校對者:zx-Zhu
你是否在使用 Google Play 的訂閱功能?要確保你的後端服務實現的方式是正確的。
訂閱 REST APIs 是管理使用者訂閱的真實可信來源。Purchases.subscriptions API 的返回包括一個非常重要的欄位叫做 linkedPurchaseToken。 恰當的處理這個欄位,對於保證正確的使用者能夠訪問你的內容是非常重要的。
它是如何工作的?
就像 訂閱文件 裡指出的, 每一筆新的 Google Play 的購買流程 —— 初始化購買、升級和降級還有 重新註冊¹ —— 都會產生一個新的購買令牌。而 linkedPurchaseToken 欄位則可以用來識別屬於同一個訂閱的多個購買令牌。
打個比方,一個使用者購買了一個訂閱並且收到一個購買令牌 A。linkedPurchaseToken 欄位(灰色圓圈)在 API 的返回裡沒有值,因為這個購買令牌屬於一個全新的訂閱。
如果使用者升級了他們的訂閱,一個新的購買令牌 B 產生了。既然這個升級替代了購買令牌 A 代表的訂閱,令牌 B 的 linkedPurchaseToken 欄位(灰色圓圈顯示的)將會指向令牌 A。注意它按照時間的逆序指向原始的購買令牌。
購買令牌 B 將會是唯一被更新的令牌。購買令牌 A 不應該用來授權使用者獲取你的內容。
注意: 更新訂閱時,如果你查詢 Google Play 的訂單伺服器,購買令牌 A 和 B 都會是啟用的。我們會在 下一節 裡討論這個問題。
現在,讓我們假設一個另一個使用者執行了以下操作:訂閱、升級和降級。原始的訂閱會建立購買令牌 C,升級操作會建立購買令牌 D,降級操作會建立購買令牌 E。每一個令牌都會按照時間的逆序指向前一個令牌。
讓我們在這個例子里加上第三個使用者。這個使用者一直在改變主意。在初始化訂閱之後,使用者又一連三次取消了訂閱然後重新訂閱(重新訂閱)。初始化訂閱建立了購買令牌 F,重新訂閱建立了 G、H 和 I。購買令牌 I 是最近的令牌。
最近的令牌 B、E 和 I 分別代表了使用者 1、2、3 的最終授權和付賬的訂閱。只有這些最近的令牌才有相應的權利。然而對於 Google Play 來講,如果初始的過期時間還沒到,所有的令牌都是“有效的”。
也就是說,如果你通過 獲取訂閱 API 來查詢這些令牌,包括上面的圖表內的 A, D, F, G和H,你會得到 訂閱資源響應 ,響應裡表明訂閱還沒有過期並且付款已經收到,即便如此你也只應該根據最近的令牌來授權。
第一眼看上去很奇怪:為什麼最初的令牌還是在被更新後還是有效的?簡單來說是這樣實現能讓開發者更靈活地提供內容和服務,也讓 Google 更好的保護使用者隱私。然而這也確實需要你在後端伺服器上進行重點記錄
操作 linkedPurchaseToken
每次當你確認一個訂閱,你的後臺服務都應該檢查 linkedPurchaseToken 欄位有沒有被設定。如果已經被設定,該欄位的值就代表著前一個被替換的令牌。你應該立刻把前一個令牌標記為失效,這樣使用者就不能使用這個令牌訪問你的內容。
我們再來看看上面例子裡的使用者 1, 當後端伺服器收到了代表初始購買的憑證 A,該憑證 A 的 linkedPurchaseToken 欄位為空,這時應根據憑證進行授權。接下來,當後端伺服器接收到更新後新的購買憑證 B,伺服器會檢查 linkedPurchaseToken 欄位,發現它被設定為令牌 A,於是就禁掉令牌 A 的授權。
這樣的話,後端資料庫總是儲存有效許可權的購買憑證。以使用者 3 的例子來說,資料庫的狀態變化應該如下圖:
檢查 linkedPurchaseToken 的虛擬碼:
你可以在一個開源的,端對端訂閱的應用 優雅計程車 的後臺 Firebase 上看一些例子,特別是看 disableReplacedSubscription 方法,它在 PurchasesManager.ts 裡。
清理現有的資料庫
現在你的後端應該和最新的,接連到來的購買令牌保持同步,你會檢查每一個購買的 linkedPurchaseToken 欄位,並且每一個對應著被替換訂閱的令牌,都被正確的禁用了。這太棒了!
但是如果你有一個已有的訂閱資料的資料庫,並且沒有根據 linkedPurchaseToken 欄位來調整?你需要在這個資料庫上跑一個一次性的清理演算法。
在很多情況下清理資料庫中最重要的工作就是,一個令牌是否被能夠授權相應的內容和服務。也就是說:並不需要對每一個訂閱重新建立升級/降級/重新訂閱的購買歷史,而只需要確定每個令牌正確的授權情況。一次性的資料庫清理任務就可以把訂閱狀態整理清楚。接下來,新到來的訂閱就需要像上一節中描述的那樣處理。
想象一下上面三個使用者的購買憑證都存在資料庫裡。這些購買可能出現在任何時間,順序也不一樣。如果清理功能正確處理的話,令牌 B、E 和 I 最終會被標記為有效授權,而其他的令牌則會被禁用。
對資料庫進行一次遍歷,並檢查每一項。如果 linkedPurchaseToken 欄位被設定,就把這個欄位包括的欄位禁用。根據下面的圖表,我們從上到下移動:
元素 A:linkedPurchaseToken 沒有被設定,移至下一項 元素 D:linkedPurchaseToken == C,禁用 C 元素 G:linkedPurchaseToken == F,禁用 F 元素 E:linkedPurchaseToken == D,禁用 D 元素 F:linkedPurchaseToken 沒有被設定,移至下一項 等等。
清理現有資料庫的虛擬碼:
執行完一次性的清理之後,所有的舊令牌都會被禁用,你的資料庫也就準備好了。
簡單但是重要的事
現在你已經理解 linkedPurchaseToken 欄位是怎麼工作的,確保在你的後端正確的處理它。每一個有訂閱功能的應用都應該檢查這個欄位。正確的追蹤授權對於保證正確的使用者,在正確的時間,被授予了正確的權利這一點來說,非常關鍵。
參考資料
- Google Play Billing Library
- Subscription upgrades and downgrades
- Subscriptions API
- ClassyTaxi 端對端訂閱的簡單應用
¹重新註冊 是指當一個使用者訂閱,然後取消訂閱,接著又在初始的訂閱過期之前重新訂閱。儘管使用者不會丟失授權,新的訂閱也和之前的一樣,他們還是會經歷另一個付款流程,因為他們承諾了未來的付款。他們會收到新的購買令牌並且 linkedPurchaseToken 欄位會在升級或者降級的時候被設定。
本文所有的程式碼都遵循 Apache 2.0 許可。本文不包括 Google 正式產品任何部分,並且只是為了參考使用。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。