You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中AWS Cognito登录后Token未更新问题求助

AWS Cognito登录后Token未更新问题排查与解决

问题根源分析

  1. IdentityProviderManager 无动态更新能力:你自定义的IdentityProviderManager如果仅在初始化时传入固定的loginMaps,未提供token更新逻辑,每次调用logins()都会返回初始的旧token,而非最新登录凭证。
  2. 异步流程时机错误:在loginCognito(data:)的continueWith闭包中直接调用await getLoginsToken(),但continueWith为同步闭包,此时AWS服务配置可能尚未完全生效,导致读取到旧token。
  3. 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)
            }
        }
    }
}

针对疑问的解答

  1. Token未更新的原因:核心是IdentityProviderManager无动态更新能力,且登录流程中异步调用时机错误,导致配置未生效就读取token。
  2. 确保返回最新Token:让IdentityProviderManager支持动态更新,登录时同步更新其内部token;登录完成后先刷新凭证,再读取token。
  3. 是否需要调用clearCredentials():需要,clearCredentials()清除内存旧凭证,配合clearKeychain()彻底清理本地缓存,避免旧token残留,调用时机应在更新登录信息之后、刷新凭证之前。

内容的提问来源于stack exchange,提问作者Nguyễn Đức Thành

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:06:04