钥匙串 keyChain 存储账号密码

目前我们存储账号密码,一般存在 偏好设置表里,如果明文存储,安全上又有很大隐患,所以今天给大家推荐一种更安全的密码存储方式。

不知道大家是否注意过,当我们使用百度系列的产品时,比如说:我登录上了百度糯米app后,然后我又下载了一个百度云盘,当我打开百度云盘app的时候,我居然自动登录了!这里就是用到了keyChain来保存账号密码,并通过应用组的方式在 应用间共享一套账户密码。

iOS设备中的keyChain是一个安全的存储容器,可以用来为不同应用保存敏感信息(用户名,密码,网络密码等)。同时,keyChain是一个相对独立的空间,当应用替换或删除时并不会删除keyChain的内容,目前看来,使用keyChain来保存用户名和用户密码是最优的解决方案。

本例本着简单易用的原则,提供了一些利用keyChain对账号信息进行增、删、改、查的功能。

先看一下使用:

#import "ViewController.h"
#import "GZKeyChain.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //保存或更新
    [GZKeyChain saveUserName:@"张三" pwd:@"asdfghjkl"];
    [GZKeyChain saveUserName:@"lisi" pwd:@"asrtyui"];
    [GZKeyChain saveUserName:@"张三" pwd:@"rtghnm,loi"];//会覆盖先前密码

    //查询所有用户的账号密码
    NSDictionary *dic = [GZKeyChain loadAccountInfo];
    NSLog(@"dic = %@",dic);

    //查询某一用户的账号密码
    NSString *pwd = [GZKeyChain loadPwdForUserName:@"lisi"];
    NSLog(@"userPwd = %@",pwd);

    //删除某一用户的账号密码
    [GZKeyChain removeForUserName:@"张三"];
    NSLog(@"dic1 = %@",[GZKeyChain loadAccountInfo]);

    //删除所有用户的账号密码
    [GZKeyChain removeAll];
    NSLog(@"dic2 = %@",[GZKeyChain loadAccountInfo]);

}
@end

工具实现

// 需要引入 Security 框架

.h

#import <Foundation/Foundation.h>
#import <Security/Security.h>

@interface GZKeyChain : NSObject


/**
 保存或更新 用户名、密码
 */
+ (void)saveUserName:(NSString *)userName pwd:(NSString *)pwd;

+ (void)saveUserName:(NSString *)userName pwd:(NSString *)pwd service:(NSString *)service;

/**
 加载所有 用户名、密码 信息 。    key:用户名, value:密码
 */
+ (NSDictionary *)loadAccountInfo;

+ (NSDictionary *)loadAccountInfoWithService:(NSString *)service;

/**
 加载某一用户的密码
 */
+ (NSString *)loadPwdForUserName:(NSString *)userName;

+ (NSString *)loadPwdForUserName:(NSString *)userName service:(NSString *)service;

/**
 移除所有账号信息
 */
+ (void)removeAll;

+ (void)removeAllWithService:(NSString *)service;

/**
 移除某一账号的密码信息
 */
+ (void)removeForUserName:(NSString *)userName;

+ (void)removeForUserName:(NSString *)userName service:(NSString *)service;

@end

.m

#import "GZKeyChain.h"

@implementation GZKeyChain

+ (NSString *)defaultService
{
    return [[NSBundle mainBundle] bundleIdentifier] ? : @"";
}

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service 
{
    if (!service) service = self.defaultService;
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (id)kSecClassGenericPassword,(id)kSecClass,
            service, (id)kSecAttrService,
            service, (id)kSecAttrAccount,
            (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
            nil];
}

#pragma mark 写入
+ (void)saveUserName:(NSString *)userName pwd:(NSString *)pwd
{
    [self saveUserName:userName pwd:pwd service:nil];
}

+ (void)saveUserName:(NSString *)userName pwd:(NSString *)pwd service:(NSString *)service
{
    if (![userName isKindOfClass:[NSString class]]) return;
    if (!userName || !pwd) return;

    NSMutableDictionary *query = [self getKeychainQuery:service];
    NSDictionary *results = [self loadAccountInfoWithService:service];
    SecItemDelete((CFDictionaryRef)query);
    NSMutableDictionary *dataDic = [NSMutableDictionary dictionaryWithDictionary:results ?:@{}];
    [dataDic setObject:pwd forKey:userName];
    [query setObject:[NSKeyedArchiver archivedDataWithRootObject:dataDic] forKey:(id)kSecValueData];
    SecItemAdd((CFDictionaryRef)query, NULL);
}


#pragma mark 读取
+ (NSDictionary *)loadAccountInfo
{
    return [self loadAccountInfoWithService:nil];
}

+ (NSDictionary *)loadAccountInfoWithService:(NSString *)service {
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];

    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        @try {
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
        } @catch (NSException *e) {
            NSLog(@"Unarchive of %@ failed: %@", service, e);
        } @finally {
        }
    }
    if (keyData)
        CFRelease(keyData);
    return ret;
}


+ (NSString *)loadPwdForUserName:(NSString *)userName
{
    return [self loadPwdForUserName:userName service:nil];
}

+ (NSString *)loadPwdForUserName:(NSString *)userName service:(NSString *)service
{
    if (!userName) return nil;
    NSDictionary *results = [self loadAccountInfoWithService:service];
    if (![results isKindOfClass:[NSDictionary class]]) return nil;
    return [results objectForKey:userName];
}

#pragma mark 删除
+ (void)removeAll
{
    [self removeAllWithService:nil];
}

+ (void)removeAllWithService:(NSString *)service 
{
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((CFDictionaryRef)keychainQuery);
}

+ (void)removeForUserName:(NSString *)userName
{
    [self removeForUserName:userName service:nil];
}

+ (void)removeForUserName:(NSString *)userName service:(NSString *)service
{
    NSDictionary *results = [self loadAccountInfoWithService:service];
    if (!results) return;
    NSMutableDictionary *dataDic = [NSMutableDictionary dictionaryWithDictionary:results];
    [dataDic removeObjectForKey:userName];
    NSMutableDictionary *query = [self getKeychainQuery:service];
    SecItemDelete((CFDictionaryRef)query);
    [query setObject:[NSKeyedArchiver archivedDataWithRootObject:dataDic] forKey:(id)kSecValueData];
    SecItemAdd((CFDictionaryRef)query, NULL);
}

@end

觉得对你有用就给个 star 支持一下吧!详细demo下载

如有问题,欢迎评论交流!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值