探索可验证健康记录
Explore Verifiable Health Records
2021年6月9日
一句话判断
可验证健康记录(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 字段标识记录类别(如 immunization、lab-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()
}
最佳实践
- 如果你的 app 需要验证用户的健康凭证,直接用 HealthKit API 读取,不要自己解析 JWS。HealthKit 已经帮你做了签名验证,你拿到的是已经验证过的数据。
- QR Code 展示时考虑分片。SMART Health Cards 规范支持将大 JWS 分割成多个 QR Code。如果数据超过单个 QR Code 的容量限制,使用分片模式。
- 医疗机构接入时优先使用现有的 FHIR 标准。苹果的健康记录基于 FHIR(Fast Healthcare Interoperability Resources)格式,和主流电子健康记录系统兼容。
还有什么值得关注
- iOS 15 的 Health app 可以直接添加和管理可验证健康记录,用户界面不需要开发者实现。
- Wallet app 也支持添加 SMART Health Cards,可以作为快速展示入口。
- 这个框架的设计是通用的,不限于疫苗接种,未来可以扩展到处方、检查报告等更多医疗凭证。