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

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

  • access token有效期为1小时,可多次使用。

  • 刷新 token 的有效期为1 个月,并在访问 token 过期时使用。 刷新 token 只能使用一次。

当使用 refresh token 时,除了 access token 之外,我还会得到一个新的 refresh token

这是我的问题:

我写了一个 APIClient class 来处理我的应用程序需要的所有请求。这个 class 工作得很好,除非 access token 过期。当 access token 过期时,此时将运行的所有请求都将失败并返回 401 代码(未授权)。

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

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

查看以下 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() 
} 

谢谢

请您参考如下方法:

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

1: 在 APIClient 中定义你的 completionBlock

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

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

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

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

检查这些线程以获取有关如何定义 completionBlock Swift 的代码,您就明白了。

Another Example 1

Another example 2

Another Example 3


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

ios之将选择器转发到 Swift 中的多个对象