macos – 仅使用ServiceName获取存储在Keychain中的用户名?或者:你应该在哪里存储用户名?

macos – 仅使用ServiceName获取存储在Keychain中的用户名?或者:你应该在哪里存储用户名?,第1张

概述所以OS X Keychain有三条信息: > ServiceName(我的应用程序的名称) >用户名 >密码 我显然总是知道ServiceName.有没有办法找到该ServiceName的任何已保存用户名? (一旦知道用户名,就很容易找到密码.) 我更喜欢使用一个漂亮的Cocoa包装器,如EMKeychain来做到这一点.但EMKeychain要求UserName获取任何钥匙串项目!   (EM 所以OS X Keychain有三条信息:

> Servicename(我的应用程序的名称)
>用户名
>密码

我显然总是知道Servicename.有没有办法找到该Servicename的任何已保存用户名? (一旦知道用户名,就很容易找到密码.)

我更喜欢使用一个漂亮的Cocoa包装器,如EMKeychain来做到这一点.但EMKeychain要求Username获取任何钥匙串项目!

  (EMGenericKeychainItem *)genericKeychainItemForService:(Nsstring *)servicenameString withUsername:(Nsstring *)usernameString;

如果您需要用户名来查找凭据,您希望如何充分利用钥匙串中的保存凭据?将用户名保存在.pList文件中的最佳做法是什么?

解决方法 SecKeychainFindGenericPassword仅返回单个钥匙串项.要查找特定服务的所有通用密码,您需要在钥匙串上运行查询.根据您定位的OS X版本,有多种方法可以执行此 *** 作.

如果需要在10.5或更低版本上运行,则需要使用SecKeychainSearchCreateFromAttributes.这是一个相当可怕的API.下面是一个返回将用户名映射到密码的字典的方法的粗略剪辑.

- (NSDictionary *)genericPasswordsWithService:(Nsstring *)service {    Osstatus status;    // Construct a query.    const char *utf8Service = [service UTF8String];    SecKeychainAttribute attr = { .tag = kSecServiceItemAttr,.length = strlen(utf8Service),.data = (voID *)utf8Service };    SecKeychainAttribute attrList = { .count = 1,.attr = &attr };    SecKeychainSearchref *search = NulL;    status = SecKeychainSearchCreateFromAttributes(NulL,kSecGenericPasswordItemClass,&attrList,&search);    if (status) {        report(status);        return nil;    }    // Enumerate results.    NSMutableDictionary *result = [NSMutableDictionary dictionary];    while (1) {        SecKeychainItemRef item = NulL;        status = SecKeychainSearchcopyNext(search,&item);        if (status)            break;        // Find 'account' attribute and password value.        UInt32 tag = kSecAccountItemAttr;        UInt32 format = CSSM_DB_ATTRIBUTE_FORMAT_STRING;        SecKeychainAttributeInfo info = { .count = 1,.tag = &tag,.format = &format };        SecKeychainAttributeList *attrList = NulL;        UInt32 length = 0;        voID *data = NulL;        status = SecKeychainItemcopyAttributesAndData(item,&info,NulL,&length,&data);        if (status) {            CFRelease(item);            continue;        }        NSAssert(attrList->count == 1 && attrList->attr[0].tag == kSecAccountItemAttr,@"SecKeychainItemcopyAttributesAndData is messing with us");        Nsstring *account = [[[Nsstring alloc] initWithBytes:attrList->attr[0].data length:attrList->attr[0].length enCoding:NSUTF8StringEnCoding] autorelease];        Nsstring *password = [[[Nsstring alloc] initWithBytes:data length:length enCoding:NSUTF8StringEnCoding] autorelease];        [result setobject:password forKey:account];        SecKeychainItemFreeAttributesAndData(attrList,data);        CFRelease(item);    }    CFRelease(search);    return result;}

对于10.6及更高版本,您可以使用稍微不那么不方便的SecItemcopyMatching API:

- (NSDictionary *)genericPasswordsWithService:(Nsstring *)service {    NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:                           kSecclassGenericPassword,kSecclass,(ID)kcfBooleanTrue,kSecReturnData,kSecReturnAttributes,kSecMatchlimitAll,kSecMatchlimit,service,kSecAttrService,nil];    NSArray *itemDicts = nil;    Osstatus status = SecItemcopyMatching((CFDictionaryRef)q,(CFTypeRef *)&itemDicts);    if (status) {        report(status);        return nil;    }    NSMutableDictionary *result = [NSMutableDictionary dictionary];    for (NSDictionary *itemDict in itemDicts) {        NSData *data = [itemDict objectForKey:kSecValueData];        Nsstring *password = [[[Nsstring alloc] initWithData:data enCoding:NSUTF8StringEnCoding] autorelease];        Nsstring *account = [itemDict objectForKey:kSecAttrAccount];        [result setobject:password forKey:account];    }    [itemDicts release];    return result;}

对于10.7或更高版本,您可以使用我精彩的LKKeychain框架(PLUG!).它不支持构建基于属性的查询,但您只需列出所有密码并过滤掉您不需要的密码.

- (NSDictionary *)genericPasswordsWithService:(Nsstring *)service {    LKKCKeychain *keychain = [LKKCKeychain defaultKeychain];    NSMutableDictionary *result = [NSMutableDictionary dictionary];    for (LKKCGenericPassword *item in [keychain genericPasswords]) {        if ([service isEqualToString:item.service]) {            [result setobject:item.password forKey:item.account];        }    }    return result;}

(我没有尝试运行,甚至没有编译上面的任何代码示例;抱歉任何错别字.)

总结

以上是内存溢出为你收集整理的macos – 仅使用ServiceName获取存储在Keychain中的用户名?或者:你应该在哪里存储用户名?全部内容,希望文章能够帮你解决macos – 仅使用ServiceName获取存储在Keychain中的用户名?或者:你应该在哪里存储用户名?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1002917.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存