SAP Spartacus 用户认证的实现
文章目錄
- UserAuthModule
- Authentication Flow
- AuthService
- Storing Tokens and User Identifiers
- 用戶認證的典型流程和包含步驟
- Access Tokens in API Calls and Error Recovery
- Persisting Authentication Data in the Browser Storage
- ASM
- Configuring Authorization Code Flow or Implicit Flow
- Commerce Cloud的一個限制
- Specifies if new refresh token should be created during refreshing an Access Token
- reuseRefreshToken = true - old refresh token will be returned, refresh token can be used more than one time
- reuseRefreshToken = false - new refresh token will be created
- Specifies if new refresh token should be created during refreshing an Access Token
- reuseRefreshToken = true - old refresh token will be returned, refresh token can be used more than one time
- reuseRefreshToken = false - new refresh token will be created
- Specifies if new refresh token should be created during refreshing an Access Token
- reuseRefreshToken = true - old refresh token will be returned, refresh token can be used more than one time
- reuseRefreshToken = false - new refresh token will be created
-
Commerce Cloud Authentication
-
SAP Spartacus 用戶認證的實現
From the beginning, Spartacus has included both client authentication and user authentication. Although this is not typical for web applications, it is necessary for Spartacus to work with the OCC API.
SAP Spartacus 支持 client 認證和 user 認證,為了配合 Commerce Cloud OCC API.
OCC API 有不少 endpoints是針對未登錄用戶調用的,比如用戶注冊,密碼重置,以guest方式下單等等。
這些匿名用戶消費的OCC API,也需要提供Access Token才能訪問。Access Token通過OAuth協議里定義的名叫Client Credentials Flow這一認證流來獲取。這個過程稱為Client Authentication.
而User Authentication,則是調用代表某一登錄用戶,向Commerce Cloud后臺發起 API 調用之前必須完成的流程,比如更新用戶的profile,此時該用戶必須首先登錄。用戶登錄后,Commerce Cloud 確認用戶credentials之后,返回Access Token,接下來該登錄用戶調用的所有OCC API,都使用該Access Token來完成。
在Spartacus 3.0之前,client和user認證都實現在AuthModule里,在3.0進行了一些重構,AuthModule導入了兩個Module, 分別進行這兩種認證:
- UserAuthModule
- ClientAuthModule
UserAuthModule
源代碼位置:spartacus\projects\core\src\auth\user-auth\user-auth.module.ts
https://github.com/SAP/spartacus/tree/develop/projects/core/src/auth/user-auth
UserAuthModule完成的5大任務
- performing authentication flow: 執行認證流
- storing tokens and user identifiers:存儲token
- adding access tokens for user calls:給用戶發起的HTTP請求添加Access Token
- recovering from API auth errors (for example, refreshing tokens when access tokens expire):API出現認證錯誤時的自動恢復機制,比如當Access Token過期時,自動刷新token
- persisting the tokens in browser storage - 將token存儲在瀏覽器storage里
Authentication Flow
Spartacus 3.0 使用開源的angular-oauth2-oidc來完成用戶認證。
下圖高亮區域包含了用戶認證過程中使用到的服務。
AuthService
AuthService是一個service facade,消費者可以調用它提供的下列兩個方法,觸發認證流程。
- loginWithCredentials:for the Resource Owner Password Flow
- loginWithRedirect:for the Implicit Flow or the Authorization Code Flow
The login method then interacts with the angular-oauth2-oidc library. However, this interaction always goes through the OAuthLibWrapperService, which is a layer for isolating external libraries from Spartacus code.
login方法通過OAuthLibWrapperService,調用angular-oauth2-oidc這個開源庫。OAuthLibWrapperService作為一個中間層,將Spartacus 代碼同第三方代碼隔離開。
The OAuthLibWrapperService class is also responsible for configuring the library. It uses the AuthConfigService to access the AuthConfig configuration provided in the application.
OauthLibWrapperService還包含了第三方庫的配置信息,使用AuthConfigService來訪問AuthConfig配置信息。
Storing Tokens and User Identifiers
After authentication, the tokens received from the library methods need to be stored somewhere.
用戶認證完成之后,服務器頒發的token通過開源庫文件接收,然后需要存儲在某處。
Previously, these tokens were kept in NgRx Store, but in Spartacus 3.0, there are dedicated services to keep the data.
在3.0之前,這些token存儲在NgRx store里,到了3.0, 有專門的服務用于存儲數據。
The library requires a storage mechanism with an API similar to localStorage or sessionStorage, and that was the main reason to switch from NgRx to services with a stream for keeping the data.
因為我們使用的開源angular-oauth2-oidc,需要相應的存儲機制采取類似localStorage或者SessionStorage的工作方式來配合,因此在3.0里,我們從NgRx切換成了支持Stream的自定義服務。
這些服務高亮如下:
For authentication, it is normally sufficient to store only tokens and their metadata (such as expiration time and scope).
對于認證機制來說,僅僅存儲token及其元數據即可,比如token的過期時間和scope.
However, with OCC, there is also the tightly-coupled user ID that needs to be set after login or logout, as well as being required for user emulation when working with the Assisted Service Module (ASM).
然而由于Commerce Cloud后臺實現的特殊性,在用戶登錄之后,需要設置一個緊耦合的user ID,并且在ASM模塊的user emulation場景下,也需要這個user ID.
Prior to Spartacus 3.0, the user ID was kept in the same place as the tokens in NgRx, and because of that previous association, the user ID remains in the UserAuthModule.
User ID 存儲于UserAuthModule.
However, the tokens have now been separated from the user identifier in this module. Tokens and their metadata are now stored with the AuthStorageService, while user IDs have their own, dedicated UserIdService.
Token現在存儲于AuthStorageService里, 而User ID 存儲于 UserIdService里。
用戶認證的典型流程和包含步驟
The UserIdService is part of a facade, because almost all services that interact with the OCC API require it. Previously, the user ID was exposed in the AuthService.getOccUserId. As a result, in Spartacus 3.0 it has been kept in the same facade, but in a different service and in a different method.
UserIDService是一個facade.
Access Tokens in API Calls and Error Recovery
After logging in a user, and storing their access token and user ID, it is then possible to request some of the user’s resources. To do so, it is necessary to pass an access token as a header in the request. In Spartacus, this is achieved with HTTP interceptors, as shown in the following diagram.
用戶成功登錄后,接下來發起的所有OCC API調用,都需要附上Access Token. 這個行為通過HTTP Interceptors完成。
The AuthInterceptor recognizes the request to the API based on the URL. If the request does not have the Authorization header, and does match the API path, the interceptor adds the header to the request. To make it easier to extend the interceptor, Spartacus has its own AuthHttpHeaderService helper service. In most cases, extending this one service should be enough.
應用開發人員無需進行任何操作,如果請求沒有包含Authorization頭部字段,并且路徑能夠匹配,那么interceptor會自動添加頭部字段。Interceptor使用AuthHttpHeaderService作為Helper Service,可以被partners擴展。
Apart from injecting the token, this interceptor is also responsible for handling errors that are related to authorization. In such cases, it tries to recover first and retry the request, and if that is not possible, it completes the logout process and redirects the user to the login page. When a request fails because the access token has expired, the interceptor uses the refresh token (if it exists) to request a new access token, and then retries the failed request with the new token.
Interceptor的另一個作用,當請求報錯時,interceptor首先嘗試retry,如果還不能成功,會執行logout流程,將用戶重定向到login頁面去。當請求由于Access Token過期導致失敗時,Interceptor會使用refresh token請求新的Access Token, 然后使用新得到的Access Token重發請求。
Persisting Authentication Data in the Browser Storage
After you log in, and your token has been stored and used for API calls, you refresh the page and suddenly you are no longer logged in. To avoid this problem, the AuthStatePersistenceService synchronizes the authentication data (such as tokens and user ID) in the browser storage, as shown in the following diagram.
AuthStatePersistenceService 負責將token,用戶ID等認證后返回的信息,同步到瀏覽器存儲介質里。
The AuthStatePersistenceService uses the StatePersistenceService to synchronize data to and from the browser storage. The user ID from the UserIdService, the tokens from the AuthStorageService, and the redirect URL from the AuthRedirectStorageService are all synchronized to the localStorage. Every time data changes, it is saved in the browser storage, and when the application starts, it is read from the storage into services.
- UserID - 由UserIdService提供
- token - AuthStorageService
- redirectUrl - AuthRedirectStorageService
以上三種數據全部同步到LocalStorage里。這些數據發生變化時,最新的數據都會存儲到瀏覽器storage里,當應用啟動時,直接從瀏覽器介質里加載到應用。
ASM
Since version 1.3, Spartacus supports the Assisted Service Module (ASM), which allows customer support agents to emulate users and help them accomplish their goals. This feature is tightly coupled with the AuthModule because agents need to log in with OAuth flow and make updates using the customer’s user ID.
從1.3版本開始,SAP Spartacus支持ASM模塊,允許Customer support座席通過模擬用戶的方式來幫助客戶解決問題。ASM同AuthModule具有緊耦合關系,因為座席需要使用OAuth flow登錄,然后使用客戶的User ID進行操作。
Configuring Authorization Code Flow or Implicit Flow
Now the Spartacus uses the angular-oauth2-oidc library, it is possible to support the Authorization Code Flow and the Implicit Flow.
既然Spartacus使用angular-oauth2-oidc庫,這意味著我們可以支持Authorization Code Flow 以及Implicit Flow.
These flows are very different from the Resource Owner Password Flow because the authentication part happens on the OAuth server login page rather than in Spartacus.
這兩種flow同Resource Owner Password flow有很大區別,因此其認證過程發生在OAuth server的登錄頁面,而不是在Spartacus里。
When Spartacus redirects you to this page, you provide login and password information there, and if the credentials match, you are redirected back to the Spartacus application with the token (Implicit Flow) or code (Authorization Code Flow) as part of the URL.
當Spartacus將用戶重定向到OAuth服務器的登錄頁面后,用戶提供用戶名和密碼,如果認證通過,用戶會被重定向回Spartacus,并且url的一部分,包含了token(Implicit Flow場景)或者Code(Authorization Code Flow).
Then Spartacus obtains the data from the URL and continues the login process (requests a token in the case of Authorization Code Flow, sets the user ID, dispatches the Login action, and redirects to the previously visited page).
Spartacus從url中獲取了數據之后,就能繼續login流程,比如在Authorization Code Flow里,設置User ID,分發Login action,重定向客戶回之前曾經訪問過的頁面。
authentication: {OAuthLibConfig: {responseType: 'token', // 'code`代表for Authorization Code Flow ,而token代表Implicit Flow}, },Apart from this configuration, you may need to update a few details for your OAuth client in Backoffice (such as allowing Implicit Flow or Authorization Code Flow, and setting the redirect URL of the application).
在Backoffice里配置OAuth client的明細,比如允許Implicit flow或者Authorization code flow,設置redirect url等等。
Once these settings are in place, Spartacus will use the defined flow out of the box.
The login route is configured in a way that detects the OAuth flow based on the configuration (LoginGuard and LoginRouteModule). When it detects a flow other than the Resource Owner Password Flow, Spartacus saves the previous URL (to redirect to after login), and redirects you to the OAuth server login page.
Commerce Cloud的一個限制
The default OAuth server that is provided with SAP Commerce Cloud does not have great support for the Authorization Code Flow and the Implicit Flow (there is no way to log out a user from an external application, and no way to customize the login page).
SAP Commerce Cloud使用的默認OAuth服務器,沒法完善地支持Authorization Code Flow和Implicit flow,比如無法從外部應用登出一個用戶,沒法自定義login頁面等等。
So for now it is expected that everyone using this OAuth server will continue to work with the Resource Owner Password Flow.
因此,使用SAP Commerce Cloud默認的OAuth服務器,意味著我們選用Resource Owner Password flow.
Resource Owner Password Credentials 授權和 Client Credentials 授權, 簡稱 Password 方式和 Client 方式,都只適用于應用是受信任的場景。一個典型的例子是同一個企業內部的不同產品要使用本企業的 OAuth 2.0 體系。在有些情況下,產品希望能夠定制化授權頁面。由于是同個企業,不需要向用戶展示“xxx將獲取以下權限”等字樣并詢問用戶的授權意向,而只需進行用戶的身份認證即可。這個時候,由具體的產品團隊開發定制化的授權界面,接收用戶輸入賬號密碼,并直接傳遞給鑒權服務器進行授權即可。如果信任關系再進一步,或者調用者是一個后端的模塊,沒有用戶界面的時候,可以使用 Client 方式。
However, if you use a different OAuth server (such as Auth0), you can switch to either of these flows.
當然,如果不用Commerce Cloud默認的OAuth認證服務器,就可以選擇切換到其他OAuth 認證 flow去。
oauthauthorizationserver.tokenServices.reuseRefreshToken=false”setting that to true should in theory only help in the case where:
-
you are logged in on 1 device
-
a bit later you log in on another device
-
your session expires on one first device
-
if the property is true, and it’s not 12 hours since login to 2nd device, you can still continue browsing. If false, you get logged out there too
Specifies if new refresh token should be created during refreshing an Access Token
reuseRefreshToken = true - old refresh token will be returned, refresh token can be used more than one time
reuseRefreshToken = false - new refresh token will be created
oauthauthorizationserver.tokenServices.reuseRefreshToken=false
Specifies if new refresh token should be created during refreshing an Access Token
reuseRefreshToken = true - old refresh token will be returned, refresh token can be used more than one time
reuseRefreshToken = false - new refresh token will be created
oauthauthorizationserver.tokenServices.reuseRefreshToken=false
Specifies if new refresh token should be created during refreshing an Access Token
reuseRefreshToken = true - old refresh token will be returned, refresh token can be used more than one time
reuseRefreshToken = false - new refresh token will be created
oauthauthorizationserver.tokenServices.reuseRefreshToken=false
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的SAP Spartacus 用户认证的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安装 SAP Spartacus 3.0
- 下一篇: VLAD算法浅析, BOF、FV比较