HarmonyOS 7 + User Authentication Kit + Asset Store Kit 技术干货:生物认证、敏感操作授权与关键资产安全闭环【鸿蒙心迹】
这篇我想聊一个很容易被低估的话题:很多应用不是没有“安全功能”,而是没有把“认证、授权、资产存储、访问审计”真正串起来。表面看只是多调几个接口,实际做工程时,它更像一条完整的安全访问链。

一、敏感数据保护,难点从来不是“加密”两个字
做账号系统、云服务接入、本地密钥管理时,大家都会想到“要安全”。
但真进入业务,安全不是一个抽象词,而是几个很具体的问题:
- API 密钥要不要落本地?
- 登录凭据和普通缓存数据能不能放在一起?
- 每次读取敏感内容都要求用户认证,会不会太打断体验?
- 哪些操作必须做指纹 / 人脸 / 锁屏口令验证?
- 认证成功后,访问窗口应该维持多久?
- 访问过哪些关键资产,需不需要留痕?
这些问题如果不在设计阶段想清楚,后面很容易出现两种极端:
一种是为了方便,所有数据都能直接读;
另一种是为了安全,所有操作都强行二次验证,结果把体验做崩。
所以我后来给自己定了一个很实用的拆法:
- User Authentication Kit 负责“你是不是本人”;
- Asset Store Kit 负责“资产放哪儿、怎么存、怎么读”;
- 业务层策略 负责“什么场景必须认证、什么时候允许继续访问”。
二、先分清“普通数据”和“关键资产”
我做这类功能时,不会把所有数据都扔进一个统一存储里。
因为“配置项”“页面缓存”“用户偏好”跟“API 密钥”“第三方登录凭据”“本地加密数据”完全不是一个安全级别。
我通常会这样分:
- 普通数据:Preferences、数据库缓存、页面表单中间态;
- 重要数据:账户标识、业务状态快照、最近操作记录;
- 关键资产:API_KEY、refresh token、加密材料、本地受保护文档索引。
真正需要 Asset Store 保护的,应该是第三层。
这件事如果前期不分,后面越做越乱。因为安全策略一定是跟“数据价值”绑定的,而不是跟“代码写在哪个页面”绑定的。
三、认证入口别写散,敏感操作前做统一校验
最怕的一种写法,是每个按钮里自己去判断要不要认证。
这种写法短期很快,长期会很难维护。你今天有“查看 API 密钥”,明天又有“导出本地凭据”,后天还有“删除关键资产”。如果每个操作都自己判断,认证逻辑马上到处开花。
我更建议把“敏感操作前认证”做成一层统一服务。
例如下面这段代码,核心不是 API 写法,而是把认证动作从页面按钮里抽出来:
import userAuth from '@ohos.userIAM.userAuth';
export class AuthService {
async authenticateForSensitiveAction(): Promise<boolean> {
try {
const result = await userAuth.getUserAuthInstance().auth({
challenge: new Uint8Array([1, 2, 3, 4]),
authType: [
userAuth.UserAuthType.FINGERPRINT,
userAuth.UserAuthType.FACE,
userAuth.UserAuthType.PIN
],
authTrustLevel: userAuth.AuthTrustLevel.ATL2
});
return result.result === 0;
} catch (err) {
console.error(`authenticate failed: ${JSON.stringify(err)}`);
return false;
}
}
}
这个思路的好处很明显:
- 哪些认证方式可用,由认证服务统一决策;
- 页面只关心“是否通过”;
- 后续切换认证策略,不用满工程改按钮事件。
四、Asset Store 不只是“存一下”,更重要的是访问边界
很多人会把安全存储理解成“把字符串存进去,再取出来”。
这理解不算错,但太浅了。
在工程里,Asset Store 更大的价值是:给关键资产一个独立、受控、可组合认证策略的存取空间。
像 API 密钥、登录凭据这类信息,不该和普通配置一起暴露在宽松访问链路里。
我一般会把资产层再封成单独服务,例如:
import asset from '@ohos.security.asset';
export class AssetService {
async saveApiKey(value: string) {
const attrs = new Map<string, Uint8Array | number>();
attrs.set(asset.Tag.ALIAS, new TextEncoder().encode('api_key'));
attrs.set(asset.Tag.SECRET, new TextEncoder().encode(value));
attrs.set(asset.Tag.ACCESSIBILITY, asset.Accessibility.DEVICE_POWERED_ON);
await asset.add(attrs);
}
async queryApiKey(): Promise<string> {
const query = new Map<string, Uint8Array>();
query.set(asset.Tag.ALIAS, new TextEncoder().encode('api_key'));
const result = await asset.query(query);
return new TextDecoder().decode(result.secret as Uint8Array);
}
}
这里真正关键的是:资产访问不直接暴露给页面,而是放在统一服务层,由认证服务作为前置门禁。
也就是说,读取关键资产之前,应该先问一句:当前操作有没有通过身份验证?

这张 DevEco 图很适合拿来讲结构。左边目录把 AuthService、AssetService、页面组件分开,中间代码能看到认证与资产操作的衔接,右边模拟器则把“身份验证后访问资产”的实际交互直观展现出来。底部日志又把认证开始、认证成功、资产读取成功串起来了。
五、界面设计要把“认证状态”和“资产状态”分开展示
如果页面只给一个“安全中心”大按钮,读者其实很难理解整个链路。
我更喜欢把信息拆开:
- 可用认证方式:指纹 / 人脸 / 锁屏口令;
- 敏感操作说明:为什么要认证;
- 关键资产列表:有哪些内容受保护;
- 认证后状态:当前是否已授权访问;
- 安全记录:最近的访问结果。

这张运行图就是一个比较典型的“认证前”状态:
- 页面先告诉你支持哪些系统级认证方式;
- 再告诉你为什么这次操作需要身份验证;
- 下面列出关键资产,但默认不直接把内容全部暴露出来;
- 只有用户明确发起“验证身份并访问”,才会进入下一步。
这种交互的好处是克制。它不会一上来就把敏感数据摊给用户,也不会让安全能力藏得太深。
六、真正好用的,不是认证成功,而是“认证成功后能形成一次完整授权会话”
很多实现到“认证成功”就结束了,但真实业务里还差一段。
用户认证成功之后,系统应该让这次访问形成一个清晰的授权结果:
- 本次认证方式是什么;
- 授权开始时间是什么;
- 当前允许访问哪些资产;
- 资产存储状态是否正常;
- 最近有哪些关键操作已经发生。

这张图就比较像“认证后”的结果页:
- 顶部直接告诉你身份认证成功;
- 中间把 Asset Store 的状态、关键资产数量、认证保护状态列清楚;
- 下方资产列表展示当前可访问项;
- 最近安全记录把“读了什么、什么时候读的、结果如何”交代明白。
这样做的好处是,安全能力不再是一个黑盒。用户完成认证后,既知道自己做了什么,也知道系统开放了什么范围。
七、这类能力真正值钱的地方,是把安全体验做成“工程结构”
我自己的感受是,HarmonyOS 这类系统能力真正好用的地方,不只是 API 本身,而是它让你有机会把一套安全访问流程收成可维护的结构。
我现在会默认坚持几条原则:
- 关键资产和普通数据一定分层;
- 敏感操作前统一经过认证服务;
- 认证方式尽量复用系统能力,不自己造轮子;
- 页面展示“认证状态”和“资产状态”时要分层表达;
- 关键操作要留记录,方便排查与审计;
- 安全链路要兼顾体验,不能把用户每一步都挡住。
说到底,这篇文章不是想把安全讲得多玄,而是想强调一个非常工程化的结论:
安全不是某一个 API,也不是某一个页面,它是一条从身份确认、授权控制到资产访问与记录留痕的完整链路。
如果这条链路做顺了,你的应用不只是“更安全”,而是会明显更可维护。后面无论接密钥管理、账号安全、离线加密数据,结构都能接得住。
更多推荐




所有评论(0)