HarmonyOS APP开发中的生物识别小实践
HarmonyOS APP开发中的生物识别:@ohos.userIAM.userAuth 深度解析
📌 核心要点:生物识别是 HarmonyOS 安全认证的最高体验层,掌握 userAuth 模块才能实现指纹/人脸认证与安全级别的精准匹配
一、背景与动机
想象一下这个场景——你在地铁上单手拿着手机,另一只手提着早餐,这时候需要打开支付 App 确认一笔订单。如果还要输入6位密码,那体验简直灾难。但如果只需要看一眼手机,或者轻轻碰一下指纹传感器,支付就完成了——这就是生物识别的魅力。
生物识别不是什么新鲜事,但在 HarmonyOS 上实现它有很多讲究。不同的场景需要不同的认证方式:支付需要高安全级别的人脸+指纹双重认证,解锁App只需要低安全级别的面部识别就够了。如果一刀切地使用最高安全级别,用户体验会很差;如果安全级别太低,又可能被照片或假指纹骗过。
HarmonyOS 的 @ohos.userIAM.userAuth 模块提供了灵活的生物识别认证框架,支持指纹、人脸、PIN 码等多种认证方式,并且可以按需配置安全等级。理解这个模块,你就能在安全性和便利性之间找到最佳平衡点。
二、核心原理
2.1 生物识别认证架构
flowchart TB
A[应用发起认证请求] --> B[UserAuthClient]
B --> C{认证方式选择}
C -->|指纹| D[FingerprintAuth]
C -->|人脸| E[FaceAuth]
C -->|PIN码| F[PinAuth]
C -->|组合| G[MultiFactorAuth]
D --> H[TEE安全环境]
E --> H
F --> H
G --> H
H --> I{安全级别判断}
I -->|S1| J[便捷级<br/>照片可能通过]
I -->|S2| K[安全级<br/>需要活体检测]
I -->|S3| L[高安全级<br/>硬件级防伪]
J --> M[返回认证结果]
K --> M
L --> M
classDef primary fill:#4CAF50,stroke:#388E3C,color:#fff
classDef warning fill:#FF9800,stroke:#F57C00,color:#fff
classDef error fill:#F44336,stroke:#D32F2F,color:#fff
classDef info fill:#2196F3,stroke:#1976D2,color:#fff
classDef purple fill:#9C27B0,stroke:#7B1FA2,color:#fff
class A,B primary
class C,D,E,F,G info
class H purple
class I,J,K,L warning
class M primary
2.2 认证方式与安全级别
HarmonyOS 定义了三种生物识别类型和三个安全级别,它们之间的组合决定了认证的严格程度:
| 认证类型 | API常量 | 说明 | 硬件要求 |
|---|---|---|---|
| PIN码 | PIN |
数字/图案密码 | 无特殊要求 |
| 指纹 | FINGERPRINT |
指纹传感器采集 | 指纹传感器 |
| 人脸 | FACE |
前置摄像头采集 | 前置摄像头+3D结构光(S3级别) |
| 安全级别 | API常量 | 说明 | 典型场景 |
|---|---|---|---|
| S1 | S1 |
便捷级,可能被伪造 | App解锁 |
| S2 | S2 |
安全级,需要活体检测 | 普通支付 |
| S3 | S3 |
高安全级,硬件级防伪 | 大额转账 |
2.3 认证流程
sequenceDiagram
participant App as 应用
participant UserAuth as UserAuth服务
participant TEE as TEE安全环境
participant User as 用户
App->>UserAuth: 1. 创建认证会话(authIntent)
UserAuth->>UserAuth: 2. 检查认证能力可用性
UserAuth->>App: 3. 返回可用认证方式
App->>UserAuth: 4. 发起认证(onStart)
UserAuth->>TEE: 5. 启动TEE内认证
TEE->>User: 6. 提示用户操作(放手指/看镜头)
User->>TEE: 7. 提供生物特征
TEE->>TEE: 8. 特征比对(TEE内完成)
TEE->>UserAuth: 9. 返回认证结果
UserAuth->>App: 10. 回调通知认证结果
Note over TEE: 生物特征数据永不离开TEE<br/>应用只能获得成功/失败结果
关键点:生物特征数据(指纹图像、人脸数据)永远不会离开 TEE 安全环境。应用只能获得"认证成功"或"认证失败"的结果,无法获取原始生物特征数据。这就像你把钥匙交给保险箱验证——保险箱只告诉你"钥匙对不对",不会把锁芯结构暴露给你。
三、代码实战
3.1 基础生物识别认证
最简单的用法——检测设备是否支持生物识别,然后发起一次认证。
import { userAuth } from '@kit.UserAuthenticationKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 生物识别认证管理器
* 封装常用的生物识别认证操作
*/
class BiometricAuthManager {
private authInstance: userAuth.UserAuthInstance | null = null;
/**
* 检查设备是否支持指定的认证方式
* @param authType 认证类型
* @param trustLevel 信任级别
*/
async checkAuthAbility(
authType: userAuth.UserAuthType = userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel = userAuth.AuthTrustLevel.ATL2
): Promise<boolean> {
try {
// 查询认证能力
const result = userAuth.getAvailableStatus(authType, trustLevel);
if (result === userAuth.UserAuthResult.SUCCESS) {
console.info(`[BiometricAuth] 设备支持 ${this.getAuthTypeName(authType)} ` +
`认证,安全级别 ${this.getTrustLevelName(trustLevel)}`);
return true;
} else {
console.warn(`[BiometricAuth] 设备不支持该认证配置: result=${result}`);
return false;
}
} catch (error) {
const err = error as BusinessError;
console.error(`[BiometricAuth] 检查认证能力失败: code=${err.code}, msg=${err.message}`);
// 常见错误码处理
switch (err.code) {
case 12500001: // 认证能力不可用
console.error('[BiometricAuth] 该认证方式不可用,请检查设备硬件');
break;
case 12500002: // 用户未录入生物特征
console.error('[BiometricAuth] 用户尚未录入指纹/人脸,请先到系统设置中录入');
break;
case 12500003: // 认证被锁定
console.error('[BiometricAuth] 认证次数过多被锁定,请稍后重试');
break;
}
return false;
}
}
/**
* 发起生物识别认证
* @param authType 认证类型
* @param trustLevel 信任级别
* @param title 认证对话框标题
* @param subtitle 认证对话框副标题
*/
async authenticate(
authType: userAuth.UserAuthType = userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel = userAuth.AuthTrustLevel.ATL2,
title: string = '请验证身份',
subtitle: string = '使用指纹验证'
): Promise<userAuth.UserAuthResult> {
try {
// 1. 先检查认证能力
const available = await this.checkAuthAbility(authType, trustLevel);
if (!available) {
console.error('[BiometricAuth] 认证能力不可用,无法发起认证');
return userAuth.UserAuthResult.GENERAL_ERROR;
}
// 2. 创建认证请求
const authRequest: userAuth.UserAuthRequest = {
challenge: this.generateChallenge(), // 挑战码,防止重放攻击
authType: authType,
trustLevel: trustLevel,
};
// 3. 创建认证实例
this.authInstance = userAuth.getUserAuthInstance(authRequest);
// 4. 订阅认证结果
return new Promise<userAuth.UserAuthResult>((resolve, reject) => {
this.authInstance!.on('result', {
onResult(result: userAuth.UserAuthResult, extraInfo?: userAuth.AuthResultInfo) {
console.info(`[BiometricAuth] 认证结果: ${result}`);
if (result === userAuth.UserAuthResult.SUCCESS) {
console.info('[BiometricAuth] 认证成功!');
if (extraInfo) {
console.info(`[BiometricAuth] 认证方式: ${extraInfo.authType}`);
console.info(`[BiometricAuth] 安全级别: ${extraInfo.trustLevel}`);
}
} else if (result === userAuth.UserAuthResult.FAIL) {
console.warn('[BiometricAuth] 认证失败,生物特征不匹配');
} else if (result === userAuth.UserAuthResult.CANCELED) {
console.info('[BiometricAuth] 用户取消了认证');
} else if (result === userAuth.UserAuthResult.TIMEOUT) {
console.warn('[BiometricAuth] 认证超时');
}
resolve(result);
}
});
// 5. 启动认证
this.authInstance!.start();
console.info('[BiometricAuth] 认证已启动');
});
} catch (error) {
const err = error as BusinessError;
console.error(`[BiometricAuth] 认证异常: code=${err.code}, msg=${err.message}`);
return userAuth.UserAuthResult.GENERAL_ERROR;
}
}
/**
* 取消正在进行的认证
*/
cancelAuthentication(): void {
if (this.authInstance) {
try {
this.authInstance.cancel();
console.info('[BiometricAuth] 认证已取消');
} catch (error) {
const err = error as BusinessError;
console.error(`[BiometricAuth] 取消认证失败: ${err.message}`);
}
}
}
/**
* 生成随机挑战码
* 用于防止重放攻击
*/
private generateChallenge(): string {
const length = 16;
const array = new Uint8Array(length);
for (let i = 0; i < length; i++) {
array[i] = Math.floor(Math.random() * 256);
}
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
/**
* 获取认证类型名称
*/
private getAuthTypeName(type: userAuth.UserAuthType): string {
switch (type) {
case userAuth.UserAuthType.PIN: return 'PIN码';
case userAuth.UserAuthType.FINGERPRINT: return '指纹';
case userAuth.UserAuthType.FACE: return '人脸';
default: return '未知';
}
}
/**
* 获取信任级别名称
*/
private getTrustLevelName(level: userAuth.AuthTrustLevel): string {
switch (level) {
case userAuth.AuthTrustLevel.ATL1: return 'S1(便捷级)';
case userAuth.AuthTrustLevel.ATL2: return 'S2(安全级)';
case userAuth.AuthTrustLevel.ATL3: return 'S3(高安全级)';
case userAuth.AuthTrustLevel.ATL4: return 'S4(最高安全级)';
default: return '未知';
}
}
}
// 使用示例:App解锁场景
async function demoAppUnlock() {
const authManager = new BiometricAuthManager();
// 使用指纹进行App解锁(S2安全级别)
const result = await authManager.authenticate(
userAuth.UserAuthType.FINGERPRINT,
userAuth.AuthTrustLevel.ATL2,
'解锁应用',
'请使用指纹验证身份'
);
if (result === userAuth.UserAuthResult.SUCCESS) {
console.info('[Demo] 应用解锁成功');
// 进入应用主界面
} else {
console.warn('[Demo] 应用解锁失败,回退到密码输入');
// 显示密码输入界面
}
}
3.2 多因素组合认证
高安全场景(如支付、转账)需要多种认证方式组合使用,提高安全性。
import { userAuth } from '@kit.UserAuthenticationKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 多因素认证管理器
* 支持指纹+人脸、PIN+指纹等组合认证
*/
class MultiFactorAuthManager {
/**
* 认证配置:定义不同场景的认证策略
*/
private readonly AUTH_POLICIES: Map<string, AuthPolicy> = new Map([
['app_unlock', {
description: '应用解锁',
primaryAuth: userAuth.UserAuthType.FACE,
fallbackAuth: userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel.ATL1,
requireMultiFactor: false,
}],
['payment', {
description: '支付验证',
primaryAuth: userAuth.UserAuthType.FINGERPRINT,
fallbackAuth: userAuth.UserAuthType.PIN,
trustLevel: userAuth.AuthTrustLevel.ATL2,
requireMultiFactor: false,
}],
['large_transfer', {
description: '大额转账',
primaryAuth: userAuth.UserAuthType.FINGERPRINT,
fallbackAuth: userAuth.UserAuthType.FACE,
trustLevel: userAuth.AuthTrustLevel.ATL3,
requireMultiFactor: true, // 需要双重认证
}],
['sensitive_operation', {
description: '敏感操作',
primaryAuth: userAuth.UserAuthType.FACE,
fallbackAuth: userAuth.UserAuthType.PIN,
trustLevel: userAuth.AuthTrustLevel.ATL3,
requireMultiFactor: true,
}],
]);
/**
* 根据场景执行认证
* @param scenario 认证场景
*/
async authenticateByScenario(scenario: string): Promise<boolean> {
const policy = this.AUTH_POLICIES.get(scenario);
if (!policy) {
console.error(`[MultiFactor] 未知场景: ${scenario}`);
return false;
}
console.info(`[MultiFactor] 场景: ${policy.description}`);
// 尝试主要认证方式
const primaryResult = await this.tryAuthenticate(
policy.primaryAuth,
policy.trustLevel
);
if (primaryResult === userAuth.UserAuthResult.SUCCESS) {
// 如果不需要多因素认证,直接返回成功
if (!policy.requireMultiFactor) {
return true;
}
// 需要多因素认证,继续第二因素
console.info('[MultiFactor] 第一因素认证成功,继续第二因素...');
const secondaryResult = await this.tryAuthenticate(
policy.fallbackAuth,
policy.trustLevel
);
return secondaryResult === userAuth.UserAuthResult.SUCCESS;
}
// 主要认证方式失败或不可用,尝试回退方式
if (primaryResult === userAuth.UserAuthResult.CANCELED) {
// 用户主动取消,不再尝试回退
return false;
}
console.info('[MultiFactor] 主要认证方式不可用,尝试回退方式...');
const fallbackResult = await this.tryAuthenticate(
policy.fallbackAuth,
policy.trustLevel
);
if (fallbackResult === userAuth.UserAuthResult.SUCCESS) {
if (!policy.requireMultiFactor) {
return true;
}
// 多因素场景:回退方式成功后,还需要另一种认证
console.info('[MultiFactor] 回退方式认证成功,继续补充认证...');
const supplementResult = await this.tryAuthenticate(
policy.primaryAuth,
policy.trustLevel
);
return supplementResult === userAuth.UserAuthResult.SUCCESS;
}
return false;
}
/**
* 尝试使用指定方式进行认证
*/
private async tryAuthenticate(
authType: userAuth.UserAuthType,
trustLevel: userAuth.AuthTrustLevel
): Promise<userAuth.UserAuthResult> {
try {
// 先检查可用性
const availableStatus = userAuth.getAvailableStatus(authType, trustLevel);
if (availableStatus !== userAuth.UserAuthResult.SUCCESS) {
console.warn(`[MultiFactor] ${this.getAuthTypeName(authType)} 不可用`);
return userAuth.UserAuthResult.GENERAL_ERROR;
}
// 创建认证请求
const authRequest: userAuth.UserAuthRequest = {
challenge: this.generateChallenge(),
authType: authType,
trustLevel: trustLevel,
};
const authInstance = userAuth.getUserAuthInstance(authRequest);
return new Promise<userAuth.UserAuthResult>((resolve) => {
authInstance.on('result', {
onResult(result: userAuth.UserAuthResult) {
resolve(result);
}
});
authInstance.start();
});
} catch (error) {
const err = error as BusinessError;
console.error(`[MultiFactor] 认证异常: ${err.message}`);
return userAuth.UserAuthResult.GENERAL_ERROR;
}
}
private generateChallenge(): string {
const length = 16;
const array = new Uint8Array(length);
for (let i = 0; i < length; i++) {
array[i] = Math.floor(Math.random() * 256);
}
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
private getAuthTypeName(type: userAuth.UserAuthType): string {
switch (type) {
case userAuth.UserAuthType.PIN: return 'PIN码';
case userAuth.UserAuthType.FINGERPRINT: return '指纹';
case userAuth.UserAuthType.FACE: return '人脸';
default: return '未知';
}
}
}
/**
* 认证策略接口
*/
interface AuthPolicy {
description: string;
primaryAuth: userAuth.UserAuthType;
fallbackAuth: userAuth.UserAuthType;
trustLevel: userAuth.AuthTrustLevel;
requireMultiFactor: boolean;
}
// 使用示例:不同场景的认证策略
async function demoMultiFactorAuth() {
const manager = new MultiFactorAuthManager();
// 场景1:应用解锁(低安全级别,单因素)
const unlockResult = await manager.authenticateByScenario('app_unlock');
console.info(`[Demo] 应用解锁: ${unlockResult ? '成功' : '失败'}`);
// 场景2:支付验证(中安全级别,单因素+回退)
const paymentResult = await manager.authenticateByScenario('payment');
console.info(`[Demo] 支付验证: ${paymentResult ? '成功' : '失败'}`);
// 场景3:大额转账(高安全级别,双重认证)
const transferResult = await manager.authenticateByScenario('large_transfer');
console.info(`[Demo] 大额转账: ${transferResult ? '成功' : '失败'}`);
}
3.3 认证状态监听与安全等级配置
在实际应用中,我们需要监听认证状态变化,并根据不同的安全等级动态调整认证策略。
import { userAuth } from '@kit.UserAuthenticationKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 认证状态监听器
* 监听生物特征变化和认证状态
*/
class AuthStateMonitor {
private authInstance: userAuth.UserAuthInstance | null = null;
/**
* 查询设备支持的所有认证能力
* 返回每种认证方式的可用状态
*/
async queryDeviceAuthCapabilities(): Promise<AuthCapability[]> {
const capabilities: AuthCapability[] = [];
const authTypes = [
userAuth.UserAuthType.PIN,
userAuth.UserAuthType.FINGERPRINT,
userAuth.UserAuthType.FACE,
];
const trustLevels = [
userAuth.AuthTrustLevel.ATL1,
userAuth.AuthTrustLevel.ATL2,
userAuth.AuthTrustLevel.ATL3,
userAuth.AuthTrustLevel.ATL4,
];
for (const authType of authTypes) {
for (const trustLevel of trustLevels) {
try {
const status = userAuth.getAvailableStatus(authType, trustLevel);
const isAvailable = status === userAuth.UserAuthResult.SUCCESS;
capabilities.push({
authType: authType,
trustLevel: trustLevel,
isAvailable: isAvailable,
authTypeName: this.getAuthTypeName(authType),
trustLevelName: this.getTrustLevelName(trustLevel),
});
if (isAvailable) {
console.info(`[AuthState] ✅ ${this.getAuthTypeName(authType)} ` +
`@ ${this.getTrustLevelName(trustLevel)} 可用`);
}
} catch {
// 该组合不支持,跳过
}
}
}
console.info(`[AuthState] 设备共有 ${capabilities.filter(c => c.isAvailable).length} 种可用认证组合`);
return capabilities;
}
/**
* 根据安全需求推荐最佳认证方案
* @param securityRequirement 安全需求等级
*/
async recommendAuthScheme(
securityRequirement: 'low' | 'medium' | 'high' | 'critical'
): Promise<RecommendedScheme> {
const capabilities = await this.queryDeviceAuthCapabilities();
// 根据安全需求确定最低信任级别
const minTrustLevel: Map<string, userAuth.AuthTrustLevel> = new Map([
['low', userAuth.AuthTrustLevel.ATL1],
['medium', userAuth.AuthTrustLevel.ATL2],
['high', userAuth.AuthTrustLevel.ATL3],
['critical', userAuth.AuthTrustLevel.ATL4],
]);
const requiredLevel = minTrustLevel.get(securityRequirement) ?? userAuth.AuthTrustLevel.ATL2;
// 优先选择指纹(便捷性最好),其次人脸,最后PIN
const authPriority = [
userAuth.UserAuthType.FINGERPRINT,
userAuth.UserAuthType.FACE,
userAuth.UserAuthType.PIN,
];
let recommended: AuthCapability | null = null;
for (const authType of authPriority) {
const found = capabilities.find(
c => c.authType === authType && c.trustLevel === requiredLevel && c.isAvailable
);
if (found) {
recommended = found;
break;
}
}
// 如果精确匹配失败,降低信任级别再找
if (!recommended) {
for (const authType of authPriority) {
const found = capabilities.find(
c => c.authType === authType && c.isAvailable
);
if (found) {
recommended = found;
console.warn(`[AuthState] 无法满足${securityRequirement}安全需求,降级为 ${found.trustLevelName}`);
break;
}
}
}
const scheme: RecommendedScheme = {
securityRequirement: securityRequirement,
primaryAuth: recommended?.authType ?? userAuth.UserAuthType.PIN,
trustLevel: recommended?.trustLevel ?? userAuth.AuthTrustLevel.ATL1,
isDowngraded: recommended?.trustLevel !== requiredLevel,
description: recommended
? `推荐使用${recommended.authTypeName}(${recommended.trustLevelName})`
: '无可用的生物识别方式,请使用PIN码',
};
console.info(`[AuthState] 推荐方案: ${scheme.description}`);
return scheme;
}
/**
* 执行带完整回调的认证
* 监听认证过程中的各种状态变化
*/
async authenticateWithFullCallbacks(
authType: userAuth.UserAuthType,
trustLevel: userAuth.AuthTrustLevel
): Promise<userAuth.UserAuthResult> {
try {
const authRequest: userAuth.UserAuthRequest = {
challenge: this.generateChallenge(),
authType: authType,
trustLevel: trustLevel,
};
this.authInstance = userAuth.getUserAuthInstance(authRequest);
return new Promise<userAuth.UserAuthResult>((resolve) => {
// 监听认证结果
this.authInstance!.on('result', {
onResult(result: userAuth.UserAuthResult, extraInfo?: userAuth.AuthResultInfo) {
console.info(`[AuthCallback] 认证结果: ${result}`);
if (extraInfo) {
console.info(`[AuthCallback] 错误码: ${extraInfo.errCode ?? '无'}`);
console.info(`[AuthCallback] 认证耗时: ${extraInfo.remainTimes ?? '未知'}`);
}
resolve(result);
}
});
// 启动认证
this.authInstance!.start();
console.info('[AuthCallback] 认证已启动,等待用户操作...');
});
} catch (error) {
const err = error as BusinessError;
console.error(`[AuthCallback] 认证异常: ${err.message}`);
return userAuth.UserAuthResult.GENERAL_ERROR;
}
}
/**
* 释放认证资源
*/
release(): void {
if (this.authInstance) {
try {
this.authInstance.off('result');
this.authInstance = null;
console.info('[AuthState] 认证资源已释放');
} catch (error) {
const err = error as BusinessError;
console.error(`[AuthState] 释放资源失败: ${err.message}`);
}
}
}
private generateChallenge(): string {
const length = 16;
const array = new Uint8Array(length);
for (let i = 0; i < length; i++) {
array[i] = Math.floor(Math.random() * 256);
}
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
private getAuthTypeName(type: userAuth.UserAuthType): string {
switch (type) {
case userAuth.UserAuthType.PIN: return 'PIN码';
case userAuth.UserAuthType.FINGERPRINT: return '指纹';
case userAuth.UserAuthType.FACE: return '人脸';
default: return '未知';
}
}
private getTrustLevelName(level: userAuth.AuthTrustLevel): string {
switch (level) {
case userAuth.AuthTrustLevel.ATL1: return 'S1';
case userAuth.AuthTrustLevel.ATL2: return 'S2';
case userAuth.AuthTrustLevel.ATL3: return 'S3';
case userAuth.AuthTrustLevel.ATL4: return 'S4';
default: return '未知';
}
}
}
/**
* 认证能力信息
*/
interface AuthCapability {
authType: userAuth.UserAuthType;
trustLevel: userAuth.AuthTrustLevel;
isAvailable: boolean;
authTypeName: string;
trustLevelName: string;
}
/**
* 推荐认证方案
*/
interface RecommendedScheme {
securityRequirement: string;
primaryAuth: userAuth.UserAuthType;
trustLevel: userAuth.AuthTrustLevel;
isDowngraded: boolean;
description: string;
}
// 使用示例:智能认证方案选择
async function demoSmartAuthSelection() {
const monitor = new AuthStateMonitor();
// 查询设备认证能力
await monitor.queryDeviceAuthCapabilities();
// 不同安全需求的推荐方案
const lowScheme = await monitor.recommendAuthScheme('low');
const mediumScheme = await monitor.recommendAuthScheme('medium');
const highScheme = await monitor.recommendAuthScheme('high');
const criticalScheme = await monitor.recommendAuthScheme('critical');
// 使用推荐方案进行认证
const result = await monitor.authenticateWithFullCallbacks(
mediumScheme.primaryAuth,
mediumScheme.trustLevel
);
// 释放资源
monitor.release();
}
四、踩坑与注意事项
4.1 权限声明
生物识别认证需要声明权限:
{
"requestPermissions": [
{
"name": "ohos.permission.ACCESS_BIOMETRIC",
"reason": "$string:biometric_auth_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
4.2 必须提供回退方案
不是所有设备都支持生物识别,也不是所有用户都录入了生物特征。必须提供 PIN 码或密码作为回退方案:
async function safeAuthenticate(): Promise<boolean> {
const authManager = new BiometricAuthManager();
// 先尝试指纹认证
const fingerprintAvailable = await authManager.checkAuthAbility(
userAuth.UserAuthType.FINGERPRINT,
userAuth.AuthTrustLevel.ATL2
);
if (fingerprintAvailable) {
const result = await authManager.authenticate(
userAuth.UserAuthType.FINGERPRINT,
userAuth.AuthTrustLevel.ATL2
);
if (result === userAuth.UserAuthResult.SUCCESS) {
return true;
}
}
// 指纹不可用或认证失败,回退到PIN码
console.info('[SafeAuth] 回退到PIN码认证');
const pinAvailable = await authManager.checkAuthAbility(
userAuth.UserAuthType.PIN,
userAuth.AuthTrustLevel.ATL2
);
if (pinAvailable) {
const result = await authManager.authenticate(
userAuth.UserAuthType.PIN,
userAuth.AuthTrustLevel.ATL2
);
return result === userAuth.UserAuthResult.SUCCESS;
}
// 所有方式都不可用,回退到应用内密码
console.warn('[SafeAuth] 所有系统认证方式不可用,使用应用内密码');
return false;
}
4.3 认证实例的生命周期
每个 UserAuthInstance 只能使用一次,认证完成后必须释放:
// ❌ 错误:复用认证实例
const instance = userAuth.getUserAuthInstance(request);
await startAndAwait(instance); // 第一次认证
await startAndAwait(instance); // 报错!实例已消费
// ✅ 正确:每次认证创建新实例
async function performAuth(request: userAuth.UserAuthRequest) {
const instance = userAuth.getUserAuthInstance(request);
try {
return await startAndAwait(instance);
} finally {
instance.off('result'); // 清理回调
}
}
4.4 Challenge 的重要性
Challenge(挑战码)是防止重放攻击的关键。每次认证都应该生成不同的 challenge:
// ❌ 危险:使用固定challenge
const request: userAuth.UserAuthRequest = {
challenge: 'fixed_challenge_123', // 容易被重放攻击
authType: userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel.ATL2,
};
// ✅ 安全:每次生成随机challenge
const request: userAuth.UserAuthRequest = {
challenge: generateRandomChallenge(), // 每次不同的挑战码
authType: userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel.ATL2,
};
4.5 人脸识别的局限性
人脸识别在不同安全级别下的表现差异很大:
| 安全级别 | 防伪能力 | 2D摄像头 | 3D结构光 |
|---|---|---|---|
| ATL1 | 低,可能被照片欺骗 | ✅ 可用 | ✅ 可用 |
| ATL2 | 中,需要活体检测 | ⚠️ 部分设备 | ✅ 可用 |
| ATL3 | 高,硬件级防伪 | ❌ 不支持 | ✅ 可用 |
| ATL4 | 最高 | ❌ 不支持 | ⚠️ 部分设备 |
如果你的应用需要高安全级别的人脸认证,务必检查设备是否支持3D结构光。
五、HarmonyOS 6 适配
5.1 API 变更
| 变更项 | HarmonyOS 5 | HarmonyOS 6 |
|---|---|---|
| 认证实例创建 | getUserAuthInstance |
新增 getUserAuthInstanceV2 支持自定义UI |
| 认证回调 | on('result') |
新增 on('tip') 提供实时认证提示 |
| 活体检测 | 隐含在trustLevel中 | 新增显式 livenessDetection 配置 |
| 认证意图 | 不支持 | 新增 authIntent 区分认证用途 |
| 多因素认证 | 需手动组合 | 新增 AuthSession 原生多因素支持 |
5.2 迁移指南
// HarmonyOS 5 写法
const request: userAuth.UserAuthRequest = {
challenge: challenge,
authType: userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel.ATL2,
};
const instance = userAuth.getUserAuthInstance(request);
// HarmonyOS 6 推荐写法
const requestV2: userAuth.UserAuthRequestV2 = {
challenge: challenge,
authType: userAuth.UserAuthType.FINGERPRINT,
trustLevel: userAuth.AuthTrustLevel.ATL2,
// HarmonyOS 6 新增:认证意图
authIntent: userAuth.UserAuthIntent.VERIFY,
// HarmonyOS 6 新增:自定义UI配置
uiOptions: {
dialogStyle: userAuth.DialogStyle.CLASSIC,
customTitle: '请验证身份',
customSubtitle: '使用指纹完成支付验证',
},
};
const instanceV2 = userAuth.getUserAuthInstanceV2(requestV2);
5.3 实时认证提示
HarmonyOS 6 新增了认证过程中的实时提示回调,可以给用户更好的引导:
// HarmonyOS 6: 监听认证提示
instanceV2.on('tip', {
onTip(tip: userAuth.AuthTip) {
switch (tip) {
case userAuth.AuthTip.FINGERPRINT_TIP_TOO_FAST:
console.info('手指移动太快,请放慢速度');
break;
case userAuth.AuthTip.FINGERPRINT_TIP_TOO_SLOW:
console.info('手指移动太慢,请稍快一些');
break;
case userAuth.AuthTip.FINGERPRINT_TIP_PARTIAL:
console.info('指纹覆盖不完整,请调整手指位置');
break;
case userAuth.AuthTip.FACE_TIP_NOT_DETECTED:
console.info('未检测到人脸,请正对摄像头');
break;
case userAuth.AuthTip.FACE_TIP_POOR_LIGHT:
console.info('光线不足,请移到明亮处');
break;
}
}
});
六、总结
核心知识点回顾
生物识别认证(userAuth)
├── 认证方式
│ ├── PIN码 ── 最基础,所有设备支持
│ ├── 指纹 ── 便捷性好,需要指纹传感器
│ └── 人脸 ── 无接触,3D结构光支持高安全级别
├── 安全级别
│ ├── ATL1(S1) ── 便捷级,可能被伪造
│ ├── ATL2(S2) ── 安全级,需要活体检测
│ ├── ATL3(S3) ── 高安全级,硬件级防伪
│ └── ATL4(S4) ── 最高安全级
├── 核心操作
│ ├── 能力检查 ── getAvailableStatus
│ ├── 创建实例 ── getUserAuthInstance
│ ├── 启动认证 ── instance.start()
│ ├── 结果回调 ── on('result')
│ └── 取消认证 ── instance.cancel()
├── 多因素认证
│ ├── 策略配置 ── 按场景定义认证策略
│ ├── 优先级选择 ── 指纹 > 人脸 > PIN
│ ├── 回退机制 ── 主方式失败自动回退
│ └── 双重验证 ── 高安全场景需要两种认证
└── 注意事项
├── 权限声明 ── ACCESS_BIOMETRIC
├── 回退方案 ── 必须提供PIN/密码回退
├── 实例生命周期 ── 每次认证创建新实例
├── Challenge ── 防止重放攻击
└── 人脸局限 ── 2D摄像头不支持高安全级别
生物识别是安全与体验的平衡艺术。太严格,用户觉得麻烦;太宽松,安全形同虚设。掌握认证方式、安全级别和多因素组合策略,你就能为不同场景设计出恰到好处的认证方案。记住:永远提供回退方案——不是每个用户都愿意(或能够)使用生物识别。
- 点赞
- 收藏
- 关注作者
评论(0)