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

Swift中OAuth2令牌清理异常:注销后无法正常重新登录

Swift OAuth2注销与钥匙串问题解决方案

一、解决注销后自动登录的异常

  • 彻底清除OAuth2实例状态:
    调用authorizer.oauth2.forgetTokens()后,手动清空实例内的令牌字段,避免内存中残留状态触发自动登录:
    authorizer.oauth2.forgetTokens()
    authorizer.oauth2.accessToken = nil
    authorizer.oauth2.refreshToken = nil
    
  • 销毁并重建OAuth2实例:
    注销完成后直接销毁原OAuth2CodeGrant实例,重新登录时创建全新实例,不要复用旧实例:
    // 注销时销毁实例
    authorizer.oauth2 = nil
    // 重新登录初始化新实例
    let oauthSettings = OAuth2CodeGrantSettings(
        clientId: "你的ClientID",
        clientSecret: "你的ClientSecret",
        authorizeUrl: "授权地址",
        tokenUrl: "令牌地址",
        redirectUri: "回调地址"
    )
    authorizer.oauth2 = OAuth2CodeGrant(settings: oauthSettings)
    

二、解决钥匙串删除失败(Error Code -25300)

错误码-25300代表errSecItemNotFound,要么条目不存在,要么权限不匹配,按以下步骤处理:

  • 核对钥匙串访问组:
    如果App开启了钥匙串共享,确保OAuth2实例的keychainAccessGroup和项目配置的访问组完全一致,否则无法正确操作钥匙串条目。
  • 手动调用钥匙串API删除:
    框架自带的删除方法失效时,直接用系统钥匙串API指定条件删除:
    // 删除令牌相关钥匙串条目
    func deleteTokenFromKeychain(oauth2: OAuth2CodeGrant) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: oauth2.keychainAccountForTokens,
            kSecAttrService as String: oauth2.keychainServiceName,
            kSecAttrAccessGroup as String: oauth2.keychainAccessGroup ?? ""
        ]
        SecItemDelete(query as CFDictionary)
    }
    
    // 删除客户端凭证相关钥匙串条目
    func deleteClientCredentialsFromKeychain(oauth2: OAuth2CodeGrant) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: oauth2.keychainAccountForClientCredentials,
            kSecAttrService as String: oauth2.keychainServiceName,
            kSecAttrAccessGroup as String: oauth2.keychainAccessGroup ?? ""
        ]
        SecItemDelete(query as CFDictionary)
    }
    
  • 确保在主线程执行钥匙串操作:
    部分钥匙串API对线程环境有要求,尽量把删除/查询逻辑放在主线程调用。

三、访问keychainAccountForClientCredentials和keychainAccountForTokens的存储数据

可以直接通过这两个属性拿到对应的钥匙串账户名,再用系统API查询存储的原始数据:

// 查询令牌数据
func getStoredTokenData(oauth2: OAuth2CodeGrant) -> Data? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: oauth2.keychainAccountForTokens,
        kSecAttrService as String: oauth2.keychainServiceName,
        kSecReturnData as String: kCFBooleanTrue!,
        kSecMatchLimit as String: kSecMatchLimitOne
    ]
    
    var result: AnyObject?
    let status = SecItemCopyMatching(query as CFDictionary, &result)
    return status == errSecSuccess ? (result as? Data) : nil
}

// 查询客户端凭证数据
func getStoredClientCredentialsData(oauth2: OAuth2CodeGrant) -> Data? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: oauth2.keychainAccountForClientCredentials,
        kSecAttrService as String: oauth2.keychainServiceName,
        kSecReturnData as String: kCFBooleanTrue!,
        kSecMatchLimit as String: kSecMatchLimitOne
    ]
    
    var result: AnyObject?
    let status = SecItemCopyMatching(query as CFDictionary, &result)
    return status == errSecSuccess ? (result as? Data) : nil
}

拿到的Data是框架序列化后的内容,一般是JSON格式,可尝试转成JSON对象解析具体内容。

内容的提问来源于stack exchange,提问作者Camille Gallet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 19:15:52