[英]How to handle refreshing credentials using RxSwift
我的應用程序中的身份驗證流程有問題。 有一些 API 用於授權(它是如何工作的:我正在發送請求,它在 HTTPCookieStorage.shared 中設置身份驗證令牌cookies並帶有一些過期時間(20 分鍾))。 如果用戶通過身份驗證,我在HTTPCookieStorage.shared中有 authToken cookie,如果沒有,則 HTTPCookieStorage.shared為空。
現在我遇到了問題,如何刷新過期的令牌。 例如,如果我一小時不使用應用程序,我的令牌已過期,並且在獲得新的 authToken 之前我無法使用其他 api 調用。
現在我有以下解決方案:我在每個請求之前調用身份驗證請求並檢查我是否在 HTTPCookieStorage.shared 中有東西如果是,那么我 return.just(my_auth_token),如果沒有,我通過觸發身份驗證請求獲得新令牌。
但它有一個巨大的缺陷:如果我在應用啟動時有多個請求,將會有多個身份驗證請求可能導致身份驗證令牌的意外行為(比如它可以立即過期,因為我們已經獲得了新令牌來自另一個身份驗證請求)
所以問題是:如何讓其他 observables 等到會有一些 authToken? 我在考慮 skipUntil 運算符,但我認為它也不合適,因為一旦觸發,它就會傳遞所有事件,即進入 observable 的事件。 它很糟糕,因為一旦我們刷新令牌,我們就無法第二次刷新它。
這是我寫的一篇文章解決了這個問題: RxSwift 和處理無效令牌
您提到的“巨大缺陷”是我考慮的用例之一:
- 由於在服務等待新令牌時多個請求可能未經授權,因此我需要一種方法來在提供令牌后通知所有請求。
解決方案...
由於要求(3),我知道必須有某種 object 可以將所有請求綁定在一起,並且這個 object 主要負責在需要時獲取新令牌。 我將其命名為 class TokenAcquisitionService。 此 object 還將根據要求提供最新的令牌。
一旦你有一個正確構建的 TokenAcquisitionService object,你將能夠處理如下請求:
/**
Builds and makes network requests using the token provided by the
service. Will request a new token and retry if the result is an
unauthorized (401) error.
- parameter response: A function that sends requests to the network
and emits responses. Can be for example
`URLSession.shared.rx.response`
- parameter tokenAcquisitionService: The object responsible for
tracking the auth token. All requests should use the same
object.
- parameter request: A function that can build the request when
given a token.
- returns: response of a guaranteed authorized network request.
**/
typealias Response = (URLRequst) -> Observable<(response: HTTPURLResponse, data: Data)>
typealias Request = (String) -> URLRequest
func getData(response: @escaping Response, tokenAcquisitionService: TokenAcquisitionService, request: @escaping Request) -> Observable<(response: HTTPURLResponse, data: Data)> {
return Observable
.deferred { tokenAcquisitionService.token.take(1) }
.map { request($0) }
.flatMap { response($0) }
.map { response in
guard response.response.statusCode != 401 else { throw ResponseError.unauthorized }
return response
}
.retryWhen { $0.renewToken(with: tokenAcquisitionService) }
}
文章中提供了我構建的TokenAcquisionService
以及對其工作原理的分析以及證明它工作的完整測試工具。 它已在我知道的幾個項目中使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.