iOS Swift中AWS Cognito登录后Token未更新问题求助
AWS Cognito登录后Token未更新问题排查与解决
问题根源分析
- IdentityProviderManager 无动态更新能力:你自定义的
IdentityProviderManager如果仅在初始化时传入固定的loginMaps,未提供token更新逻辑,每次调用logins()都会返回初始的旧token,而非最新登录凭证。 - 异步流程时机错误:在
loginCognito(data:)的continueWith闭包中直接调用await getLoginsToken(),但continueWith为同步闭包,此时AWS服务配置可能尚未完全生效,导致读取到旧token。 - CredentialsProvider 未持久化+缓存未彻底清理:登录时创建的
credentialsProvider是局部变量,虽设置给全局配置,但旧实例可能仍被引用;且仅调用clearCredentials()未清理钥匙串缓存,旧token残留。
解决方案
1. 改造IdentityProviderManager支持动态更新Token
确保身份提供者可以实时更新登录信息:
class IdentityProviderManager: NSObject, AWSIdentityProviderManager { private var loginMaps: [String: String] init(loginMaps: [String: String]) { self.loginMaps = loginMaps super.init() } // 添加更新方法 func updateLogins(_ newLogins: [String: String]) { self.loginMaps = newLogins } func logins() -> AWSTask<NSDictionary> { return AWSTask(result: loginMaps as NSDictionary) } }
2. 修正登录流程逻辑
将核心实例作为类属性持久化,修正异步调用时机:
// 类属性 private var credentialsProvider: AWSCognitoCredentialsProvider? private var identityProviderManager: IdentityProviderManager? private func loginCognito(data: AWSConfigData) async throws { let loginsKey = "cognito-idp.\(data.region).amazonaws.com/\(data.userPoolId)" let logins = [loginsKey: data.idToken] // 复用或更新身份提供者 if let manager = identityProviderManager { manager.updateLogins(logins) } else { identityProviderManager = IdentityProviderManager(loginMaps: logins) } // 初始化或复用凭证提供者 if credentialsProvider == nil { credentialsProvider = AWSCognitoCredentialsProvider( regionType: data.regionType, identityPoolId: data.identityPoolId, identityProviderManager: identityProviderManager! ) } // 彻底清理旧缓存 credentialsProvider?.clearCredentials() credentialsProvider?.clearKeychain() self.awsConfigData = data // 先刷新凭证确保配置生效 try await withCheckedThrowingContinuation { continuation in credentialsProvider?.getCredentials().continueWith { task in if let error = task.error { continuation.resume(throwing: error) } else { let configuration = AWSServiceConfiguration( region: data.regionType, credentialsProvider: self.credentialsProvider! ) AWSServiceManager.default().defaultServiceConfiguration = configuration continuation.resume(returning: ()) } } } // 配置生效后再读取最新token let latestToken = try await getLoginsToken() printAWS(addition: "Latest Token after login:", message: latestToken) }
3. 优化Token读取逻辑
直接使用类属性的凭证提供者,避免全局配置的旧引用:
private func getLoginsToken() async throws -> String { guard let credentialsProvider = credentialsProvider, let awsConfigData else { throw NSError(domain: "S3Error", code: -1, userInfo: [NSLocalizedDescriptionKey: "Can't get credentialsProvider"]) } return try await withCheckedThrowingContinuation { continuation in credentialsProvider.identityProvider.logins().continueWith { task in let loginsKey = "cognito-idp.\(awsConfigData.region).amazonaws.com/\(awsConfigData.userPoolId)" if let result = task.result, let token = result[loginsKey] as? String { printAWS(addition: "Token:", message: "\(token)") continuation.resume(returning: token) } else if let error = task.error { continuation.resume(throwing: error) } else { let error = NSError(domain: "S3Error", code: -1, userInfo: [NSLocalizedDescriptionKey: "Get login error"]) continuation.resume(throwing: error) } } } }
针对疑问的解答
- Token未更新的原因:核心是
IdentityProviderManager无动态更新能力,且登录流程中异步调用时机错误,导致配置未生效就读取token。 - 确保返回最新Token:让
IdentityProviderManager支持动态更新,登录时同步更新其内部token;登录完成后先刷新凭证,再读取token。 - 是否需要调用clearCredentials():需要,
clearCredentials()清除内存旧凭证,配合clearKeychain()彻底清理本地缓存,避免旧token残留,调用时机应在更新登录信息之后、刷新凭证之前。
内容的提问来源于stack exchange,提问作者Nguyễn Đức Thành
相关产品推荐
相关产品推荐

