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

AWS Cognito Swift:首次登录后Token无法更新的问题求助

解决AWS Cognito二次登录后Token未更新的问题

问题现象

  • 首次登录时,Login with Token与Current Token输出一致
  • 二次及后续登录时,传入的新Token能在loginCognito中正常打印,但getLoginsToken返回的始终是首次登录的旧Token
  • 尝试调用credentialsProvider.clearCredentials()无法解决问题

核心原因

  1. 原代码中IdentityProviderManager的loginMaps是初始化时固定的,没有动态更新机制,一旦创建就只能返回初始Token
  2. AWSCognitoCredentialsProvider默认会缓存身份提供者实例和身份ID,二次登录时即使创建新的credentialsProvider,旧的缓存实例依然会被复用,导致返回旧Token

解决方案

1. 修改IdentityProviderManager支持动态更新Token

让身份提供者类可以随时更新存储的Token,不用每次登录都创建新实例:

private class IdentityProviderManager: NSObject, AWSIdentityProviderManager {
    private var loginMaps: [String: String]

    init(loginMaps: [String: String]) {
        self.loginMaps = loginMaps
        super.init()
    }

    // 新增方法:动态更新指定key的Token
    func updateLoginToken(for key: String, token: String) {
        loginMaps[key] = token
    }

    func logins() -> AWSTask<NSDictionary> {
        return AWSTask(result: loginMaps as NSDictionary)
    }
}

2. 重构loginCognito函数,复用实例+清空缓存

优先复用已有的凭证提供者实例,更新Token后强制清空缓存并刷新,确保Cognito使用最新Token:

private func loginCognito(data: AWSConfigData) async throws {
    let loginsKey = "cognito-idp.\(data.region).amazonaws.com/\(data.userPoolId)"
    
    var credentialsProvider: AWSCognitoCredentialsProvider
    
    // 检查是否已有可用的凭证提供者实例
    if let existingConfig = AWSServiceManager.default()?.defaultServiceConfiguration,
       let existingProvider = existingConfig.credentialsProvider as? AWSCognitoCredentialsProvider,
       let identityManager = existingProvider.identityProvider as? IdentityProviderManager {
        // 更新现有实例的Token
        identityManager.updateLoginToken(for: loginsKey, token: data.idToken)
        credentialsProvider = existingProvider
        // 清空缓存的凭证和身份ID,强制Cognito刷新
        credentialsProvider.clearCredentials()
        credentialsProvider.clearIdentityId()
    } else {
        // 首次登录:创建新的实例
        let logins = [loginsKey: data.idToken]
        let identityProviderManager = IdentityProviderManager(loginMaps: logins)
        credentialsProvider = AWSCognitoCredentialsProvider(
            regionType: data.regionType,
            identityPoolId: data.identityPoolId,
            identityProviderManager: identityProviderManager
        )
    }
    
    self.awsConfigData = data
    let configuration = AWSServiceConfiguration(
        region: data.regionType,
        credentialsProvider: credentialsProvider
    )
    AWSServiceManager.default()?.defaultServiceConfiguration = configuration
    
    // 等待凭证刷新完成,确保新Token生效
    return try await withCheckedThrowingContinuation { continuation in
        credentialsProvider.refresh().continueWith { task in
            if let error = task.error {
                continuation.resume(throwing: error)
            } else {
                // 打印更新后的Token
                credentialsProvider.identityProvider.logins().continueWith { loginTask in
                    if let result = loginTask.result, let token = result[loginsKey] as? String {
                        print("Login with Token:", token)
                    }
                    continuation.resume(returning: ())
                }
            }
        }
    }
    
    // 验证最新Token
    Task {
        let currentToken = try await self.getLoginsToken()
        print("Current Token:", currentToken)
    }
}

3. getLoginsToken函数无需修改

原函数逻辑可以保持不变,现在它会从更新后的身份提供者实例中获取最新Token:

private func getLoginsToken() async throws -> String {
    guard let configuration = AWSServiceManager.default().defaultServiceConfiguration,
          let credentialsProvider = configuration.credentialsProvider as? AWSCognitoCredentialsProvider,
          let awsConfigData else {
        let error = NSError(domain: "S3Error", code: -1, userInfo: [NSLocalizedDescriptionKey: "Cannot get credentialsProvider"])
        print("Token Error:", error)
        throw error
    }

    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 {
                print("Token:", token)
                return continuation.resume(returning: token)
            } else if let error = task.error {
                print("Token Error:", error)
                return continuation.resume(throwing: error)
            } else {
                let error = NSError(domain: "S3Error", code: -1, userInfo: [NSLocalizedDescriptionKey: "Get login error"])
                return continuation.resume(throwing: error)
            }
        }
    }
}

关键修改说明

  • 让IdentityProviderManager支持动态更新Token,避免重复创建实例
  • 登录时复用现有凭证提供者,同时调用clearCredentials()和clearIdentityId()彻底清空缓存
  • 调用credentialsProvider.refresh()强制Cognito服务刷新凭证,确保新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 14:25:20