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

添加SecAccessControlRef后SecItemAdd返回errSecParam错误求助

解决SecItemAdd使用kSecAttrAccessControl返回errSecParam的问题

代码中的核心错误点

  • 可访问性规则冲突:kSecAttrAccessControl对象已经通过SecAccessControlCreateWithFlags的第二个参数指定了kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,但你又在后续的update字典中添加了kSecAttrAccessibleAlways。这两个字段不能同时存在,会直接触发errSecParam错误。
  • 对象所有权错误转移:kSecUseAuthenticationUIAllow是系统提供的常量,不需要用__bridge_transfer转移所有权,这种操作会导致对象被错误释放,进而引发参数异常,应改用__bridge进行类型转换。
  • 未校验Access Control对象创建结果:SecAccessControlCreateWithFlags可能因设备未设置锁屏密码(你指定的规则要求必须有密码)等原因返回nil,直接将nil传入kSecAttrAccessControl会导致errSecParam。

修正后的代码

1. 修正查询字典生成方法

static NSDictionary * AFKeyChainQueryDictionaryWithIdentifier(NSString *identifier){
    NSCParameterAssert(identifier);
    
    NSError *error = nil;
    SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
                                            kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
                                            kSecAccessControlUserPresence,
                                            &error);
    // 校验Access Control对象是否创建成功
    if (!sacObject) {
        NSLog(@"创建SecAccessControlRef失败: %@", error);
        return nil;
    }

    return @{
            (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
            (__bridge id)kSecAttrService: @"AFOAuthCredentialService",
            (__bridge id)kSecAttrAccount: identifier,
            (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacObject,
            (__bridge id)kSecUseAuthenticationUI: (__bridge id)kSecUseAuthenticationUIAllow,
    };
}

2. 修正存储方法

+ (OSStatus)storeCredential:(AFOAuthCredential *)credential
        withIdentifier:(NSString *)identifier
        withAccessbility:(id)accessbility
{
    NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
    if (!queryDictionary) {
        return errSecParam;
    }
    
    // 使用iOS 12+推荐的安全编码方式归档数据
    NSError *archiveError = nil;
    NSData *credentialData = [NSKeyedArchiver archivedDataWithRootObject:credential requiringSecureCoding:YES error:&archiveError];
    if (!credentialData) {
        NSLog(@"归档凭证失败: %@", archiveError);
        return errSecParam;
    }
    
    NSMutableDictionary *update = [NSMutableDictionary dictionary];
    update[(__bridge id)kSecValueData] = credentialData;
    // 移除单独的kSecAttrAccessible设置,避免与Access Control规则冲突
    // update[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways;
    
    [queryDictionary addEntriesFromDictionary:update];
    
    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)queryDictionary, NULL);
    
    return status;
}

额外注意事项

  • 确保设备已设置锁屏密码,因为你使用的kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly规则要求设备必须有密码,否则SecAccessControlCreateWithFlags会返回nil。
  • 如需调整可访问性规则,直接修改SecAccessControlCreateWithFlags的第二个参数即可,不要单独添加kSecAttrAccessible字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 10:51:09