【共创稿事节】HarmonyOS 7 数字身份 DID 实战:TEE 颁发、本人同意、最小化出示

本文基于 HarmonyOS 7(API 26)官方《DID数字身份》开发指导与官方新能力一览整理。文中接口名称、权限名与版本号均标注官方出处;示例代码以官方开发步骤为骨架改写,未做真机实测,不编造任何实测数据。数字身份为 HarmonyOS 7 新能力,需升级至 HarmonyOS 7 并以实际支持机型为准。


引子:出示证件照这件事,我们交出去了多少多余信息

V哥先讲一个所有人都干过的事:注册某个服务,被要求"上传身份证照片"。照片拍完传上去,你交出去的是什么?姓名、性别、民族、出生日期、住址、身份证号、签发机关、有效期------全部。而那个业务真正要验证的,可能只有一句话:"这个人是不是成年人。"

一张证件照,交出去一百个字段,用上一个。多出来的九十九个去哪了?存在对方服务器里,存多久、谁能看、会不会被爬,你一概不知。V哥不是吓唬人,这是过去几十年"复印件思维"的通病:验证身份的唯一办法,就是把证件本身交出去。

HarmonyOS 7(API 26)给这个问题上了一个系统级解法------分布式数字身份 DID (Decentralized Identifier,去中心化身份)。官方新能力一览的原文是这么说的(HarmonyOS 7 新能力一览):

系统级的数字身份 DID 框架,通过 TEE 存储颁发用户的数字身份,使用时经本人同意后按需出示,证明身份且最小化证件隐私暴露。

V哥把这句话拆成三个词:TEE 颁发、本人同意、最小化出示 。这也是本文标题的由来,更是这一期想讲透的主线:数字身份的要害不是"把证件数字化",而是最小化暴露------凭证存在 TEE 里,用的时候经本人同意、按需出示,应用自始至终碰不到原始证件数据。


一、先想明白:DID 到底换了什么

传统方式和 DID 方式的差别,V哥画一张链路图就清楚了:

对应到官方能力,HarmonyOS 7 在 Online Authentication Kit(在线认证服务) 里新增了数字身份特性(从 API 版本 26.0.0 开始,官方开发指导),提供四块能力:

能力 官方描述关键词 对开发者的意义
DID 密钥创建及使用 创建及使用与用户 DID 关联的密钥 密钥在 TEE 里生成,应用拿不到私钥
DID 导入、查询及删除 导入 DID 标识、DID 文档等信息到设备 身份标识由用户设备持有,不在应用手里
VC 导入、查询及删除 可验证凭证(Verifiable Credentials)导入设备 TEE 环境安全存储 凭证存 TEE,应用只能拿到概要信息
VP 出示 获取用户同意后,在 TEE 中将需披露的属性组装成 VP(Verifiable Presentation)返回 出示这一步过本人同意 + 部分披露

注意官方那句"在 TEE 中将 VC 中需要披露的属性组装成 VP"------这句话就是"复印件思维"的终结者。传统流程里应用拿到的是完整证件;DID 流程里应用拿到的是系统在 TEE 里按你声明的字段范围裁剪、签名后的出示声明,多一个字段都出不来。

V哥在这里给出本文的自创观点:DID 的真正革命不是加密,而是"验证方权限的降维"。过去验证方默认有权查看证件全本,DID 之后验证方只拥有"提问权"------你问"是否成年",系统答"是",至于生日是哪天,从头到尾不经过你。把"查看"降级成"问答",隐私问题才从根上解决,加密只是给这套问答上了把锁。

还有一个架构认知先立住:这套体系是端云协同 的,不是端侧单机游戏。移动端负责 TEE 密钥、凭证存储和出示;你的应用还得有一个符合 W3C DID 协议的服务器,负责公钥上链、获取 DID 文档、向发行方拿凭证。官方原话:"应用部署符合 DID 协议的服务器之后,结合移动端的数字身份能力,可实现跨平台互通互认的数字身份业务场景。"


二、准入门槛:三条硬约束,一条都不能少

写代码之前先对表,官方"约束与限制"给了三条(官方开发指导):

① 服务器门槛。 应用已部署符合 DID 标准协议的服务器。这是最大的工程量所在------端侧 API 反而不难,难在云侧要按 W3C DID 协议把 DID 文档、凭证颁发、VP 核验这套东西建起来。

② 设备门槛。 设备需支持生物特征(指纹/3D人脸),且达到 ATL4 级别的认证可信等级。官方给的查询方式:

typescript 复制代码
import { BusinessError } from '@kit.BasicServicesKit';
import { userAuth } from '@kit.UserAuthenticationKit';

// 查询设备人脸识别是否达到 ATL4 认证可信等级(官方示例)
try {
  userAuth.getAvailableStatus(userAuth.UserAuthType.FACE, userAuth.AuthTrustLevel.ATL4);
  console.info('current auth trust level is supported');
} catch (error) {
  const err: BusinessError = error as BusinessError;
  console.error(`current auth trust level is not supported. Code is ${err?.code}, message: ${err?.message}`);
}

V哥的提醒:这个查询要放进运行时降级逻辑,不能只当启动自检。ATL4 不达标就别拉起 DID 流程,退回传统验证方式,别让用户面对一个必挂的按钮。

③ 权限门槛。 需要申请受限权限 ohos.permission.ACCESS_FIDO2_ONLINEAUTH(官方开发准备章节)。受限权限不是声明了就有,要按申请受限权限流程提交申请,具体获批条件以官方审核为准。

另外官方还有一条隐私红线:数字身份服务会将凭证信息、匿名化的指纹 ID 和面容 ID 等个人信息返回至应用,应用将个人信息上云前,需要向用户明示并且取得同意。这句要写进你的隐私设计里,不是免责声明,是硬要求。


三、动手第一步:在 TEE 里生成 DID 密钥

官方把业务分成三段流程:启用数字身份 → 颁发数字凭证 → 出示数字凭证。V哥用"给员工发一张数字化工作证"当例子串起来。

启用数字身份的官方流程是:应用云侧下发密钥别名等参数 → 构造 GenerateKeyRequest 调用 generateKey 生成 DID 密钥 → 拿到公钥、证书链 → 公钥上报云侧完成上链等操作并获取 DID 文档 → 调用 importDid 导入设备。核心代码(以官方开发步骤为骨架):

typescript 复制代码
import { did } from '@kit.OnlineAuthenticationKit';
import { buffer } from '@kit.ArkTS';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

// 第一步:在 TEE 里生成 DID 密钥
async function generateDidKey(context: common.UIAbilityContext): Promise<void> {
  // keyAlias 由应用云侧下发,别在前端硬编码
  const generateKeyRequest: did.GenerateKeyRequest = {
    keyAlias: 'vgeWorkCardKey',
    keyConfig: {
      algorithm: did.KeyAlgo.SM2,                    // 国密 SM2
      purposeList: [did.KeyPurpose.SIGN, did.KeyPurpose.VERIFY]
    },
    authenticatorConfig: {
      authTypeList: [did.AuthType.UVM_FINGERPRINT],  // 绑定生物认证
      requireBioId: true
    }
  };
  try {
    const response: did.GenerateKeyResponse =
      await did.generateKey(context, generateKeyRequest);
    // V哥提醒:公钥和证书链要上报应用云侧,由云侧完成公钥上链、换取 DID 文档
    // 私钥留在 TEE 里,应用侧从头到尾摸不到
    console.info('did key generated, certChain:', response.certChain);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`generateKey failed. Code: ${err.code}, message: ${err.message}`);
  }
}

// 第二步:把云侧换来的 DID 文档导入设备
async function importDidDoc(context: common.UIAbilityContext): Promise<void> {
  const importDidRequest: did.ImportDidRequest = {
    isUpdate: false,
    did: 'did:example:123456',                       // 云侧生成并返回的 DID 标识
    didKeyList: [{ keyAlias: 'vgeWorkCardKey', keyId: 'keyId123' }],
    didDoc: JSON.stringify({
      '@context': 'https://www.w3.org/ns/did/v1',
      id: 'did:example:123456'
      // ... DID 文档其余内容由云侧下发
    })
  };
  try {
    await did.importDid(context, importDidRequest);
    console.info('did imported');
  } catch (error) {
    const err = error as BusinessError;
    console.error(`importDid failed. Code: ${err.code}, message: ${err.message}`);
  }
}

两个细节值得停一下。其一,authenticatorConfig 里绑定生物认证------这一步决定了后面出示凭证时"本人同意"不是一句空话,而是拿指纹/人脸说了算。其二,did.sign 接口可以在已导入的 DID 密钥上做数据签名(官方能力之一),用户授权、数据签署都走它,私钥同样不出 TEE。


四、颁发:把 VC 灌进 TEE

启用身份后,应用从发行方获取可验证凭证(比如工作证凭证),通过 importDigitalCredential 导入设备,DID 服务验证凭证格式并在 TEE 中安全存储

typescript 复制代码
async function importCredential(context: common.UIAbilityContext): Promise<void> {
  const request: did.ImportDigitalCredentialRequest = {
    did: 'did:example:123456',
    credentialType: did.CredentialType.VC,
    isUpdate: false,
    // credentialData 为发行方下发的 VC 内容,需符合官方规定的 VC 格式
    credentialData: buildVcFromIssuer(),
    // 显示配置:决定用户在系统界面里看到什么
    displayConfig: {
      credentialDisplayName: '工作证',
      issuerDisplayName: 'V哥科技公司',
      propertyDisplayName: '姓名'
    },
    securityConfig: {
      authConfig: { requireAuth: true }   // 后续使用需生物认证
    }
  };
  try {
    const response = await did.importDigitalCredential(context, request);
    // V哥提醒:应用侧只拿得到凭证概要(credentialSummary),
    // VC 本体存在 TEE 里------这就是"应用不碰原始证件数据"的落点
    console.info('credential imported, summary:', response.credentialSummary);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`importDigitalCredential failed. Code: ${err.code}, message: ${err.message}`);
  }
}

这里有一个官方明说的格式硬约束:数字身份服务仅支持解析两种格式的 VC (类型均为选择性披露凭证,签名类型分别为 SM3WithSM2SM2Signature2024,并涉及默克尔根计算方式的选择)。多传不可识别的字段不会报错,但不会被解析。V哥的建议:VC 组装放在云侧发行方服务里做,格式对表官方开发指导里的两个样例,端侧只做透传------端侧写 JSON 组装逻辑,出了格式问题你连报错都难定位。


五、出示:本人同意 + 最小化披露,整条链的题眼

前面都是铺垫,这一步才是 DID 的灵魂。当应用作为验证方需要请求用户凭证时,官方流程是:应用云侧下发请求参数 → 构造 GetDigitalCredentialRequest 调用 getDigitalCredential用户确认出示的凭证及披露的属性字段后,数字身份服务将 VP 出示到验证方应用:

typescript 复制代码
async function presentCredential(context: common.UIAbilityContext): Promise<void> {
  const request: did.GetDigitalCredentialRequest = {
    credentialType: did.CredentialType.VP,
    // 展示给用户看的验证方信息与用途------本人同意的前提是知道"给谁看、干什么用"
    displayConfig: {
      verifierDisplayName: '访客系统',
      purpose: '访客身份核验'
    },
    holderConfigList: [{
      holderDid: 'did:example:123456',
      holderDidKeyId: 'keyId123'
    }],
    credentialFilterList: [{
      credentialId: 'credential123',
      issuerDid: 'did:example:issuer'
    }]
  };
  try {
    const response = await did.getDigitalCredential(context, request);
    // 系统在 TEE 中完成:生物认证授权 -> 按披露范围裁剪属性 -> 组装并签名 VP
    // V哥拿到的只有 VP,裁掉了哪些字段,链路上无人知晓
    handlePresentation(response);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`getDigitalCredential failed. Code: ${err.code}, message: ${err.message}`);
  }
}

官方对这一步的描述有三个关键词,V哥逐个标注分量:

  • 获取用户同意:不是应用调个弹窗意思一下,是数字身份服务层面的确认流程,用户能看到"出示什么、给谁看、披露哪些字段"。
  • 生物认证授权出示:拿指纹/人脸做授权,出示动作本身和"本人"强绑定。
  • 凭证的部分披露:VP 里只含被披露的属性。VP 同样只支持官方规定的两种格式,验证方解析时要对表。

V哥再给一个接入思路上的判断:这套能力最适合的接入位,是你业务里"本来就要收证件"的环节------酒店入住核验、访客登记、入职背书、年龄敏感服务。凡是过去靠"上传证件照"过审的流程,都是 DID 的候选改造点。反过来,纯粹为了炫技把 DID 套在无关环节上,只会在受限权限申请和云侧协议部署上白费功夫。


六、接入自检清单

V哥把整条链路压成六项,接 DID 前逐项对表:

# 检查项 依据
1 HarmonyOS 7(API 26)+ 实际支持 ATL4 的机型? 约束与限制
2 受限权限 ohos.permission.ACCESS_FIDO2_ONLINEAUTH 已申请? 开发准备
3 应用云侧已部署符合 W3C DID 协议的服务? 约束与限制
4 VC/VP 组装与解析对表官方两种格式? 开发步骤
5 出示环节的验证方名称与用途 displayConfig 写清楚? 出示流程
6 个人信息上云前已明示并取得用户同意? 约束与限制

最后说句实话:DID 不是一个人能落地的能力,它是端侧 TEE、云侧协议、发行方、验证方四方协奏。也正因为门槛在这里,它筛掉了一批只想"传张照片"的旧流程------能按 DID 标准把身份验证重构掉的业务,才有资格说自己在做隐私合规


参考与出处

本文涉及的机制、流程、接口与约束,均来自以下华为开发者联盟官方文档:


最后一句:复印件思维的时代,证明自己是谁的办法是把证件全本交出去;DID 时代,你只需要让 TEE 替你说一句"是"------多一个字段都算系统失职,这才是数字身份该有的样子。

相关推荐
贾伟康1 小时前
【HarmonyOS 7新能力|039】冷启网络预建链工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·软件架构·网络优化
星栖与芯11 小时前
LiteOS-M 切换汇编逐行图解(4):中断三件套与 HalTaskSchedule 触发
汇编·stm32·单片机·嵌入式硬件·harmonyos
李游Leo13 小时前
定位功能“偶尔失效“怎么查:HarmonyOS Location Kit 权限、订阅与地理围栏实践
harmonyos
庆登登登17 小时前
nvm 鸿蒙 PC 适配全记录:从 Shell Function 到 HNP 原生交付
华为·harmonyos
不羁的木木17 小时前
给鸿蒙 App 增加用系统应用打开文件的能力 —— open_app_file 的鸿蒙使用指南
flutter·harmonyos
李游Leo18 小时前
HarmonyOS 7 系统能力深度实战 02:用模块化对象开放应用内部能力
harmonyos
HMS Core20 小时前
AI 赋能 Push Kit 场景化消息开发,高效完成鸿蒙应用推送能力接入
harmonyos
花先锋队长1 天前
华为Mate XT2铰链防尘保养指南:如何让三折叠开合长久丝滑如初?
华为·智能手机·harmonyos
马剑威(威哥爱编程)1 天前
【共创稿事节】HarmonyOS 7 图像超分实战:端侧 4 倍高清放大,数据不出设备
华为·harmonyos