在发布问题之前,我进行了很多搜索,但不幸的是,我无法找到问题的解决方案。
我开发了一个连接到服务器的应用程序,该服务器需要使用 access token
和 refresh 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 的代码,您就明白了。