Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
如何使用 SMART on FHIR 实现患者同意管理
教程:逐步使用 SMART on FHIR 和 OAuth 2.1 及 PKCE——发现、应用注册、同意屏幕、令牌交换、范围强制执行、刷新轮换和撤销——以及 Anpheros 的实现。
SMART on FHIR 是应用程序获取个人访问其 FHIR 记录权限的标准方式:使用 OAuth 2.1 和 PKCE 进行授权,使用作用域精确说明可读写的内容,以及使用发现文档告知应用程序去哪里。 本教程将分步演示整个流程在 Anpheros 上的运行情况,包括 curl:发现、注册应用程序、将用户引导至同意屏幕、交换代码、在授予的作用域内调用 API、刷新以及用户撤销访问时发生的情况。Anpheros 是 SMART on FHIR 后端:它托管授权服务器、同意屏幕和 FHIR R4 服务器,因此您无需编写自己的登录或同意 UI。
为什么使用同意书而不是 API 密钥
API 密钥只能访问您的项目创建的患者数据。个人的现有记录(他们自己的数据,由其他应用程序、诊所和实验室收集)由他们自己决定是否共享。使用 SMART on FHIR:
- 用户能以他们自己的语言看到,哪个应用程序在请求什么,它想读取或写入什么,目的是什么,以及持续多久;
- 您的应用程序只能获取那些资源类型和操作,并且仅限于该一个记录;
- 每次访问都会被记录并对用户可见,用户可以随时撤销访问权限;
- 授权也会以 FHIR
Consent资源的形式存储。
其背后的模型在 带有患者同意书的医疗保健 API 和 同意书和访问模型 中有详细描述。
步骤 1:发现
curl https://platform.anpheros.com/fhir/R4/.well-known/smart-configuration
响应列出了端点以及服务器支持的内容(节选):
{"issuer": "https://platform.anpheros.com",
"authorization_endpoint": "https://platform.anpheros.com/oauth/authorize",
"token_endpoint": "https://platform.anpheros.com/oauth/token",
"revocation_endpoint": "https://platform.anpheros.com/oauth/revoke",
"code_challenge_methods_supported": ["S256"],
"scopes_supported": ["patient/*.rs", "patient/Patient.r", "patient/Observation.rs", "patient/Observation.rs?category=laboratory",
"patient/Observation.rs?category=vital-signs", "patient/Observation.c", "patient/Condition.rs",
"patient/MedicationStatement.rs", "patient/DocumentReference.rs", "patient/AllergyIntolerance.rs",
"offline_access", "launch/patient", "openid", "fhirUser"],
"capabilities": ["launch-standalone", "client-public", "client-confidential-symmetric", "permission-patient",
"permission-offline", "context-standalone-patient", "sso-openid-connect"]}
SMART 客户端库会读取此文档,无需其他配置。
步骤 2:注册您的应用程序
在 仪表板 中,打开您的项目并添加一个应用程序及其重定向 URI。或者通过 Admin API:
curl -X POST https://platform.anpheros.com/admin/projects/$PROJECT/applications \
-H "Authorization: Bearer $FIREBASE_ID_TOKEN" -H "Content-Type: application/json" -d '{
"name": "CardioAI", "client_type": "public",
"redirect_uris": ["https://cardio.example/callback"],
"purpose": "cardiology follow-up", "privacy_url": "https://cardio.example/privacy"
}'
{"id": "app_…", "name": "CardioAI", "client_type": "public", "client_id": "client_Hg6CknNkYlMgN190", "client_secret": null,
"redirect_uris": ["https://cardio.example/callback"], "purpose": "cardiology follow-up", "status": "active", …}
对于无法保管密钥并依赖 PKCE 的移动和浏览器应用,请使用 public。对于服务器,请使用 confidential;其 client_secret 仅显示一次。名称、目的和隐私链接是用户在同意屏幕上看到的内容。
步骤 3:将用户引导至同意屏幕
创建一对 PKCE。验证器保留在您这里;只有其哈希值会被传输:
VERIFIER=$(openssl rand -base64 64 | tr -d '=+/\n' | cut -c1-64)
CHALLENGE=$(printf %s "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
然后,在用户的浏览器中打开此地址(为方便阅读添加了换行符):
https://platform.anpheros.com/oauth/authorize?response_type=code
&client_id=client_Hg6CknNkYlMgN190
&redirect_uri=https://cardio.example/callback
&scope=openid fhirUser patient/Observation.rs?category=laboratory patient/Condition.rs offline_access
&state=8c1e… ← a random value you check on return
&code_challenge=$CHALLENGE&code_challenge_method=S256
&purpose=treatment&lang=en
请求您最需要的信息。此应用程序读取实验室结果和诊断信息,仅此而已。offline_access 会提供一个刷新令牌,因此用户无需每 30 分钟重新批准一次。
用户登录 Anpheros,以通俗易懂的语言阅读请求,选择要共享的记录(他们自己的、他们照顾的家庭成员的,或您的应用程序为他们创建的记录)以及访问的持续时间,然后允许或拒绝。他们将返回到您的重定向 URI:
https://cardio.example/callback?code=…&state=8c1e…
在代码之前,请检查 state 是否与您之前发送的值匹配。
第 4 步:用代码交换令牌
curl -X POST https://platform.anpheros.com/oauth/token \
-d grant_type=authorization_code -d client_id=client_Hg6CknNkYlMgN190 \
-d code=$CODE -d code_verifier=$VERIFIER -d redirect_uri=https://cardio.example/callback
{"access_token": "at_…", "token_type": "Bearer", "expires_in": 1800,
"scope": "patient/Observation.rs?category=laboratory patient/Condition.rs openid fhirUser offline_access",
"patient": "82bfd321-6a4d-4aea-943a-a62f4d81d419", "grant_id": "grant_…",
"id_token": "eyJ…", "refresh_token": "rt_…"}
scope列出了已授予的内容。请将其与令牌一起保留,并仅显示其涵盖的功能。patient是您应用程序的记录 ID。它是成对的:另一个应用程序在不同 ID 下看到同一个人。id_token是一个 OpenID Connect 令牌,其fhirUserclaim 命名患者资源。- 该代码只能使用一次,并且只能与匹配的
code_verifier一起使用。
步骤 5:在作用域内调用 API
curl "https://platform.anpheros.com/fhir/R4/Observation?patient=$PATIENT&category=laboratory" -H "Authorization: Bearer $ACCESS_TOKEN"
实验室结果照常返回。请求超出授权范围的内容,例如药物:
curl "https://platform.anpheros.com/fhir/R4/MedicationStatement?patient=$PATIENT" -H "Authorization: Bearer $ACCESS_TOKEN"
{"resourceType": "OperationOutcome", "issue": [{"severity": "error", "code": "forbidden",
"diagnostics": "The consent behind this token does not allow 's' on MedicationStatement."}]}
这是一个403。超出授权范围的搜索也会被过滤:使用Observation.rs?category=laboratory,搜索所有观察结果只会返回实验室相关的。对于此令牌,任何其他患者都不存在(404)。REST 视图(/v1)和上下文 API 应用相同的范围。
步骤 6:刷新
访问令牌有效期为 30 分钟。刷新令牌有效期为 30 天,并在每次使用时轮换:
curl -X POST https://platform.anpheros.com/oauth/token \
-d grant_type=refresh_token -d client_id=client_Hg6CknNkYlMgN190 -d refresh_token=$REFRESH_TOKEN
您将获得一个新的访问令牌和一个新的刷新令牌。请立即存储新的令牌。重复使用旧的刷新令牌将被视为盗用:它将以 400 失败并撤销整个授权。
步骤 7:撤销
用户可以随时在 Anpheros 中撤销您的访问权限,您也可以自行撤销,例如当用户在您的应用中断开连接时:
curl -X POST https://platform.anpheros.com/oauth/revoke -d token=$REFRESH_TOKEN -d client_id=client_Hg6CknNkYlMgN190
从那时起,使用该授权的所有调用都将返回 401。通过向用户显示连接已结束并提供重新连接的选项来处理此情况。订阅 consent.revoked webhook 可以在不等待调用失败的情况下获知此信息。
使用 SDK
TypeScript 和 Dart SDK 会为您处理步骤 3 到 6:OAuthFlow.authorizeUrl 使用生成的 PKCE 对,exchange 在回调时,以及自动刷新和轮换。完整示例:如何使用 FHIR 后端构建 AI 医疗保健应用 (TypeScript) 和 如何使用 Flutter 构建医疗保健应用 (Dart)。
Anpheros 的实现
| SMART 的部分 | Anpheros 中的实现 |
|---|---|
| Discovery | /.well-known/smart-configuration on the FHIR base, with the endpoints, scopes and PKCE methods supported |
| Launch | standalone launch (应用程序启动,然后请求访问);不支持从临床系统内部启动的 EHR launch |
| Authorisation | OAuth 2.1 with PKCE required, authorisation code flow |
| Scopes | SMART v2 patient scopes, patient/<Resource>.<cruds> with category filters, plus openid and fhirUser |
| Identity | an OpenID Connect id_token naming the patient as a FHIR resource |
| Consent | a hosted consent screen in the patient's language, with the duration chosen by the patient, mirrored as a FHIR Consent |
| Tokens | 30-minute access tokens, rotating 30-day refresh tokens bound to the consent, revocation |
| Conformance | the capability statement declares the SMART security service; the "Standalone Launch" group of the Inferno SMART App Launch STU2 test kit passes 22 of 22 tests (run of 28 September 2026); the other Inferno groups and test kits have not been run |
Writing works the same way: write scopes (patient/Observation.c, .u, .d) let your application create, update or delete within the record. Everything written carries your application as the author, retries with an idempotency key never duplicate a measurement, and deletions are soft and keep history (Medical data API).
尚不支持的功能
- EHR 启动(从医院系统内部使用启动上下文打开的应用程序)。
system/范围的后端服务;组织使用 API 密钥代替。- 批量数据导出(
$export);支持按患者导出($everything)。
这些功能与其余功能一起列在 版本控制和弃用 中,能力声明始终是权威来源。
常见问题解答
什么是 SMART on FHIR?
SMART on FHIR 是一个开放标准,基于 OAuth 2.0/2.1 和 OpenID Connect 构建,它定义了应用程序如何请求访问 FHIR 记录,哪些范围描述了该访问,以及服务器如何宣传其端点。任何支持 SMART 的客户端库都可以使用任何支持 SMART 的服务器。
我需要 PKCE 吗?
是的。Anpheros 要求对所有授权码流程都使用 PKCE 和 S256,无论是公共客户端还是机密客户端。这可以防止截获的授权码被其他人使用。
如果用户拒绝怎么办?
用户将返回到您的重定向 URI,并附带 error=access_denied 和您的 state,但没有代码。请解释该功能的需求,并让他们重试;在授权之外的调用始终会返回 403。
家长可以为孩子提供同意吗?
可以。在同意屏幕上,用户可以选择他们关心的记录,例如孩子的记录,前提是该记录已链接到他们的账户。授权仅适用于该记录。
相关资源
- 身份验证和 OAuth:API 密钥、令牌和生命周期详解
- 带有患者同意的医疗保健 API:同意如何改变您的应用程序设计
- 同意和访问模型
- FHIR 平台
- 构建医疗保健应用程序
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card