去中心化标识符(DID)是一种用于可验证的“自我主权”数字身份的新型标识符。DID完全由DID控制者控制,独立于任何中心化注册机构、身份提供者或证书颁发机构。DID解析为DID文档——描述如何使用该特定DID的简单文档。

本文档规定了解析DID和解引用DID URL的算法和指南。

欢迎对本文档提出意见。请直接在 GitHub 上提交问题, 或发送至 public-did-wg@w3.org (订阅, 存档)。

本规范的部分工作由美国国土安全部科学技术局资助,合同号为 HSHQDC-17-C-00019。本规范的内容不一定反映美国政府的立场或政策,也不应推断为官方认可。

本规范的工作也得到了由 Christopher Allen、Shannon Appelcline、Kiara Robles、Brian Weller、Betty Dhamers、Kaliya Young、Kim Hamilton Duffy、Manu Sporny、Drummond Reed、Joe Andrieu 和 Heather Vescent 主持的“重启 Web 信任”社区的支持。

介绍

DID解析是获取给定 DIDDID文档的过程。这是可以对任何DID执行的四个必需操作之一(“读取”;其他操作包括“创建”、“更新”和“停用”)。这些操作的细节因 DID方法而异。 在 DID解析的基础上,DID URL解引用是获取给定 DID URL 的资源的表示的过程。能够执行这些过程的软件和/或硬件称为 DID解析器

本规范定义了 DID解析DID URL解引用过程的通用要求、算法(包括其输入和结果)、架构选项和各种注意事项。

请注意,虽然本规范定义了DID解析的一些基本功能,但与DID的 可验证数据注册表通信所需的实际步骤由适用的 DID方法规范定义。

“解析” DID 和“解引用” DID URL 之间的区别正在被社区深入讨论。例如,参见 此评论

一个 符合规范的DID解析器 是任何实现为软件和/或硬件的算法,它遵守 中的相关规范性声明。

一个 符合规范的DID URL解引用器 是任何实现为软件和/或硬件的算法,它遵守 中的相关规范性声明。

受众

本规范有三个主要受众:符合规范的DID方法的实现者;符合规范的DID解析器的实现者;以及希望使用DID解析器解析DID的系统和服务实现者。目标受众包括但不限于软件架构师、数据建模师、应用程序开发人员、服务开发人员、测试人员、操作人员和用户体验(UX)专家。参与与去中心化身份、可验证凭证和安全存储相关的广泛标准工作的其他人也可能对本规范感兴趣。

术语

DID参数

DID URL 语法支持一种简单的参数格式 (参见 [[DID-CORE]] 中的 查询 部分)。向 DID URL 添加DID参数意味着该参数成为 资源 标识符的一部分。

did:example:123?versionTime=2021-05-10T17:00:00Z
	
did:example:123?service=files&relativeRef=/resume.pdf
	

一些DID参数完全独立于任何特定的 DID方法,并且对所有 DID 的功能相同。其他DID参数并非所有 DID方法 都支持。在支持可选参数的情况下,期望这些参数在支持它们的 DID方法 中统一操作。下表提供了在所有 DID方法 中功能相同的常见DID参数。支持所有 DID参数 是可选的。

参数名称 描述
service 通过服务 ID 从 DID文档 中识别服务。 如果存在,关联的值必须是一个 ASCII 字符串
relativeRef 根据 RFC3986 第 4.2 节 的相对 URI 引用,它标识了 服务端点 上的 资源,该服务端点通过使用 service 参数从 DID文档 中选择。 如果存在,关联的值必须是一个 ASCII 字符串,并且必须使用 RFC3986 第 2.1 节 中指定的百分号编码。
versionId 标识要解析的 DID文档 的特定版本(版本 ID 可以是顺序的、UUID或方法特定的)。 如果存在,关联的值必须是一个 ASCII 字符串
versionTime 标识要解析的 DID文档 的特定版本时间戳。即,在指定的 `versionTime` 之前对 DID 有效的 DID文档 的最新版本。如果存在,关联的值必须是一个 ASCII 字符串,它是有效的 XML 日期时间值,如 W3C XML Schema 定义语言 (XSD) 1.1 第 2 部分:数据类型 [[XMLSCHEMA11-2]] 第 3.3.7 节中所定义。此日期时间值必须规范化为 UTC 00:00:00,并且不包含亚秒级小数精度。 例如:2020-12-20T19:17:47Z
hl DID文档 的资源哈希,用于添加完整性保护,如 [[?HASHLINK]] 中所指定。此参数是非规范性的。 如果存在,关联的值必须是一个 ASCII 字符串

实现者以及 DID方法 规范作者可能会使用此处未列出的其他DID参数。为了最大程度的互操作性,建议DID参数使用DID规范注册机制 [[?DID-SPEC-REGISTRIES]],以避免与具有不同语义的相同DID参数的其他用途发生冲突。

如果存在明确的用例,其中参数需要成为 URL 的一部分以更精确地引用 资源,则可以使用DID参数。如果相同的功能可以通过将输入元数据传递给 DID解析器 来表达,则预计不会使用DID参数。

DID解析DID URL解引用 功能可以通过传递 DID解析器 来影响,这些选项不是 DID URL 的一部分。这与 HTTP 类似,某些参数可以包含在 HTTP URL 中,或者作为 HTTP 头在解引用过程中传递。重要的区别在于,作为 DID URL 一部分的DID参数应该用于指定 正在识别的 资源,而不作为 DID URL 一部分的输入元数据应该用于控制 如何解析或解引用该 资源

DID解析

DID解析 功能通过使用适用的 DID方法 的“读取”操作将 DID 解析为 DID文档,如 方法操作 中所述。所有符合规范的 DID解析器 都实现了以下函数,其抽象形式如下:

resolve(did, resolutionOptions) →
   «DIDResolutionMetadata,DIDDocument,DIDDocumentMetadata »
      

所有符合规范的 DID解析器 必须为至少一种 DID方法 实现 DID解析 功能,并且必须能够返回至少一种符合规范的 表示DID文档

符合规范的 DID解析器 实现不会以任何方式更改此函数的签名。DID解析器 实现可能会将 resolve 函数映射到方法特定的内部函数以执行实际的 DID解析 过程。DID解析器 实现可能会实现并暴露具有不同签名的其他函数,除了此处指定的 resolve 函数。

resolve 函数的输入变量如下:

did
这是要解析的 DID。此输入是必需的,值必须是符合 中定义的 DID
resolutionOptions
一个 元数据结构,包含 中定义的属性。此输入是必需的,但结构可能为空。

此函数返回多个值,并且对这些值如何一起返回没有限制。resolve 的返回值包括 didResolutionMetadatadidDocumentdidDocumentMetadata。这些值描述如下:

didResolutionMetadata
一个 元数据结构,包含与 DID解析 过程结果相关的值,这些值通常在 resolve 函数的调用之间变化,因为它表示解析过程本身的数据。此结构是必需的,并且在解析过程中出现错误时,此结构不能为空。此元数据由 定义。如果解析不成功,此结构必须包含一个描述错误的 error 属性。
didDocument
如果解析成功,这必须是一个 DID文档,它能够以 [[[DID]]] 规范中定义的符合规范的 表示 之一表示。解析的 DID文档 中的 id 值必须与解析的 DID 匹配。如果解析不成功,此值必须为空。
didDocumentMetadata
如果解析成功,这必须是一个 元数据结构。此结构包含 didDocument 属性中包含的 DID文档 的元数据。此元数据通常在 resolve 函数的调用之间不会变化,除非 DID文档 发生变化,因为它表示 DID文档 的元数据。如果解析不成功,此输出必须是一个空的 元数据结构。此规范定义的属性在 中。

DID解析选项

此结构中的可能属性及其可能值在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下常见属性。

accept
调用者首选的 DID文档 的媒体类型。媒体类型必须表示为 ASCII 字符串DID解析器 实现应使用此值来确定返回的 didDocument表示,如果支持并可用此类 表示。此属性是可选的。
expandRelativeUrls
一个布尔标志,指示 DID解析器相对DID URL 扩展为符合 DID URL语法 的绝对DID URL。
versionId
参见 中的定义。
versionTime
参见 中的定义。

DID解析元数据

此结构中的可能属性及其可能值在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下DID解析元数据属性:

contentType
返回的 didDocument 的媒体类型。此属性是可选的。如果存在,此属性的值必须是一个 ASCII 字符串,它是符合规范的 表示 的媒体类型。在这种情况下,resolve 函数的调用者必须使用此值来确定如何解析和处理 didDocument
error
解析过程中的错误代码。当解析过程中出现错误时,此属性是必需的。此属性的值必须是一个单一的关键字 ASCII 字符串。此字段的可能属性值应在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下常见错误值:
invalidDid
提供给 DID解析 函数的 DID 不符合有效语法。(参见 。)
notFound
DID解析器 无法找到此解析请求生成的 DID文档
representationNotSupported
如果通过 accept 输入元数据属性请求的 表示 不受 DID方法 和/或 DID解析器 实现支持,则返回此错误代码。

DID文档元数据

此结构中的可能属性及其可能值应在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下常见属性。

created
DID文档 元数据应包括一个 created 属性,以指示 创建操作 的时间戳。属性的值必须是一个 字符串,格式化为 XML 日期时间,规范化为 UTC 00:00:00,并且不包含亚秒级小数精度。例如:2020-12-20T19:17:47Z
updated
DID文档 元数据应包括一个 updated 属性,以指示解析的文档版本的最后一次 更新操作 的时间戳。属性的值必须遵循与 created 属性相同的格式化规则。如果从未对 DID文档 执行过更新操作,则省略 updated 属性。如果存在 updated 属性,它可以与 created 属性具有相同的值,当两个时间戳之间的差异小于一秒时。
deactivated
如果DID已被 停用DID文档 元数据必须包含此属性,并且布尔值为 true。如果DID未被停用,此属性是可选的,但如果包含,则必须具有布尔值 false
nextUpdate
如果解析的文档版本不是文档的最新版本,DID文档 元数据可以包含一个 nextUpdate 属性,指示下一次 更新操作 的时间戳。属性的值必须遵循与 created 属性相同的格式化规则。
versionId
DID文档 元数据应包含一个 versionId 属性,以指示解析的文档版本的最后一次 更新操作 的版本。属性的值必须是一个 ASCII 字符串
nextVersionId
如果解析的文档版本不是文档的最新版本,DID文档 元数据可以包含一个 nextVersionId 属性,指示下一次 更新操作 的版本。属性的值必须是一个 ASCII 字符串
equivalentId

一个 DID方法 可以定义不同形式的 DID,这些形式在逻辑上是等价的。例如,一个 DID 在注册到 可验证数据注册表 之前可能采用一种形式,而在注册后采用另一种形式。在这种情况下,DID方法 规范可能需要将解析的 DID 的一个或多个逻辑等价的 DID 作为 DID文档 的属性表达出来。这就是 equivalentId 属性的目的。

DID文档 元数据可以包含一个 equivalentId 属性。如果存在,值必须是一个 集合,其中每个项目是一个 字符串,符合 中的规则。关系是每个 equivalentId 值在逻辑上等同于 id 属性值,因此指的是相同的 DID主体。每个 equivalentIdDID值必须由与 id 属性值相同的 DID方法 生成,并且是该 DID方法 的一种形式。(例如,did:example:abc == did:example:ABC

一个符合规范的 DID方法 规范必须保证每个 equivalentId 值在逻辑上等同于 id 属性值。

请求方应保留 idequivalentId 属性的值,以确保与它们包含的任何值的后续交互都被正确处理为逻辑等价(例如,在数据库中保留所有变体,以便与任何一个交互都映射到相同的底层账户)。

equivalentId 是一种比 alsoKnownAs 更强的等价形式,因为等价性必须由治理的 DID方法 保证。equivalentId 表示一个完整的图合并,因为相同的 DID文档 描述了 equivalentId DIDid 属性 DID

如果请求方不保留 idequivalentId 属性的值,并确保与它们包含的任何值的后续交互都被正确处理为逻辑等价,可能会出现负面或意外的问题。强烈建议实现者遵守与此元数据属性相关的指示。

canonicalId

canonicalId 属性与 equivalentId 属性相同,除了:a) 它与单个值而不是集合相关联,b) DID 被定义为包含 DID文档 范围内的 DID主体 的规范 ID。

DID文档 元数据可以包含一个 canonicalId 属性。如果存在,值必须是一个 字符串,符合 中的规则。关系是 canonicalId 值在逻辑上等同于 id 属性值,并且 canonicalId 值由 DID方法 定义为包含 DID文档 范围内的 DID主体 的规范 ID。一个 canonicalId 值必须由与 id 属性值相同的 DID方法 生成,并且是该 DID方法 的一种形式。(例如,did:example:abc == did:example:ABC)。

一个符合规范的 DID方法 规范必须保证 canonicalId 值在逻辑上等同于 id 属性值。

请求方应使用 canonicalId 值作为其 DID主体 的主要 ID 值,并将所有其他等价值视为次要别名(例如,更新其系统中的相应主要引用以反映新的规范 ID 指示)。

canonicalId 是与 equivalentId 相同的等价性声明,除了它被约束为单个值,该值被定义为包含 DID文档 范围内的 DID主体 的规范。与 equivalentId 一样,canonicalId 表示一个完整的图合并,因为相同的 DID文档 描述了 canonicalIdDID和 id 属性 DID

如果解析方不使用 canonicalId 值作为其 DID主体 的主要 ID 值,并将所有其他等价值视为次要别名,可能会出现与用户体验相关的负面或意外问题。强烈建议实现者遵守与此元数据属性相关的指示。

算法

以下 DID解析 算法必须由符合规范的 DID解析器 实现。

  1. 验证 输入 DID 是否符合 DID语法 中的 `did` 规则。 如果不符合,DID解析器 必须返回以下结果:
    1. didResolutionMetadata: «[ "error" → "invalidDid", ... ]»
    2. didDocument: null
    3. didDocumentMetadata: «[ ]»
  2. 确定 输入 DID 的DID方法是否由实现此算法的 DID解析器 支持。如果不支持,DID解析器 必须返回以下结果:
    1. didResolutionMetadata: «[ "error" → "methodNotSupported", ... ]»
    2. didDocument: null
    3. didDocumentMetadata: «[ ]»
  3. 通过执行 读取 操作,从 输入 DID可验证数据注册表 中获取 DID文档,如 输入 DID方法 所定义:
    1. 除了 输入 DID 外,此算法的所有其他 解析选项 都必须传递给 输入 DID方法读取 操作。
    2. 如果 输入 DID 不存在,返回以下结果:
      1. didResolutionMetadata: «[ "error" → "notFound", ... ]»
      2. didDocument: null
      3. didDocumentMetadata: «[ ]»
    3. 如果 输入 DID 已被停用,返回以下结果:
      1. didResolutionMetadata: «[ ... ]»
      2. didDocument: null
      3. didDocumentMetadata: «[ "deactivated" → true, ... ]»
    4. 否则,读取 操作的结果称为 输出 DID文档。此结果必须以与 accept 输入 DID解析选项 对应的符合规范的 表示 表示。
  4. 如果 输入 DID解析选项 包含值为 trueexpandRelativeUrls 选项:
    1. 遍历 服务验证方法验证关系 中的所有 输出 DID文档
    2. 如果 服务验证方法id 属性值(包括嵌入在 验证关系 中的值)是 相对DID URL,或者如果 验证关系相对DID URL
      1. 根据 相对DID URL 的规则,将 相对DID URL 解析为符合 DID URL语法 的绝对 DID URL
    3. 更新 输出 DID文档,将 相对DID URL 替换为解析后的绝对 DID URL
  5. 返回以下结果:
    1. didResolutionMetadata: «[ ... ]»
    2. didDocument: 输出DID文档
    3. didDocumentMetadata: «[ "contentType" → 输出DID文档媒体类型, ... ]»

关于如何处理已被 停用 的DID的讨论正在进行中。

指定在DID解析过程中如何验证DID文档上的签名/证明。

我们是否应该定义功能,使客户端能够发现 DID解析器 支持的 DID方法 列表或其他功能?或者这是实现特定的,超出本规范的范围?例如,参见 这里这里

DID URL解引用

DID URL解引用 功能将 DID URL 解引用为 资源,其内容取决于 DID URL 的组件,包括 DID方法、方法特定的标识符、路径、查询和片段。此过程依赖于 DID解析 包含在 DID URL 中的 DIDDID URL解引用 可能涉及多个步骤(例如,当被解引用的DID URL包含片段时),并且该函数定义为在所有步骤完成后返回最终资源。下图描述了上述关系。


DID解析为DID文档;DID URL包含DID;DID URL解引用为DID文档片段或外部资源。
DID URL解引用概述 参见:叙述性描述

图的左上部分包含一个黑色轮廓的矩形,标记为 "DID"。

图的左下部分包含一个黑色轮廓的矩形,标记为 "DID URL"。 此矩形包含四个较小的黑色轮廓矩形,水平排列相邻。这些较小的矩形分别标记为 "DID"、"路径"、"查询" 和 "片段"。

图的右上部分包含一个黑色轮廓的矩形,标记为 "DID文档"。 此矩形包含三个较小的黑色轮廓矩形。这些较小的矩形分别标记为 "id"、"(属性 X)" 和 "(属性 Y)",并被多个省略号(...)包围。一个弯曲的黑色箭头,标记为 "DID文档 - 相对片段解引用",从标记为 "(属性 X)" 的矩形延伸到标记为 "(属性 Y)" 的矩形。

图的右下部分包含一个黑色轮廓的椭圆形,标记为 "资源"。

一个黑色箭头,标记为 "解析为DID文档",从图的左上部分标记为 "DID" 的矩形指向图的右上部分标记为 "DID文档" 的矩形。

一个黑色箭头,标记为 "引用",从图的右上部分标记为 "DID文档" 的矩形指向图的右下部分标记为 "资源" 的椭圆形。

一个黑色箭头,标记为 "包含",从图的左下部分标记为 "DID" 的小矩形指向图的左上部分标记为 "DID" 的矩形。

一个黑色箭头,标记为 "解引用为DID文档",从图的左下部分标记为 "DID URL" 的矩形指向图的右上部分标记为 "DID文档" 的矩形。

一个黑色箭头,标记为 "解引用为资源",从图的左下部分标记为 "DID URL" 的矩形指向图的右下部分标记为 "资源" 的椭圆形。

所有符合规范的 DID解析器 都实现了以下函数,其抽象形式如下:

dereference(DID URL, dereferenceOptions) →
   « dereferencingMetadata, contentStream, contentMetadata »
      

dereference 函数的输入变量如下:

DID URL
一个符合规范的 DID URL,作为单个 字符串。这是要解引用的 DID URL。要解引用 DID片段,必须使用包含 DID片段 的完整 DID URL。此输入是必需的。

虽然任何 DID URL 都可以传递给DID URL解引用器,但实现者应参考 以进一步了解 DID URL 如何被解引用的常见模式。

dereferencingOptions
一个 元数据结构,包含除 DID URL 本身之外的 dereference 函数的输入选项。此规范定义的属性在 中。此输入是必需的,但结构可能为空。

此函数返回多个值,并且对这些值如何一起返回没有限制。dereference 的返回值包括 dereferencingMetadatacontentStreamcontentMetadata

dereferencingMetadata
一个 元数据结构,包含与 DID URL解引用 过程结果相关的值。此结构是必需的,并且在解引用过程中出现错误时,此结构不能为空。此规范定义的属性在 中。如果解引用不成功,此结构必须包含一个描述错误的 error 属性。
contentStream
如果 dereferencing 函数被调用并成功,这必须包含与 DID URL 对应的 资源contentStream 可以是 资源,例如可以以符合规范的 表示 之一序列化的 DID文档验证方法服务,或任何其他可以通过媒体类型标识并通过解析过程获得的资源格式。如果解引用不成功,此值必须为空。
contentMetadata
如果解引用成功,这必须是一个 元数据结构,但结构可能为空。此结构包含 contentStream 的元数据。如果 contentStreamDID文档,这必须是 didDocumentMetadata 结构,如 DID解析 中所述。如果解引用不成功,此输出必须是一个空的 元数据结构

符合规范的 DID URL解引用 实现不会以任何方式更改这些函数的签名。DID URL解引用 实现可能会将 dereference 函数映射到方法特定的内部函数以执行实际的 DID URL解引用 过程。DID URL解引用 实现可能会实现并暴露具有不同签名的其他函数,除了此处指定的 dereference 函数。

DID URL解引用选项

此结构中的可能属性及其可能值应在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下常见的解引用选项属性:

accept
调用者首选的 contentStream 的媒体类型。媒体类型必须表示为 ASCII 字符串DID URL解引用 实现应使用此值来确定返回的 表示contentType,如果支持并可用此类 表示

DID URL解引用元数据

此结构中的可能属性及其可能值已在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下常见属性。

contentType
如果解引用成功,返回的 contentStream 的媒体类型应使用此属性表示。媒体类型值必须表示为 ASCII 字符串
error
解引用过程中的错误代码。当解引用过程中出现错误时,此属性是必需的。此属性的值必须为单个关键字,表示为 ASCII 字符串。此字段的可能属性值应在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册。本规范定义了以下常见错误值:
invalidDID URL
提供给 DID URL解引用 函数的 DID URL 不符合有效语法。(参见 。)
notFound
DID URL解引用器 无法找到此解引用请求产生的 contentStream

算法

以下 DID URL解引用 算法必须由符合规范的 DID解析器 实现。根据 [[RFC3986]],它包含以下三个步骤:解析DID;解引用资源;以及解引用片段(仅当 输入 DID URL 包含 DID片段 时):

解引用资源

  1. 验证 输入 DID URL 是否符合 DID URL语法 的 `did-url` 规则。如果不符合,DID URL解引用器 必须返回以下结果:
    1. dereferencingMetadata: «[ "error" → "invalidDID URL" ]»
    2. contentStream: null
    3. contentMetadata: «[ ]»
  2. 通过执行 DID解析 算法获取 输入 DIDDID文档,如 中所定义。所有 解引用选项输入 DID URL 的所有 DID参数 必须作为 解析选项 传递给 DID解析 算法。
  3. 如果 输入 DID 在 VDR 中不存在,DID URL解引用器 必须返回以下结果:
    1. dereferencingMetadata: «[ "error" → "notFound", ... ]»
    2. contentStream: null
    3. contentMetadata: «[ ]»
  4. 否则,DID解析 算法的 didDocument 结果称为 解析的 DID文档
  5. 如果存在,从 输入 DID URL 中分离 DID片段 并继续使用调整后的 输入 DID URL
  6. 如果 输入 DID URL 不包含 DID路径DID查询
    did:example:1234
    DID URL解引用器 必须返回 解析的 DID文档解析的 ,如下所示:
    1. dereferencingMetadata: «[ ... ]»
    2. contentStream: resolvedDIDdocument
    3. contentMetadata: «[ resolvedDIDdocument metadata
  7. 如果 输入 DID URL 包含 DID参数 hl
    did:example:1234?hl=zQmWvQxTqbG2Z9HPJgG57jjwR154cKhbtJenbyYTWkjgF3e
    1. TODO: 指定处理 `hl`DID参数的算法。

  8. 如果 输入 DID URL 包含 DID参数 service 和可选的 relativeRefDID参数:
    did:example:1234?service=files&relativeRef=%2Fmyresume%2Fdoc%3Fversion%3Dlatest
    1. 解析的 DID文档 中选择 服务端点,其 id 属性包含与 输入 DID URLserviceDID参数值匹配的片段。这称为 输入 服务端点
    2. 执行 服务端点构建 算法:
      1. 读取 输入 服务端点serviceEndpoint 属性的值。这称为 输入 服务端点 URL
      2. 输入 DID URL输入 服务端点 URL 传递给 服务端点构建 算法。
      3. 结果称为 输出 服务端点 URL
    3. 返回以下结果:
      1. dereferencingMetadata: «[ ... ]»
      2. content: output service endpoint URL
      3. contentMetadata: «[ "contentType" → "text/uri-list", ... ]»
  9. 否则,如果 输入 DID URL 包含 DID路径 和/或 DID查询
    did:example:1234/custom/path?customquery
    1. 适用的 DID方法 可以指定如何解引用 输入 DID URLDID路径 和/或 DID查询
      did:example:1234/resources/1234
    2. 扩展规范可以指定如何解引用 输入 DID URLDID路径
      did:example:1234/whois
    3. 扩展规范可以指定如何解引用 输入 DID URLDID查询
      did:example:1234?transformKey=JsonWebKey
    4. 客户端可以以应用程序特定的方式解引用 输入 DID URL
  10. 如果此算法、适用的 DID方法、扩展或客户端都无法解引用 输入 DID URL,则返回以下结果:
    1. dereferencingMetadata: «[ "error" → "notFound" ]»
    2. contentStream: null
    3. contentMetadata: «[ ]»

除了DID参数 service 之外,是否还可以有一个DID参数 serviceType 来根据服务的类型而不是 ID 选择服务。参见 Dave Longley 的评论 关于 `serviceType`。

解引用片段

如果 输入 DID URL 包含 DID片段,则片段的解引用取决于资源的媒体类型 ([[RFC2046]]),即 的结果。

  1. 如果 的结果是 输出 服务端点 URL,并且 输入 DID URL 包含 DID片段
    did:example:1234?service=files&relativeRef=%2Fmyresume%2Fdoc%3Fversion%3Dlatest#intro
    1. 如果 输出 服务端点 URL 包含 fragment 组件,则引发错误。
    2. DID片段 附加到 输出 服务端点 URL。换句话说,输出 服务端点 URL “继承” 了 输入 DID URLDID片段
    3. 返回 输出 服务端点 URL
  2. 否则,根据资源的媒体类型 ([[RFC2046]]) 解引用DID片段。例如,如果资源是媒体类型为 application/did 的DID文档表示,则片段根据与 JSON-LD 1.1: application/ld+json 媒体类型 [JSON-LD11] 相关的规则进行处理。

DID片段 的这种使用方式与 [[RFC3986]] 中片段标识符的定义一致。它标识了 主资源(即 DID文档)的一个 子资源

DID片段 的这种行为类似于在 HTTP URL 中解引用片段时的处理方式,当解引用它返回带有 Location 头的 HTTP 3xx(重定向)响应时(参见 [[RFC7231]] 的第 7.1.2 节)。

示例

给定以下 输入 DID URL

did:example:123456789abcdefghi#keys-1

... 以及以下 解析的 DID文档

{
	"@context": "https://www.w3.org/ns/did/v1",
	"id": "did:example:123456789abcdefghi",
	"verificationMethod": [{
		"id": "did:example:123456789abcdefghi#keys-1",
		"type": "Ed25519VerificationKey2018",
		"controller": "did:example:123456789abcdefghi",
		"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
	}],
	"service": [{
		"id": "did:example:123456789abcdefghi#agent",
		"type": "AgentService",
		"serviceEndpoint": "https://agent.example.com/8377464"
	}, {
		"id": "did:example:123456789abcdefghi#messages",
		"type": "MessagingService",
		"serviceEndpoint": "https://example.com/messages/8377464"
	}]
}

... 那么 算法的结果是以下 输出资源

{
	"@context": "https://www.w3.org/ns/did/v1",
	"id": "did:example:123456789abcdefghi#keys-1",
	"type": "Ed25519VerificationKey2018",
	"controller": "did:example:123456789abcdefghi",
	"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}

给定以下 输入 DID URL 和与上述相同的 解析的 DID文档

did:example:123456789abcdefghi?service=messages&relativeRef=%2Fsome%2Fpath%3Fquery#frag

... 那么 算法的结果是以下 输出 服务端点 URL

https://example.com/messages/8377464/some/path?query#frag
Diagram showing how aDID URLcan be dereferenced to a service endpoint URL
将DID URL解引用为服务端点 URL。

更改图表和/或示例以使其一致。

元数据结构

DID解析DID URL解引用 和其他DID相关过程中,通常涉及输入和输出元数据。用于传达此元数据的结构必须是一个 映射 属性。每个属性名称必须是一个 字符串。每个属性值必须是一个 字符串映射列表集合布尔值null。任何复杂数据结构(如映射和列表)中的值也必须是这些数据类型之一。在DID规范注册表 [[?DID-SPEC-REGISTRIES]] 中注册的所有元数据属性定义必须定义值类型,包括该值的任何其他格式或限制(例如,格式化为日期或十进制整数的字符串)。建议属性定义使用字符串作为值。整个元数据结构必须根据 [[INFRA]] 规范中的 JSON 序列化规则 可序列化。实现可以将元数据结构序列化为其他数据格式。

所有使用元数据结构作为输入或输出的函数的实现都能够以确定性的方式完全表示此处描述的所有数据类型。由于使用元数据结构的输入和输出是根据数据类型而不是其序列化定义的,因此 表示 的方法是函数实现内部的,不在本规范的范围内。

以下示例演示了可能用作 DID解析输入元数据 的 JSON 编码元数据结构。

{
"accept": "application/did+ld+json"
}
  

此示例对应于以下格式的元数据结构:

«[
"accept" → "application/did+ld+json"
]»
  

下一个示例演示了可能用作 DID解析元数据 的 JSON 编码元数据结构,如果未找到 DID

{
"error": "notFound"
}
  

此示例对应于以下格式的元数据结构:

«[
"error" → "notFound"
]»
  

下一个示例演示了可能用作 DID文档元数据 的 JSON 编码元数据结构,用于描述与 DID文档 关联的时间戳。

{
"created": "2019-03-23T06:35:22Z",
"updated": "2023-08-10T13:40:06Z"
}
  

此示例对应于以下格式的元数据结构:

«[
"created" → "2019-03-23T06:35:22Z",
"updated" → "2023-08-10T13:40:06Z"
]»
  

DID解析架构

TODO: 描述 DID解析器 如何实现和使用,描述 DID方法 的相关性。解释“方法架构”和“解析器架构”之间的区别。

方法架构

DID解析 算法涉及根据其 DID方法DID 执行 读取 操作(参见 )。

“读取”操作的机制在 DID方法 之间可能有很大差异。特别是,不应假设:

  • ... 使用不可变的区块链作为(部分)可验证数据注册表
  • ... 在执行“读取”操作期间需要与远程网络交互。
  • ... 实际的 DID文档 以纯文本形式存储在 可验证数据注册表 上,或者可以通过 HTTP(S) 等标准协议简单地检索 DID文档。虽然某些 DID方法 可能以这种方式定义其“读取”操作,但其他方法可能定义更复杂的多步骤过程,涉及动态构建“虚拟”DID文档

例如,提到“解析”对等/离链/微链/边缘链DID的含义(例如,参见 [[DID-PEER]] 和 这里)。

例如,提到“解析”仅仅是包装的公钥的DID的含义(例如,参见 [[DID-KEY]] 和 这里)。

根据 DID方法 的“读取”操作的确切性质,DID解析器可验证数据注册表 之间的交互可以实现为 可验证读不可验证读

Diagram showing a 'verifiable read' implementation of aDIDmethod.
DID方法可验证读 实现。
Diagram showing an 'unverifiable read' implementation of aDIDmethod.
DID方法不可验证读 实现。

可验证读 最大限度地提高了对“读取”操作结果的完整性和正确性的信心——在适用的 DID方法 下尽可能做到这一点。它可以通过多种方式实现,例如:

不可验证读没有这样的保证,因此不太理想,例如:

是否可以进行可验证读不仅取决于DID方法本身,还取决于DID解析器的实现方式。DID方法可以定义多种不同的“读取”操作实现方式,并且应该至少提供一种实现可验证读的指导。

可验证读的保证仍然始终受到底层可验证数据注册表的架构、协议、加密和其他方面的限制。最强的可验证读实现形式被认为是不需要与远程网络进行任何交互的形式(例如,参见[[DID-KEY]]),或者将依赖特定网络基础设施的需求降到最低,并将“信任根”仅归结为经过验证的熵和加密(例如,参见[[KERI]])。

TODO: 描述客户端如何在不信任DID解析器的情况下独立验证“读取”操作的结果(例如,使用状态证明)。

一个DID解析器必须支持至少一种DID方法DID解析算法,并且可以支持多种DID方法

支持多种DID方法的DID解析器的图示。
支持多种DID方法DID解析器

在这种情况下,上述关于可验证读不可验证读实现的考虑适用于每个支持的DID方法

解析器架构

DID解析DID URL解引用的算法被定义为抽象函数(参见)。

这些算法由DID解析器实现。客户端通过绑定调用DID解析器。绑定定义了如何使用具体的编程或通信接口实现这些抽象函数。可以区分本地绑定(例如本地命令行工具或库API)和远程绑定(例如HTTP(S)绑定)。

具有“本地绑定”的DID解析器的图示。
DID解析器本地绑定
具有“远程绑定”的DID解析器的图示。
DID解析器远程绑定

TODO: 描述本地绑定远程绑定,以及对隐私、安全和信任的影响。

还要描述远程绑定潜在缺点的缓解措施,例如:

TODO: 讨论在受限用户代理(如移动应用和浏览器)中的DID解析。

代理解析

一个DID解析器可以调用另一个DID解析器,后者作为代理执行DID解析算法,如中定义。

第一个DID解析器然后充当客户端,并选择适当的绑定来调用第二个DID解析器。例如,一个DID解析器可以通过本地绑定(例如命令行工具)调用,而后者又通过远程绑定(例如HTTP(S)绑定)调用另一个DID解析器

图示显示两个DID解析器,一个通过“本地绑定”调用,另一个通过“远程绑定”调用。
客户端通过本地绑定调用一个DID解析器,后者通过远程绑定调用另一个DID解析器,后者又支持解析多种DID方法

这类似于DNS架构中的“存根解析器”调用“递归解析器”,尽管概念并不完全可比(DNS解析使用单一的具体协议,而DID解析是由不同的DID方法和不同的绑定实现的抽象函数)。

客户端解引用

DID URL解引用算法的不同部分可以由解析器架构的不同组件执行。

具体来说,当解引用带有DID片段DID URL时,解引用资源DID解析器完成,而解引用片段客户端完成。

示例:给定DID URL did:xyz:1234#keys-1,可以通过本地绑定调用DID解析器解引用资源(即DID文档),而客户端可以通过解引用片段(即DID文档的一部分)来完成DID URL解引用算法。

图示显示通过DID解析器和客户端对DID URL进行客户端解引用。
通过DID解析器客户端DID URL进行客户端解引用。

示例:给定DID URL did:xyz:1234#keys-1,可以通过本地绑定调用DID解析器,后者又通过远程绑定调用另一个DID解析器解引用资源(即DID文档),而客户端可以通过解引用片段(即DID文档的一部分)来完成DID URL解引用算法。

图示显示通过两个DID解析器和客户端对DID URL进行客户端解引用。
通过两个DID解析器客户端DID URL进行客户端解引用(结合代理解析)。

示例:给定DID URL did:xyz:1234?service=agent&relativeRef=%2Fsome%2Fpath%3Fquery#frag,可以调用DID解析器解引用资源(即服务端点 URL),而客户端可以通过解引用片段(即带有片段的服务端点 URL)来完成DID URL解引用算法。

图示显示通过DID解析器和客户端对DID URL进行客户端解引用。
通过DID解析器客户端DID URL进行客户端解引用。

DID解析结果

本节定义了一个数据结构,表示中描述的算法的结果。DID解析结果包含DID文档以及DID解析元数据DID文档元数据

此数据结构的媒体类型定义为`application/ld+json;profile="https://w3id.org/did-resolution"`。

示例

{
	"@context": "https://w3id.org/did-resolution/v1",
	"didDocument": {
		"@context": "https://www.w3.org/ns/did/v1",
		"id": "did:example:123456789abcdefghi",
		"authentication": [{
			"id": "did:example:123456789abcdefghi#keys-1",
			"type": "Ed25519VerificationKey2018",
			"controller": "did:example:123456789abcdefghi",
			"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
		}],
		"service": [{
			"id":"did:example:123456789abcdefghi#vcs",
			"type": "VerifiableCredentialService",
			"serviceEndpoint": "https://example.com/vc/"
		}]
	},
	"didResolutionMetadata": {
		"contentType": "application/did+ld+json",
		"retrieved": "2024-06-01T19:73:24Z",
	},
	"didDocumentMetadata": {
		"created": "2019-03-23T06:35:22Z",
		"updated": "2023-08-10T13:40:06Z",
		"method": {
			"nymResponse": {
				"result": {
					"data": "{\"dest\":\"WRfXPg8dantKVubE3HX8pw\",\"identifier\":\"V4SGRU86Z58d6TV7PBUe6f\",\"role\":\"0\",\"seqNo\":11,\"txnTime\":1524055264,\"verkey\":\"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV\"}",
					"type": "105",
					"txnTime": 1.524055264E9,
					"seqNo": 11.0,
					"reqId": 1.52725687080231475E18,
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"dest": "WRfXPg8dantKVubE3HX8pw"
				},
				"op": "REPLY"
			},
			"attrResponse": {
				"result": {
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"seqNo": 12.0,
					"raw": "endpoint",
					"dest": "WRfXPg8dantKVubE3HX8pw",
					"data": "{\"endpoint\":{\"xdi\":\"http://127.0.0.1:8080/xdi\"}}",
					"txnTime": 1.524055265E9,
					"type": "104",
					"reqId": 1.52725687092557056E18
				},
				"op": "REPLY"
			}
		}
	}
}

参见相应的开放问题。

需要定义此数据结构的确切工作方式,以及它是否始终包含DID文档,或者也可以包含其他结果。

DID文档

DID关联的DID文档的结果。

DID解析元数据

这是一个元数据结构(参见[[DID-CORE]]中的元数据结构部分),包含有关DID解析过程的元数据。

此元数据通常在DID解析函数的调用之间变化,因为它表示解析过程本身的数据。

此元数据的来源是DID解析器。

DID解析元数据的示例包括:

另请参见[[DID-CORE]]中的DID解析元数据部分。

DID文档元数据

这是一个元数据结构(参见[[DID-CORE]]中的元数据结构部分),包含有关DID文档的元数据。

此元数据通常在DID解析函数的调用之间不会变化,除非DID文档发生变化,因为它表示有关DID文档的数据。

此元数据的来源是DID控制者和/或DID方法

DID文档元数据的示例包括:

DID文档元数据还可以包括方法特定的元数据,例如:

另请参见[[DID-CORE]]中的DID文档元数据部分。

对于某些数据,可能存在争议,它是否应该属于DID文档(即描述DID主体的数据),或者它是否是元数据(即关于DID文档或DID解析过程的数据)。例如BTCR方法中的“延续DID文档”的URL。

DID URL解引用结果

本节定义了一个数据结构,用于表示在中描述的算法的结果。DID URL解引用结果包含任意内容以及 DID解析元数据内容元数据

参见相关的开放问题。

此数据结构的媒体类型定义为`application/ld+json;profile="https://w3id.org/did-resolution"`。

示例

{
	"@context": "https://w3id.org/did-resolution/v1",
	"content": {
		"@context": "https://www.w3.org/ns/did/v1",
		"id": "did:example:123456789abcdefghi",
		"authentication": [{
			"id": "did:example:123456789abcdefghi#keys-1",
			"type": "Ed25519VerificationKey2018",
			"controller": "did:example:123456789abcdefghi",
			"publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
		}],
		"service": [{
			"id":"did:example:123456789abcdefghi#vcs",
			"type": "VerifiableCredentialService",
			"serviceEndpoint": "https://example.com/vc/"
		}]
	},
	"DID URLDereferencingMetadata": {
		"contentType": "application/did+ld+json",
		"retrieved": "2024-06-01T19:73:24Z",
	},
	"contentMetadata": {
		"created": "2019-03-23T06:35:22Z",
		"updated": "2023-08-10T13:40:06Z",
		"method": {
			"nymResponse": {
				"result": {
					"data": "{\"dest\":\"WRfXPg8dantKVubE3HX8pw\",\"identifier\":\"V4SGRU86Z58d6TV7PBUe6f\",\"role\":\"0\",\"seqNo\":11,\"txnTime\":1524055264,\"verkey\":\"H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV\"}",
					"type": "105",
					"txnTime": 1.524055264E9,
					"seqNo": 11.0,
					"reqId": 1.52725687080231475E18,
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"dest": "WRfXPg8dantKVubE3HX8pw"
				},
				"op": "REPLY"
			},
			"attrResponse": {
				"result": {
					"identifier": "HixkhyA4dXGz9yxmLQC4PU",
					"seqNo": 12.0,
					"raw": "endpoint",
					"dest": "WRfXPg8dantKVubE3HX8pw",
					"data": "{\"endpoint\":{\"xdi\":\"http://127.0.0.1:8080/xdi\"}}",
					"txnTime": 1.524055265E9,
					"type": "104",
					"reqId": 1.52725687092557056E18
				},
				"op": "REPLY"
			}
		}
	}
}

内容

DID URL关联的任意内容。的结果。

DID URL解引用元数据

这是一个元数据结构(参见[[DID-CORE]]中的元数据结构部分),包含有关DID URL解引用过程的元数据。

此元数据通常在DID URL解引用函数的调用之间发生变化,因为它表示有关解引用过程本身的数据。

添加更多关于DID URL解引用元数据如何工作的细节。

另见[[DID-CORE]]中的DID URL解引用元数据部分。

内容元数据

这是一个元数据结构(参见[[DID-CORE]]中的元数据结构部分),包含有关内容的元数据。

此元数据通常在DID URL解引用函数的调用之间不会发生变化,除非内容发生变化,因为它表示有关内容的数据。

添加更多关于内容元数据如何工作的细节。

错误

invalidDid

如果在DID解析过程中检测到无效的DID, DID解析元数据error属性的值必须为invalidDid, 如部分所定义。

invalidDID URL

如果在DID解析DID URL解引用过程中检测到无效的DID URL, DID解析或DID URL解引用元数据error属性的值必须为invalidDID URL, 如部分所定义。

notFound

如果在DID解析DID URL解引用过程中DID或DID URL不存在, DID解析或DID URL解引用元数据error属性的值必须为notFound, 如部分所定义。

representationNotSupported

如果在DID解析DID URL解引用过程中不支持DID文档的表示形式, DID解析元数据error属性的值必须为representationNotSupported, 如部分所定义。

methodNotSupported

如果在DID解析DID URL解引用过程中不支持DID方法, DID解析或DID URL解引用元数据error属性的值必须为methodNotSupported

internalError

当在DID解析DID URL解引用过程中发生意外错误时, DID解析或DID URL解引用元数据error属性的值必须为internalError

invalidPublicKey

如果在DID解析DID URL解引用过程中检测到无效的公钥值, DID解析或DID URL解引用元数据error属性的值必须为invalidPublicKey

invalidPublicKeyLength

如果在DID解析DID URL解引用过程中,rawPublicKeyBytes的字节长度与关联的multicodecValue的预期公钥长度不匹配, DID解析或DID URL解引用元数据error属性的值必须为invalidPublicKeyLength

invalidPublicKeyType

如果在DID解析DID URL解引用过程中检测到无效的公钥类型, DID解析或DID URL解引用元数据error属性的值必须为invalidPublicKeyType

unsupportedPublicKeyType

如果在DID解析DID URL解引用过程中检测到不支持的公钥类型, DID解析或DID URL解引用元数据error属性的值必须为unsupportedPublicKeyType

绑定

本节定义了部分中抽象算法的绑定。

HTTP(S) 绑定

本节定义了一个DID解析器绑定,通过HTTP(S)端点暴露DID解析和/或DID URL解引用功能(包括所有解析/解引用选项和元数据)。参见

HTTP(S)绑定是一个远程绑定。它需要一个已知的HTTP(S) URL,远程DID解析器可以在该URL上被调用。此URL称为DID解析器 HTTP(S) 端点

使用此绑定,DID解析功能(参见)和/或DID URL解引用功能(参见)可以按以下方式执行:

  1. 使用DID解析器 HTTP(S) 端点初始化请求HTTP(S) URL
    https://resolver.example/1.0/identifiers/
  2. 对于DID解析功能:
    1. 输入 DID附加到请求HTTP(S) URL
      https://resolver.example/1.0/identifiers/did:example:1234
    2. Accept HTTP 请求头设置为`application/ld+json;profile="https://w3id.org/did-resolution"`以请求完整的,或者
    3. Accept HTTP 请求头设置为解析选项中的accept值。
    4. 如果提供了其他解析选项
      1. 输入 DID必须进行URL编码(如RFC3986 第2.1节所指定)。
      2. 将所有解析选项(除了accept)编码为请求HTTP(S) URL中的查询参数。
        https://resolver.example/1.0/identifiers/did%3Aexample%3A1234?option1=value1&option2=value2
  3. 对于DID URL解引用功能:
    1. 输入 DID URL附加到请求HTTP(S) URL
      https://resolver.example/1.0/identifiers/did:example:1234?service=files&relativeRef=/resume.pdf
    2. Accept HTTP 请求头设置为`application/ld+json;profile="https://w3id.org/did-url-dereferencing"`以请求完整的,或者
    3. Accept HTTP 请求头设置为解引用选项中的accept值。
    4. 如果提供了其他解引用选项
      1. 输入 DID URL必须进行URL编码(如RFC3986 第2.1节所指定)。
      2. 将所有解引用选项(除了accept)编码为请求HTTP(S) URL中的查询参数。
        https://resolver.example/1.0/identifiers/did%3Aexample%3A1234%3Fservice%3Dfiles%26relativeRef%3D%2Fresume.pdf?option1=value1&option2=value2
  4. 请求HTTP(S) URL上执行HTTP GET请求。这将调用远程DID解析器上的DID解析DID URL解引用功能。
  5. 如果DID解析DID URL解引用功能在didResolutionMetadatadereferencingMetadata中返回error元数据属性, 则HTTP响应状态码必须对应于error元数据属性的值,根据以下表格:
    错误 HTTP 状态码
    invalidDid 400
    invalidDID URL 400
    notFound 404
    representationNotSupported 406
    methodNotSupported 501
    internalError 500
    (其他值) 500
  6. 如果DID解析DID URL解引用功能在didDocumentMetadatacontentMetadata中返回deactivated元数据属性,且其值为true
    1. HTTP响应状态码必须为410
  7. 对于DID解析功能:
    1. 如果Content-Type HTTP 响应头的值为`application/ld+json;profile="https://w3id.org/did-resolution"`:
      1. HTTP 主体必须包含DID解析结果(参见),这是DID解析功能的结果。
    2. 如果功能成功并返回didDocument
      1. HTTP响应状态码必须为200
      2. HTTP响应必须包含Content-Type HTTP 响应头。其值必须为didResolutionMetadata中的contentType元数据属性的值(参见)。
      3. HTTP响应主体必须包含DID解析功能的结果didDocument,其表示形式对应于Content-Type HTTP 响应头
  8. 对于DID URL解引用功能:
    1. 如果Content-Type HTTP 响应头的值为`application/ld+json;profile="https://w3id.org/did-url-dereferencing"`:
      1. HTTP 主体必须包含DID URL解引用结果(参见),这是DID URL解引用功能的结果。
    2. 如果功能成功并返回contentStream,且contentType元数据属性的值为text/uri-list
      1. HTTP响应状态码必须为303
      2. HTTP响应必须包含Location头。该头的值必须为输出 服务端点 URL
      3. HTTP响应主体必须为空。
    3. 如果功能成功并返回contentStream,且contentType为其他值:
      1. HTTP响应状态码必须为200
      2. HTTP响应必须包含Content-Type HTTP 响应头。其值必须为dereferencingMetadata中的contentType元数据属性的值(参见)。
      3. HTTP响应主体必须包含DID URL解引用功能的结果contentStream,其表示形式对应于Content-Type HTTP 响应头

参见此处的OpenAPI定义。

DID解析示例

给定以下DID解析器 HTTP(S) 端点

https://resolver.example/1.0/identifiers/

以及以下输入 DID

did:sov:WRfXPg8dantKVubE3HX8pw

请求HTTP(S) URL为:

https://resolver.example/1.0/identifiers/did:sov:WRfXPg8dantKVubE3HX8pw

可以通过以下方式调用HTTP(S)绑定:

curl -X GET https://resolver.example/1.0/identifiers/did:sov:WRfXPg8dantKVubE3HX8pw

HTTP(S)绑定的其他示例:

通过HTTPS调用resolve()的图示
通过HTTP(S)调用resolve()。
通过HTTPS调用resolve()的图示
通过HTTP(S)调用resolve()。

DID URL解引用示例

HTTP(S)绑定的其他示例:

通过HTTPS调用dereference()的图示
通过HTTP(S)调用dereference()。
通过HTTPS调用dereference()的图示
通过HTTP(S)调用dereference()。

服务端点构建

本节定义了服务端点构建的输入和算法,该算法返回一个服务端点 URL作为输出。此算法在DID URL解引用过程中选择服务端点时使用(参见)。

在本节中,pathqueryfragment的定义遵循[[RFC3986]]。

输入

服务端点构建算法的输入是一个输入 DID URL和一个输入 服务端点 URL

服务端点构建算法的输入要求如下:

算法

  1. 将字符串输出服务端点URL初始化为输入服务端点URL的值
  2. 如果输出服务端点URL包含query组件,则移除该组件
  3. 如果输出服务端点URL包含fragment组件,则移除该组件
  4. 输入DID URLpath组件追加到输出服务端点URL
  5. 如果输入服务端点URL包含query组件,则在输出服务端点URL后追加?加上query
  6. 如果输入DID URL包含query组件,则在输出服务端点URL后追加?加上query
  7. 如果输入服务端点URL包含fragment组件,则在输出服务端点URL后追加#加上fragment
  8. 如果输入DID URL包含fragment组件,则在输出服务端点URL后追加#加上fragment
  9. 返回输出服务端点URL

我们可能允许输入DID URL输入服务端点URL同时包含query组件,前提是它们都包含可以合并的键/值参数列表。

服务端点构建算法的细节已在2019年4月的CCG邮件列表中讨论过,例如这里这里

我们可以考虑复用[[RFC3986]]中定义的“相对解析”算法,而不是定义自己的算法。

参见对应的开放问题。

示例

给定以下输入服务端点URL

https://example.com/messages/8377464

以及以下输入DID URL

did:example:123456789abcdefghi?service=messages&relativeRef=%2Fsome%2Fpath%3Fquery#frag

输出服务端点URL为:

https://example.com/messages/8377464/some/path?query#frag

安全与隐私考虑

认证/授权

DID解析DID URL解引用不涉及任何认证或授权功能。类似于DNS解析,任何人都可以执行此过程,无需任何凭据或非公开知识。

说明DID不一定是全局可解析的,例如成对或N-wise的“对等”DID。

参见[[RFC3339]]: URI具有全局范围,无论上下文如何,其解释都是一致的,尽管解释结果可能与最终用户的上下文相关。

一个高级的想法是,DID解析的结果可能是上下文相关的或依赖于策略,参见此评论

一个相关主题是DID文档(或部分)是否可以加密,例如w3c/did-core/issues/25。另见IPIDDID方法中片段的使用。

缓存

DID解析器可以维护DID文档的通用缓存,也可以维护特定于某些DID方法的缓存。

可以使用noCache解析选项来请求特定的缓存行为。

解析选项是可选的。

该属性的可能值包括:

缓存行为可以通过DID解析器的配置、noCache解析选项或DID文档内容(例如`cacheMaxTtl`字段)或其组合来控制。

参见对应的开放问题。

或许我们可以复用其他协议(如HTTP)的缓存机制。

版本控制

如果提供了versionIdversionTimeDID参数, 则DID解析算法会返回DID文档的特定版本。

DID参数versionIdversionTime 是互斥的。

versionIdDID参数的使用是特定于DID方法的。 其可能值包括顺序号、随机UUID、内容哈希等。

DID文档元数据可能包含versionId 属性,该属性会随着每次对DID文档执行的更新操作而改变。

虽然大多数DID方法支持更新操作, 但DID方法并不需要保留所有先前的DID文档版本,因此并非所有DID方法都支持版本控制。

参见对应的开放问题。

非DID标识符

关于DID解析与非DID标识符(如域名、HTTP URI或电子邮件地址)解析之间关系的讨论正在进行中。这包括如何从非DID标识符中发现DID,以及如何使标识符之间的链接可验证。

DID方法治理

描述DID解析器应支持哪些方法,以及潜在的影响。

未来工作

本节列出了正在讨论中但尚未纳入算法的其他DID URL解引用功能。

重定向

服务端点可能具有 一个serviceEndpoint属性,其值本身是一个DID。这被解释为从输入DID到另一个DID的“DID重定向”。在这种情况下,可以启动一个“子”DID解析过程以到达“最终”服务端点。

客户端可以提供follow-redirect解析选项作为提示,指示是否应遵循重定向。此解析选项是可选的。

参见对应的开放问题。

DID重定向不仅可以应用于单个服务端点,还可以应用于整个DID文档,从而实现可移植性用例。

{
   "id": "did:example:123456789abcdefghi#hub1",
   "type": "HubService",
   "serviceEndpoint": "did:example:xyz"
}

代理

DID文档可能包含“代理”服务类型,该类型将提供一个需要遵循的映射,以解析到最终的服务URL。

{
   "id": "did:example:123456789abcdefghi",
   "type": "ProxyService",
   "serviceEndpoint": "https://mydomain.com/proxy"
}

JSON指针

正在讨论几种选择DID文档部分的方法,包括使用JSON指针。

参见对应的PR 这里这里

DID解析资源

  1. DID核心规范中的DID解析器
  2. 通用解析器
  3. did-client
  4. uPortDID解析器