简述: 在类似支付宝为首的应用以及各种理财等涉及钱财对安全性要求较高的应用中,目前普遍对关键数据都做了安全访问限制,比如通过手势密码、指纹密码等手段,本章主要分析一下iOS开发中指纹识别的一些坑和技术要点。
指纹识别
指纹识别是iPhone5s iOS8.0之后推出的功能,需要硬件以及软件的支持。指纹识别的功能定义在系统框架<LocalAuthentication/LocalAuthentication.h>
中,并且在app中集成指纹识别是跟系统解锁iPhone用的一套指纹识别,就是说假如在app中指纹识别错误了5次(iOS 系统默认指纹识别错误5次后,指纹识别会被判定为无效状态),那么不仅app中的指纹识别系统是无效的,系统的iPhone指纹识别解锁系统也是无效的,必须输入iPhone解锁口令码验证之后,指纹识别才会被系统重新判别为有效!指纹识别有两个模式:
typedef NS_ENUM(NSInteger, LAPolicy)
{
//8.0支持的API
LAPolicyDeviceOwnerAuthenticationWithBiometrics NS_ENUM_AVAILABLE(NA, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0) = kLAPolicyDeviceOwnerAuthenticationWithBiometrics,
//9.0支持的API
LAPolicyDeviceOwnerAuthentication NS_ENUM_AVAILABLE(10_11, 9_0) = kLAPolicyDeviceOwnerAuthentication
} NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);
需要注意的是开发的时候一定要注意区分iOS系统的版本选用不同的API,避免出现重大问题。同时这两个不同的模式的响应方式也是不同的:
LAPolicyDeviceOwnerAuthenticationWithBiometrics
生物指纹识别。验证弹框有两个按钮,第一个是取消按钮,第二个按钮可以自定义标题名称(默认是"输入密码")。只有在第一次指纹验证失败后才会出现第二个按钮,这种鉴定方式的第二个按钮的功能自定义,第二个按钮的功能不做处理的话不会有任何响应。
前三次指纹验证失败,指纹验证框不再弹出。再次重新进入验证,还有两次验证机会,如果还是验证失败,TOUCH ID 被锁住不再继续弹出指纹验证框。(在iOS10.0以下系统中,不包括iOS 10.0,以后每次进来验证都是调用系统的设备密码直至输入正确的设备密码方可解除TOUCH ID锁,但是在iOS 10.0系统中,指纹识别累计错误5次系统判定指纹无效后不会弹出系统的设备密码输入页面,尴尬......开发的时候谁晓得iOS 10有这个大坑,被坑惨了。
Talk is cheap,show me the code.
- (void)checkTouchID{
LAContext *laContext = [[LAContext alloc] init];
//去掉 “输入密码”,这行代码可以去掉“输入密码”的按钮
laContext.localizedFallbackTitle = @"";
NSError *error;
if ([laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
NSLog(@"指纹识别有效");
[laContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:@"通过Home键验证已有手机指纹"
reply:^(BOOL success, NSError *error) {
if (success) {
//指纹验证通过
}else if (error.code == kLAErrorUserCancel){
//用户点击取消
}else if (error.code == kLAErrorAuthenticationFailed){
//用户验证没有通过,指纹错误
}
}];
}else {
NSLog(@"指纹识别无效%@",error.localizedDescription);
//不支持指纹识别,LOG出错误详情
switch (error.code) {
case LAErrorTouchIDNotEnrolled:
{
NSLog(@"TouchID is not enrolled");
break;
}
case LAErrorPasscodeNotSet:
{
NSLog(@"A passcode has not been set");
break;
}
default:
{
NSLog(@"TouchID not available");
break;
}
}
}
}
在iOS10系统中,指纹识别错误5次后,调用[laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]
就会返回NO,在- (void)checkTouchID
方法中,就会打印信息:NSLog(@"指纹识别无效%@",error.localizedDescription);
代码会跳到这个位置。
在iOS9、iOS8 系统中,指纹识别错误5次后,调用[laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]
就会返回YES,在- (void)checkTouchID
方法中,就会打印信息:指纹识别有效。 代码会跳到这个位置。NSLog(@"指纹识别有效");
LAPolicyDeviceOwnerAuthentication
生物指纹识别或系统密码验证。注意这个policy是9.0的API,对于8.0系统的手机不能使用。如果TOUCH ID 可用,且已经录入指纹,则优先调用指纹验证。其次是调用系统密码验证,如果没有开启设备密码,则不可以使用这种验证方式。指纹识别验证失败三次将自动弹出设备密码输入框,如果不进行密码输入。再次进来还可以有两次机会验证指纹,如果都失败则TOUCH ID被锁住。以后也只能弹出设备密码输入框。补充:值得注意的是在iOS9系统中,前三次验证失败会自动弹出密码验证框,后两次验证失败后不会自动弹出密码验证框。而在iOS 10系统中,前三次验证失败或者后两次验证失败,都会自动弹出密码验证框。
- (void)checkTouchID{
LAContext *laContext = [[LAContext alloc] init];
//去掉 “输入密码”
laContext.localizedFallbackTitle = @"";
NSError *error;
if ([laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
NSLog(@"指纹识别有效");
[laContext evaluatePolicy:LAPolicyDeviceOwnerAuthentication
localizedReason:@"通过Home键验证已有手机指纹"
reply:^(BOOL success, NSError *error) {
if (success) {
//指纹验证通过
}else if (error.code == kLAErrorUserCancel){
//用户点击取消
}else if (error.code == kLAErrorAuthenticationFailed){
//用户验证没有通过,指纹错误
}
}];
}else {
NSLog(@"指纹识别无效%@",error.localizedDescription);
//不支持指纹识别,LOG出错误详情
switch (error.code) {
case LAErrorTouchIDNotEnrolled:
{
NSLog(@"TouchID is not enrolled");
break;
}
case LAErrorPasscodeNotSet:
{
NSLog(@"A passcode has not been set");
break;
}
default:
{
NSLog(@"TouchID not available");
break;
}
}
}
}
在iOS9、iOS 10系统中,这个policy默认也有两个按钮,第一次验证指纹识别后会显示两个按钮,第二个按钮是"输入密码",默认点击第二个按钮会弹出设备密码输入框。
异常情况
上面所描述的是iOS系统设置了口令密码,同时也添加了指纹的情况。但是用户在使用过程中可能会出现各种情况,下面分析一下两种policy在不同系统上,只有口令密码、只有指纹、没有口令也没有指纹的情况下所作出的响应,通过打印输出结果确定代码的跳转位置。
LAPolicyDeviceOwnerAuthenticationWithBiometrics
- (void)checkTouchID{
LAContext *laContext = [[LAContext alloc] init];
//去掉 “输入密码”
laContext.localizedFallbackTitle = @"";
NSError *error;
if ([laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
NSLog(@"指纹识别有效");
}else {
NSLog(@"指纹识别无效%@",error.localizedDescription);
}
}
iOS8系统:
在只有口令密码的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
在只有指纹的情况下打印结果: NSLog(@"指纹识别无效%@",error.localizedDescription);
在没有口令也没有指纹的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
iOS9系统:
在只有口令密码的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
在只有指纹的情况下打印结果: NSLog(@"指纹识别无效%@",error.localizedDescription);
在没有口令也没有指纹的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
iOS10系统:
在只有口令密码的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
在只有指纹的情况下打印结果: NSLog(@"指纹识别无效%@",error.localizedDescription);
在没有口令也没有指纹的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
分析可知,在LAPolicyDeviceOwnerAuthenticationWithBiometrics
下必须系统口令码和指纹同时是存在的,才会判定指纹系统是可用的。
LAPolicyDeviceOwnerAuthentication
- (void)checkTouchID{
LAContext *laContext = [[LAContext alloc] init];
//去掉 “输入密码”
laContext.localizedFallbackTitle = @"";
NSError *error;
if ([laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
NSLog(@"指纹识别有效");
}else {
NSLog(@"指纹识别无效%@",error.localizedDescription);
}
}
iOS9系统:
在只有口令密码的情况下打印结果:NSLog(@"指纹识别有效");
在只有指纹的情况下打印结果: NSLog(@"指纹识别无效%@",error.localizedDescription);
在没有口令也没有指纹的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
iOS10系统:
在只有口令密码的情况下打印结果:NSLog(@"指纹识别有效");
在只有指纹的情况下打印结果: NSLog(@"指纹识别无效%@",error.localizedDescription);
在没有口令也没有指纹的情况下打印结果:NSLog(@"指纹识别无效%@",error.localizedDescription);
综合iOS9、iOS10在policy:LAPolicyDeviceOwnerAuthentication
下的表现,只要开启了系统口令码,就判定指纹系统可用,更加印证了 如果没有开启设备密码,则不可以使用这种验证方式。
指纹鉴定错误码
1、 验证(指纹/密码)不能开启的错误信息(指纹系统被判定为无效):
LAErrorPasscodeNotSet : 设备密码未设置
LAErrorTouchIDNotAvailable : TOUCH ID不可用
LAErrorTouchIDNotEnrolled : 指纹未录入
LAErrorTouchIDLockout : TOUCH ID被锁定
LAErrorAppCancel : APP调用了- (void)invalidate
方法使LAContext
失效
LAErrorInvalidContext : 实例化的LAContext
对象失效,再次调用evaluation...
方法则会弹出此错误信息
2、 其他错误信息(指纹系统判定有效,但是验证指纹错误):
LAErrorAuthenticationFailed : 鉴定失败
LAErrorUserCancel : 用户取消
LAErrorUserFallback : 用户选择输入密码
LAErrorSystemCancel : 系统取消(如:另外一个应用进入前台)
总结
上面分析了指纹识别的两种policy在不同系统上、不同状态下的各种响应状态,并且列出了一些指纹鉴定错误码,相信对整个API的作用有详尽的认识,开发出类似支付宝指纹识别的流程也不是难事,希望可以帮助更多人。