实现刷新令牌功能
刷新令牌是现代身份验证系统的关键组件,允许应用程序维持用户会话,而无需频繁重新验证。在本章中,我们将探讨如何在 Swift 中使用 Alamofire 实现刷新令牌。我们将涵盖以下主题:
- 理解刷新令牌在身份验证中的作用。
- 设置令牌刷新机制。
- 处理令牌过期和重试失败的请求。
- 实现安全且可重用的解决方案。
理解刷新令牌
刷新令牌是长期有效的令牌,用于在当前访问令牌过期时获取新的访问令牌。访问令牌是短期有效的,用于对 API 请求进行身份验证。当访问令牌过期时,应用程序可以使用刷新令牌来请求新的访问令牌,而无需用户再次登录。
其流程通常如下:
- 用户登录,服务器返回访问令牌和刷新令牌。
- 访问令牌用于 API 请求,直到其过期。
- 当访问令牌过期时,应用程序将刷新令牌发送到服务器以获取新的访问令牌。
- 新的访问令牌用于后续请求。
设置令牌刷新机制
要使用 Alamofire 实现刷新令牌,我们需要拦截请求、检查令牌过期情况,并在必要时刷新令牌。设置该机制的方法如下:
- 安全存储令牌:使用 Keychain 或其他安全存储机制来存储访问令牌和刷新令牌。
- 创建请求拦截器:Alamofire 的
RequestInterceptor协议允许我们调整和重试请求。我们将使用它来处理令牌刷新逻辑。
以下是 TokenInterceptor 类的示例:
swift
import Alamofire
import Foundation
class TokenInterceptor: RequestInterceptor {
private let baseURL = "https://api.example.com"
private let accessTokenKey = "accessToken"
private let refreshTokenKey = "refreshToken"
// 通过向 headers 中添加访问令牌来调整请求
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
var request = urlRequest
if let accessToken = KeychainHelper.shared.read(key: accessTokenKey) {
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
}
completion(.success(request))
}
// 如果请求因令牌过期而失败,则重试请求
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
guard let response = request.task?.response as? HTTPURLResponse,
response.statusCode == 401 else {
// 不是 401 错误,不重试
completion(.doNotRetry)
return
}
// 刷新令牌
refreshToken { success in
if success {
completion(.retry) // 重试原始请求
} else {
completion(.doNotRetryWithError(error)) // 请求失败
}
}
}
// 使用刷新令牌刷新访问令牌
private func refreshToken(completion: @escaping (Bool) -> Void) {
guard let refreshToken = KeychainHelper.shared.read(key: refreshTokenKey) else {
completion(false)
return
}
let parameters: [String: Any] = ["refresh_token": refreshToken]
AF.request("\(baseURL)/refresh", method: .post, parameters: parameters)
.validate()
.responseDecodable(of: TokenResponse.self) { response in
switch response.result {
case .success(let tokenResponse):
// 保存新的访问令牌
KeychainHelper.shared.save(tokenResponse.accessToken, forKey: self.accessTokenKey)
completion(true)
case .failure:
completion(false)
}
}
}
}
// Keychain 操作的辅助类
class KeychainHelper {
static let shared = KeychainHelper()
func save(_ value: String, forKey key: String) {
// 将值保存到 Keychain
}
func read(key: String) -> String? {
// 从 Keychain 读取值
return nil
}
}
// 令牌响应模型
struct TokenResponse: Decodable {
let accessToken: String
let refreshToken: String
}处理令牌过期和重试请求
TokenInterceptor 中的 retry 方法会检查请求是否因 401 状态码(表示令牌过期)而失败。如果是,则尝试刷新令牌。如果刷新成功,将使用新令牌重试原始请求。否则,请求失败。
实现安全且可重用的解决方案
为了使解决方案可重用,如上面所示,将令牌刷新逻辑封装在一个单独的类中。这使您可以轻松地将其集成到应用程序中任何使用 Alamofire 进行网络请求的部分。
以下是如何在 Alamofire 中使用 TokenInterceptor:
swift
let session = Session(interceptor: TokenInterceptor())
session.request("https://api.example.com/data")
.validate()
.responseDecodable(of: DataResponse.self) { response in
switch response.result {
case .success(let data):
print("收到数据:\(data)")
case .failure(let error):
print("请求失败:\(error.localizedDescription)")
}
}这种方法确保所有请求都能自动处理令牌过期和刷新,为用户提供无缝体验。
通过使用 Alamofire 实现刷新令牌,您可以构建健壮且安全的应用程序,有效地维持用户会话。对于依赖经过身份验证的 API 并需要提供流畅用户体验的应用程序,此机制至关重要。