Explore Verifiable Health Records
Health & Fitness 进阶 20m

探索可验证健康记录

Explore Verifiable Health Records

2021年6月9日

在 Apple 官方观看视频

一句话判断

可验证健康记录(Verifiable Health Records)是苹果在疫情背景下推出的数字健康凭证方案 —— 基于 SMART Health Cards 标准,用 JWT + QR Code 实现疫苗接种证明的可验证传递,但它的野心远不止疫情用途。

这场 Session 讲了什么

Session 介绍了 iOS 15 中 Health app 的新能力:接收和存储可验证的健康记录。用户可以通过扫描 QR Code 或点击链接,将医疗机构签发的健康凭证(如疫苗接种记录、检测结果)添加到 Health app 中。这些记录经过加密签名,任何人都可以验证其真实性。

技术实现基于 SMART Health Cards 规范(由 VCI 组织制定)。数据格式是压缩后的 JSON Web Token(JWS),包含健康信息的 payload + 医疗机构的数字签名。验证方只需获取医疗机构的公钥即可验证签名。

Session 还讲解了开发者如何在自己的 app 中集成:读取 Health app 中的可验证记录、展示 QR Code 供第三方扫描、以及如何构建签发管道(如果你的组织是医疗机构)。

值得深挖的点

SMART Health Cards 的签名验证链路。签发方(如医院)用自己的私钥对健康数据签名,公钥发布到 VCI 的公钥目录(Key Directory)。验证时,app 从 Key Directory 获取公钥,验证 JWS 签名的合法性。整个链路和 HTTPS 证书验证的逻辑类似,但健康数据的 payload 是明文 JSON(只做了压缩,不做加密),所以隐私保护依赖于用户主动选择展示。

HealthKit 中的数据模型。可验证健康记录在 HealthKit 中通过 HKVerifiableClinicalRecord 类型存储。它的 recordType 字段标识记录类别(如 immunizationlab-test),sourceURL 指向原始 JWS 数据,itemNames 包含记录中的关键字段名。app 通过 HKSampleQuery 查询这些记录,和查询其他 HealthKit 数据的方式一致。

代码片段

查询 HealthKit 中的可验证健康记录

import HealthKit

func queryVerifiableRecords() {
    let healthStore = HKHealthStore()
    // 定义可验证临床记录类型
    guard let recordType = HKObjectType.clinicalType(
        forIdentifier: .verifiableClinicalRecord
    ) else { return }

    // 请求读取权限
    healthStore.requestAuthorization(toShare: nil, read: [recordType]) { success, error in
        guard success else { return }
        // 查询所有可验证记录
        let query = HKSampleQuery(
            sampleType: recordType,
            predicate: nil,
            limit: HKObjectQueryNoLimit,
            sortDescriptors: [NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)]
        ) { _, samples, error in
            guard let records = samples as? [HKVerifiableClinicalRecord] else { return }
            for record in records {
                print("记录类型: \(record.recordType)")
                print("签发方: \(record.issuerIdentifier)")
                print("项目: \(record.itemNames)")
            }
        }
        healthStore.execute(query)
    }
}

解析 JWS 中的健康数据

import Foundation

func parseJWSHealthCard(_ jwsString: String) {
    // JWS 格式: header.payload.signature(用 . 分隔)
    let parts = jwsString.components(separatedBy: ".")
    guard parts.count == 3 else { return }

    // 解码 payload(Base64URL 编码)
    let payloadData = Data(base64Encoded: parts[1].base64URLDecoded) ?? Data()
    let json = try? JSONSerialization.jsonObject(with: payloadData) as? [String: Any]

    // 提取健康信息
    if let vc = json?["vc"] as? [String: Any],
       let credentialSubject = vc["credentialSubject"] as? [String: Any],
       let fhirBundle = credentialSubject["fhirBundle"] as? [String: Any] {
        print("FHIR 健康数据: \(fhirBundle)")
    }
}

展示可验证记录的 QR Code

import UIKit

func generateQRCode(from jwsString: String) -> UIImage {
    // SMART Health Cards 使用压缩的 QR Code
    // 多个 QR Code 用于较大的数据
    let data = jwsString.data(using: .ascii)
    guard let filter = CIFilter(name: "CIQRCodeGenerator") else {
        return UIImage()
    }
    filter.setValue(data, forKey: "inputMessage")
    filter.setValue("M", forKey: "inputCorrectionLevel")  // 中等纠错级别
    let transform = CGAffineTransform(scaleX: 10, y: 10)
    if let output = filter.outputImage?.transformed(by: transform) {
        return UIImage(ciImage: output)
    }
    return UIImage()
}

最佳实践

  1. 如果你的 app 需要验证用户的健康凭证,直接用 HealthKit API 读取,不要自己解析 JWS。HealthKit 已经帮你做了签名验证,你拿到的是已经验证过的数据。
  2. QR Code 展示时考虑分片。SMART Health Cards 规范支持将大 JWS 分割成多个 QR Code。如果数据超过单个 QR Code 的容量限制,使用分片模式。
  3. 医疗机构接入时优先使用现有的 FHIR 标准。苹果的健康记录基于 FHIR(Fast Healthcare Interoperability Resources)格式,和主流电子健康记录系统兼容。

还有什么值得关注

  • iOS 15 的 Health app 可以直接添加和管理可验证健康记录,用户界面不需要开发者实现。
  • Wallet app 也支持添加 SMART Health Cards,可以作为快速展示入口。
  • 这个框架的设计是通用的,不限于疫苗接种,未来可以扩展到处方、检查报告等更多医疗凭证。
WWDC 2021