這是 Jerry 2021 年的第 51 篇文章,也是汪子熙公衆號總共第 328 篇原創文章。
如無特殊說明,本公衆號介紹的 SAP Commerce Cloud UI,均指新一代基於 Spartacus 開源項目開發的 UI,而非傳統的基於 JSP 技術,同 Commerce 平臺耦合在一起的 Accelerator UI.
前文 從淘寶首頁登錄說起 提到過,淘寶網的用戶會話管理,通過瀏覽器的 Cookie 和服務器端的用戶會話對象來實現。
而 SAP Commerce Cloud UI,基於 100% API 驅動的無頭電商架構,Commerce 後臺將 Commerce 核心業務通過 OCC(Omni Commerce Connect) API 的方式暴露出來。藉助這些 API 和開源的 SAP Spartacus 庫,客戶可以自行開發具備個性化 UX 的電商網站。
關於 SAP Commerce Cloud Headless 架構的更多介紹,請參考我之前的文章:Jerry在2020 SAP全球技術大會的分享:SAP Spartacus技術介紹的文字版。
SAP Commerce Cloud 有個名爲 Oauth2 的 extension,基於 OAuth 2.0 協議實現了用戶認證和令牌頒發/功能,支持 OAuth 2.0 協議定義的包括 Resource Owner Password Flow 在內的全部四種認證流。
SAP Commerce Cloud UI 扮演了 OAuth 2.0 認證框架中的客戶端 (Client) 角色,通過消費 SAP Commerce Oauth2 擴展提供的 OAuth 系列 API,實現用戶會話管理。
讓我們從最初始的用戶登錄場景說起。
輸入用戶名和密碼:
SAP Commerce Cloud UI 調用 Commerce OAuth2 API,endpoint 爲 /authorizationserver/oauth/token, 將用戶名,密碼,client_id 和 client_secret 去換取訪問令牌(Access Token)和刷新令牌(Refresh Token).
這裏的 SAP Commerce Cloud UI 作爲 OAuth 認證體系裏的客戶端,其 client_id 和 client_secret 在 Commerce Backoffice 裏配置:
服務器端驗證通過後,會頒發訪問令牌和刷新令牌,如下圖 access_token 和 refresh_token 字段所示:
SAP Commerce Cloud UI 在 OAuth 體系中扮演的角色是客戶端,通過訪問令牌,獲得訪問 Commerce 後臺服務器上的業務數據的許可。而刷新令牌,用於當訪問令牌過期時,由客戶端憑藉其換取新的訪問令牌。刷新令牌本身是一個憑證,表明持有其的客戶端,曾經通過 OAuth 認證,獲得了訪問受保護資源的許可,當通過刷新令牌再次請求新的訪問令牌時,客戶端不用再從頭開始走一遍 OAuth 認證的完整流程。
SAP Commerce Cloud 的訪問令牌和刷新令牌都有過期時間,有時也稱爲 TTL(Time-to-Live,存活時間),默認值分別爲12小時和30天。
而我們團隊的開發人員,在開發 SAP Commerce Cloud UI 用戶會話管理功能,進行各種邊界條件的測試時,爲了方便起見,通常將自己本地搭建的 Commerce 服務器上令牌的過期時間進行了調整。比如下圖的例子,二者分別調整爲30秒和60秒之後過期:
訪問令牌獲取之後,在接下來 Commerce Cloud UI 消費後臺 OCC API 時,會將其附加在 HTTP 請求的頭部字段裏:
如果此時訪問令牌已經過期,則該請求會收到服務器 401 錯誤的應答:
以及錯誤詳情 InvalidTokenError:Access token expired: IqQ-8cYzHV1gjQOpnYytHTFPt30
顯然這種偏技術的錯誤消息不應該顯示給用戶,幸運的是我們還有刷新令牌。此時,SAP Commerce Cloud UI 會將過期的訪問令牌,連同刷新令牌一齊發送給 Commerce 後臺,申請一個新的訪問令牌:
SAP Commerce Cloud UI 初次登錄申請令牌時,grant_type 的值爲 password;而訪問令牌過期,使用刷新令牌重新申請時,grant_type 的值應該填充爲 refresh_token.
如果刷新令牌的過期時間也到達了,該怎麼辦?沒有刷新令牌,也就無從獲取新的訪問令牌。因此,我們會將用戶重定向到登錄頁面,顯示一條“Session expired”的提示信息,讓其登錄之後,重新獲取訪問令牌和刷新令牌。
前文從淘寶首頁登錄說起曾經提到,我們在淘寶網上購物,如果不小心刷新了瀏覽器,只要客戶端存儲的 Cookie 尚未過期,就可仍然保持登錄狀態。這樣,客戶刷新之前的會話,比如添加商品到購物車,或者正在進行結帳的某一步,仍然處於有效狀態。
SAP Commerce Cloud UI 通過將訪問令牌持久化到瀏覽器的 Local Storage 中來實現上述場景。
每當用戶成功登錄後,我們將 Commerce 後臺服務器頒發的訪問令牌進行持久化存儲,保存到瀏覽器 Local Storage 中。
每次 SAP Commerce Cloud UI 初始化時,通過 Angular APP_INITIALIZER 這個注入令牌,我們開發了 AuthStatePersistenceService 服務,將瀏覽器本地存儲中的令牌同步到內存中。
採取這種設計後,即使用戶在購物過程中刷新了瀏覽器,SAP Commerce Cloud UI 重新加載後,從 Local Storage 中取出訪問令牌同步到內存中,接下來的用戶操作,繼續使用該令牌調用 Commerce OCC API,不會因瀏覽器刷新而中斷。
總結起來,SAP Commerce Cloud UI 有關訪問令牌和刷新令牌的使用場景如下:
(1) 用戶登錄後,SAP Commerce Cloud UI 將服務器頒發的訪問令牌存儲於內存中,並持久化到瀏覽器 Local Storage.
對於刷新令牌,出於安全性考慮,我們團隊實現時,僅將其維護在應用內存中,並不進行持久化操作。
(2) 當用戶操作 UI,觸發 API 調用後收到服務器返回的訪問令牌過期的錯誤之後,SAP Commerce Cloud UI 自動利用刷新令牌,申請新的訪問令牌;待拿到新的訪問令牌之後,使用該令牌重新調用之前因爲舊的訪問令牌過期而失敗的 API;這一系列機制對於用戶來說完全透明,用戶在界面上的操作不會受到任何影響。
(3) 如果用戶操作觸發的 API 調用收到的服務器返回爲刷新令牌過期,SAP Commerce Cloud UI 會暫存當前用戶瀏覽頁面的 URL,並將用戶重定向到登錄頁面;用戶重新登錄後,獲取到新的訪問令牌和刷新令牌,再被 SAP Commerce Cloud 重定向到刷新令牌過期時正在操作的頁面。
本文簡單介紹了 SAP Commerce Cloud UI 用戶會話管理的基本實現原理和支持的場景。對其技術實現感興趣的朋友,可以查閱我們團隊發佈在 Github 上的文檔,感謝閱讀。
https://sap.github.io/spartacus-docs/session-management
更多閱讀
更多Jerry的原創文章,盡在:"汪子熙":