访问令牌过期后处理多个未授权的请求

zar*_*nis 5 oauth ios nsurlsession swift

在发布问题之前,我进行了很多搜索,但是很遗憾,我无法找到问题的解决方案。

我开发了一个应用程序,该应用程序连接到需要使用access token和进行身份验证的服务器refresh token

  • access token有效期为1 hour,可以多次使用。

  • refresh token有效期1 monthaccess token到期时使用。The refresh令牌只能使用一次。

refresh token使用时,我得到一个新的refresh token,以及除access token

这是我的问题:

我写了一个APIClient class,处理我的应用程序需要的所有请求。这class很有效,除非access token过期。当access token到期时,将在此时间运行将失败,所有的请求401 code(授权)。

我想要的是找到一个解决方案,该解决方案将刷新access token使用refresh token,然后重试所有失败的状态为status的请求code 401。请记住,刷新令牌的函数只能调用一次,因为refresh令牌仅对一种用途有效。

我想做的是找到一种写我的方法,APIClient class以便它支持令牌的刷新并重试所有失败的请求。如果您告诉我如何实现这一目标,我将不胜感激。

看一下下面的getRequest和sendRefreshRequest源代码。

func getRequestWith(requestType: FSRequestType, usingToken: Bool, parameters: RequestParameters?, completionClosure: @escaping (NetworkResult) -> Void) {
    let sessioConfig = URLSessionConfiguration.default
    let session = URLSession(configuration: sessioConfig, delegate: nil, delegateQueue: nil)
    guard var URL = APIClient.baseURL?.appendingPathComponent(requestType.rawValue) else { return }

    if let parameters = parameters {
        URL = URL.appendingQueryParameters(parameters)
    }

    var request = URLRequest(url: URL)
    request.httpMethod = "GET"

    if usingToken {
        let tokenString = "Bearer " + TokenManager.sharedManager.accessToken()!

        request.addValue(tokenString, forHTTPHeaderField: "Authorization")
    }

    let task = session.dataTask(with: request) { (data, response, error) in
        guard error == nil else { return completionClosure(.Error(error!.localizedDescription))}
        guard let data = data else { return completionClosure(.Error("Could not load data")) }

        let statusCode = (response as! HTTPURLResponse).statusCode

        if statusCode == 401 {
            //Handle refresh token
        } else if statusCode == 200 {
            let json = JSON(data: data)
            let responseJSON = json["response"]
            completionClosure(.Success(responseJSON))
        } else {
            completionClosure(.Error("Returned status code \(statusCode) from Get request with URL: \(request.url!)"))
        }
    }
    task.resume()
}

func sendRefreshRequest() {
    let session = URLSession(configuration: .default)

    guard var URL = APIClient.baseURL?.appendingPathComponent(FSRequestType.RefreshToken.rawValue) else {return}

    let URLParams = [
        "refresh_token" : TokenManager.sharedManager.refreshToken()!
    ]

    URL = URL.appendingQueryParameters(URLParams)
    var request = URLRequest(url: URL)
    request.httpMethod = "GET"

    let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
        let statusCode = (response as! HTTPURLResponse).statusCode

        if statusCode == 200 {

            let json = JSON(data: data!)
            if TokenManager.sharedManager.saveTokenWith(json) {
                print("RefreshedToken")
            } else {
                print("Failed saving new token.")
                SessionManager.sharedManager.deauthorize()
            }
        } else if statusCode == 400 {
            print("The refresh token is invalid")
            SessionManager.sharedManager.deauthorize()
        }
    })
    task.resume()
}
Run Code Online (Sandbox Code Playgroud)

谢谢

小智 1

我不使用 Swift 编写代码,因此无法为您提供代码,但我认为最简单的方法是:

1:定义你的completionBlock内心APIClient

APIClient2:在你的if (statusCode == 401)处理程序中处理内部的所有调用,

3:刷新完token后,可以检查是否成功completionBlock != nil,再次请求数据,成功则返回回调。

当您在 中执行所有刷新方法时APIClient,直到完成刷新并再次重试请求之前,您不会返回completionBlock。

调用的其他类APIClient将等待返回completionBlock,并且您可以传递completionBlock,直到获得正确的令牌并进行重试调用。

检查这些线程中有关如何定义 Swift 完成块的代码,您就会明白了。

另一个例子1

另一个例子2

另一个例子3