簡體   English   中英

如何使用 RxSwift 處理刷新憑證

[英]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 和處理無效令牌

您提到的“巨大缺陷”是我考慮的用例之一:

  1. 由於在服務等待新令牌時多個請求可能未經授權,因此我需要一種方法來在提供令牌后通知所有請求。

解決方案...

由於要求(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM