DID Connect 协议
DID Connect 协议是一个开放协议,它利用密码学技术,提供了一种安全、去中心化的机制,旨在连接用户与 DApp。在此协议中,我们将 Connect 定义为用户向 DApp 提供所请求声明应答的流程。
本协议涉及以下各方:
- 用户:指终端用户,他们通常需借助钱包参与工作流程,而由 DID Labs 提供的 DID Wallet 便是一项解决方案。
- DApp: 为用户提供服务的应用程序。
- 中继:作为连接 DApp 与用户的桥梁。
- 注册链:去中心化信任机构。ArcBlock 提供 ABT 链作为去中心化信任机构。
整个连接工作流包含三个环节:
- 预备知识
- 请求 DID Connect
- 响应 DID Connect (可能包含多轮交互)

预备知识#
预知信息指的是用户在正式建立 DApp 连接前,获取关于该 DApp 相关详情的过程。DApp 可通过二维码或深度链接提供此类信息。
以下是二维码或深层链接的内容示例。
https://didWallet.io/i?action=requestAuth&url=https://example-dapp.io/auth/linkPath:此linkPath位于链接的开头,用于定位钱包。在此示例中,'linkPath' 为https://didWallet.io/i。此部分可配置,SDK 允许开发者为其应用程序注册自己的域名。action:钱包在下一步应执行的动作。在此,该动作应为requestAuth,并且钱包应使用GET方法访问该urlurl: 一个 x-www-form-urlencoded URL。钱包稍后会使用此 URL 来启动 DID Connect 请求流程。
请求 DID Connect#
请求 DID Connect 标志着钱包正式启动连接过程。钱包会向从上一步获取的 url 所指向的端点发起请求。此过程的详细步骤分解如下:
- 钱包向该端点发起请求。
GET https://example-dapp.io/api/connect/relay - DApp 返回的响应应包含以下字段:
appPk: 必需,DApp 的公钥,采用比特币 Base58 编码。agentPk: 可选,已获得 DApp 授权的代理公钥。authInfo: 必需,一个标准的 JWT 令牌。appSession:可选,用于 DApp 处理此连接会话的加密数据。钱包必须原样将其返回给 DApp。此字段的加密方式由 DApp 自行决定。以下是响应负载示例。
{
"appPk": "zBdZEnbDJTijVVCx4Nx68bzDPPMFwVizSRorvzSS3SGG2",
"agentPk": "zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"authInfo": "eyJhbGciOiJFZDI1NTE5IiwidHlwIjoiSldUIn0.eyJleHAiOjE1NDg4MDM0MjIsImlhdCI6MTU0ODcwMzQyMiwiaXNzIjoiZGlkOmFidDp6Tkt0Q05xWVdMWVdZVzNnV1JBMXZuUnlrZkNCWllIWnZ6S3IiLCJuYmYiOjE1NDg3MDM0MjIsInJlcXVlc3RlZENsYWltcyI6eyJkb2N1bWVudHMiOlt7Imhhc2giOiJUaGUgaGFzaCBvZiB0aGUgZG9jdW1lbnQncyBjb250ZW50IiwidXJpIjoiaHR0cHM6Ly9kb2N1bWVudC0xLmlvIn0seyJoYXNoIjoiVGhlIGhhc2ggb2YgdGhlIGRvY3VtZW50J3MgY29udGVudCIsInVyaSI6ImlwZnM6Ly9kb2N1bWVudC0yIn1dLCJwcm9maWxlIjpbImZ1bGxOYW1lIiwicGhvbmUiLCJzaGlwcGluZ0FkZHJlc3MiXSwicHJvb2ZPZkhvbGRpbmciOlt7InRva2VuIjoidG9rZW4gbmFtZSAxIiwidmFsdWUiOjE4MDAwMDB9LHsidG9rZW4iOiJ0b2tlbiBuYW1lIDIiLCJ2YWx1ZSI6MTAwMDAwMH1dfSwicmVzcG9uc2VBdXRoVXJpIjoiaHR0cHM6Ly9leGFtcGxlLWFwcGxpY2F0aW9uL3Jlc3BvbnNlLWF1dGgifQ.RasZv6ydSxOBj3H726P8THeo4K4IAd7wapqrdE4hrOVRONByAHYK1kr7uAXASc_-Mw9ShD3IcqAuwnLiEkvHCQ",
"appSession": ""
}如上所示的 authInfo 的头部和正文部分解码后为
{
"alg": "Ed25519",
"typ": "JWT"
}{
"iss": "did:abt:zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"agentDid": "did:abt:zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"iat": 1548703422,
"nbf": 1548703422,
"exp": 1548803422,
"challenge": "F16E730BFB914FA1",
"version": "1.0",
"appInfo": {
"name": "The name of the DApp",
"description": "The description of the DApp.",
"url": "https://example-dapp",
"logo": "https://example-dapp/logo"
},
"chainInfo": {
"host": "https://example-dapp/api"
},
"action": "responseAuth",
"url": "https://example-dapp/api/connect/relay/auth",
"requestedClaims": [
{
"type": "authPrincipal",
"description": "Please select account to continue."
}
],
"verifiableClaims:" [
{
"type": "certificate",
"content": "eyJleHAiOjE1NDg4MDM0MjIsImlhdCI6MTU0ODcwMzQyMiwiaXNzIjoiVGhlIGlzc3VlcidzIGRpZCBvZiB0aGUgY2VydGlmaWNhdGUuIiwibmJmIjoxNTQ4NzAzNDIyLCJvcHMiOnsiYWdyZWVtZW50IjpbImRpZ2VzdCBvZiBhZ3JlZW1lbnQgb25lIiwiZGlnZXN0IG9mIGFncmVlbWVudCB0d28iXSwicHJvZmlsZSI6WyJmdWxsTmFtZSIsIm1vYmlsZVBob25lIiwibWFpbGluZ0FkZHJlc3MiXX0sInBrIjoiVGhlIHBrIG9mIHRoZSBpc3N1ZXIiLCJzdWIiOiJUbyB3aG9tIHRoZSBjZXJ0aWZpY2F0ZSBpcyBpc3N1ZWQuIn0",
"sig": "The signature"
}
]
}iss:此 JWT 有效载荷的签发者。在此示例中,它是通过appPk生成的 DApp 的 DID。iat、nbf和exp:遵循 JWT 标准。版本:DID Auth 协议的版本。agentDid: 如果此负载由经另一个 DApp 授权的代理签名,则此参数应为代理 DID。挑战码:由DApp生成的一个8字节十六进制随机数,它必须由Wallet原样返回,并在签署认证响应时一并包含;DApp应能据此验证签名和该挑战码的正确性。appInfo:此 DApp 的基本信息,例如名称、描述、徽标等。chainInfo:此链的基本信息。目前,该协议在该字段中仅支持host。url:一个必填字段,Wallet 将在 DID Connect 响应流程中使用此字段。action: 指示 Wallet 下一步应执行的操作。此处应为responseAuth,且 Wallet 需使用POST方法访问url。requestedClaims:指 DApp 所需的可验证声明。在本例中,请求声明的类型是authPrincipal,这通常是 DApp 在连接过程中要求的首个声明。此声明意味着 DApp 要求钱包先设置认证主体,才能继续进行后续操作。认证主体即用户的 DID,其私钥将用于签署所有从钱包发送至 DApp 的请求。verifiableClaims: DApp所提供的可验证声明。在进行任何后续处理之前,钱包均应验证这些声明。
- 收到响应后,DID 钱包应进行以下验证:
- 验证
iat是否在请求发送之后。 - 通过使用
exp验证响应是否过期。 - 验证签名是否与
appPk匹配,并核实此appPk是否与iss字段中的 appDid 相符。
- 验证
- (TBD) 钱包可以(或可应用户要求)向注册区块链查询 DApp 的元数据,例如
trustLevel。ArcBlock 提供 ABT 链作为注册区块链。 - (TBD) 钱包在向用户展示所请求的声明时,可以使用
trustLevel。对于在注册链上找不到其appDid的DApp,钱包应将整个页面标记为高风险。如果一个DApp请求的可验证声明,其所需的trust_level高于该appDid所属的trust_level,则钱包应将这些声明标记为高风险。 - 钱包需要确定作为认证主体的 DID。若用户此前已访问过 DApp,则钱包应直接将扩展 DID 用作
authPrincipal。否则,钱包应在执行其他操作前,创建一个 扩展 DID。
DID Connect 响应#
这一步可视为,**DID Wallet** 借助 requestedClaims 字段答复 **DApp** 所提出的问题,而 **DApp** 则可能依据这些答复,进一步提出更多问题。
在确定了用于响应 DApp 的 userDid 值后,钱包应按以下格式组织响应:
{
"userPk": "",
"userInfo": "",
"userSession": "",
"appSession": ""
}
userPk:userDid所对应的公钥。userInfo:一个经 JWT 格式签名的认证对象。userSession:DID Wallet 处理此次连接会话所需的加密信息。DApp 必须将此字段原封不动地返回给 DID Wallet。此部分的加密由 DID Wallet 负责。appSession:供 DApp 处理此连接会话的加密信息。钱包必须将其原封不动地返回给 DApp。
就像 authInfo 一样, userInfo 也是一个标准的 JWT 对象,在本例中可按以下方式解码:
{
"alg": "Ed25519",
"typ": "JWT"
}
{
"iss": "userDid",
"iat": "1548713422",
"nbf": "1548713422",
"exp": "1548813422",
"challenge": "F16E730BFB914FA1",
}
字段 iss 表示此 JWT payload 的签发者。同时,它也是 上一步中确定的认证主体。
更丰富的 DID 认证响应#
在 DID Wallet 设定认证主体后,DApp 可根据其业务逻辑,向 DID Wallet 发送更多声明。这犹如银行的客户经理在为客户办理业务前,会提出一系列问题。为此,我们来看一个 DApp 在首轮认证后可向 DID Wallet 返回的示例响应。
{
"appPk": "zBdZEnbDJTijVVCx4Nx68bzDPPMFwVizSRorvzSS3SGG2",
"authInfo": "eyJhbGciOiJFZDI1NTE5IiwidHlwIjoiSldUIn0.eyJleHAiOjE1NDg4MDM0MjIsImlhdCI6MTU0ODcwMzQyMiwiaXNzIjoiZGlkOmFidDp6Tkt0Q05xWVdMWVdZVzNnV1JBMXZuUnlrZkNCWllIWnZ6S3IiLCJuYmYiOjE1NDg3MDM0MjIsInJlcXVlc3RlZENsYWltcyI6eyJkb2N1bWVudHMiOlt7Imhhc2giOiJUaGUgaGFzaCBvZiB0aGUgZG9jdW1lbnQncyBjb250ZW50IiwidXJpIjoiaHR0cHM6Ly9kb2N1bWVudC0xLmlvIn0seyJoYXNoIjoiVGhlIGhhc2ggb2YgdGhlIGRvY3VtZW50J3MgY29udGVudCIsInVyaSI6ImlwZnM6Ly9kb2N1bWVudC0yIn1dLCJwcm9maWxlIjpbImZ1bGxOYW1lIiwicGhvbmUiLCJzaGlwcGluZ0FkZHJlc3MiXSwicHJvb2ZPZkhvbGRpbmciOlt7InRva2VuIjoidG9rZW4gbmFtZSAxIiwidmFsdWUiOjE4MDAwMDB9LHsidG9rZW4iOiJ0b2tlbiBuYW1lIDIiLCJ2YWx1ZSI6MTAwMDAwMH1dfSwicmVzcG9uc2VBdXRoVXJpIjoiaHR0cHM6Ly9leGFtcGxlLWFwcGxpY2F0aW9uL3Jlc3BvbnNlLWF1dGgifQ.RasZv6ydSxOBj3H726P8THeo4K4IAd7wapqrdE4hrOVRONByAHYK1kr7uAXASc_-Mw9ShD3IcqAuwnLiEkvHCQ",
"appSession": "",
"userSession": ""
}
上文显示的 authInfo 的头部和主体部分,解码后为
{
"alg": "Ed25519",
"typ": "JWT"
}
{
"iss": "did:abt:zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"iat": 1548703422,
"nbf": 1548703422,
"exp": 1548803422,
"version": "1.0",
"challenge": "F16E730BFB914FA1",
"appInfo": {
"name": "The name of the application",
"description": "The description of the application.",
"logo": "https://example-dapp/logo"
},
"action": "responseAuth",
"url": "https://example-app/auth",
"requestedClaims": [
{
"type": "profile",
"description": "Please fill in basic information.",
"items": ["fullName", "mobilePhone", "mailingAddress"]
},
{
"type": "agreement",
"description": "The user data usage agreement.",
"meta": {
"name": "user_agreement",
},
"uri": "https://document-1.io",
"hash": {
"method": "sha2",
"digest": "The hash result of the document's content"
}
},
{
"type": "agreement",
"description": "The service agreement",
"meta": {
"name": "service_agreement"
},
"uri": "ipfs://document-2",
"hash": {
"method": "sha3",
"digest": "The hash result of the document's content"
}
}
]
}
meta:作为每个请求声明中的一个可选字段,钱包 必须 将其原样返回给 DApp。description: 向最终用户显示的描述。
因此,在此示例中,DApp 要求钱包提供用户的一些基本信息。钱包将提示用户完成这些信息提供,并将其返回给 DApp。我们将在下一节中讨论如何处理各类信息请求。
终止认证流程#
若要结束认证工作流,你可以按如下方式发送最终响应:
{
"alg": "Ed25519",
"typ": "JWT"
}
{
"iss": "did:abt:zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"iat": 1548703422,
"nbf": 1548703422,
"exp": 1548803422,
"version": "1.0",
"challenge": "F16E730BFB914FA1",
"appInfo": {
"name": "The name of the application",
"description": "The description of the application.",
"logo": "https://example-dapp/logo"
},
"status": "ok",
"successMessage": "success message"
"response": {
"key": "value"
}
}
或者你可以返回一条错误消息,例如:
{
"status": "error",
"errorMessage": "error message"
}
将一些数据回传至 Wallet 以实现持久化:
{
"status": "ok",
"response": {
"disposition": "attachment",
"type": "VerifiableCredential",
"data": "json presentation of the credential"
}
}
串联多个工作流#
如果您希望钱包在当前工作流完成后继续处理其他工作流,可以将后续工作流的 deeplink 包含在最终响应中。例如:
{
"alg": "Ed25519",
"typ": "JWT"
}
{
"iss": "did:abt:zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"iat": 1548703422,
"nbf": 1548703422,
"exp": 1548803422,
"version": "1.0",
"challenge": "F16E730BFB914FA1",
"appInfo": {
"name": "The name of the application",
"description": "The description of the application.",
"logo": "https://example-dapp/logo"
},
"nextWorkflow": "https://didWallet.io/i?action=requestAuth&url=https://example-dapp.io/next/workflow/"
}
拒绝 DID Connect#
在某些情况下,如果用户选择拒绝来自 DApp 的请求,钱包应将此拒绝情况告知 DApp,以提供更优质的用户体验。具体操作是将 action 字段设置为 declineAuth,并使 requestedClaims 字段保持为空。
{
"iss": "did:abt:zNKtCNqYWLYWYW3gWRA1vnRykfCBZYHZvzKr",
"iat": 1548703422,
"nbf": 1548703422,
"exp": 1548803422,
"version": "1.0",
"action": "declineAuth",
"challenge": "F16E730BFB914FA1",
"requestedClaims": []
}
撤销 DID 认证#
待定
可验证声明#
可验证声明是一份包含多项声明的清单。不同类型的声明,即便设计初衷旨在服务于不同的应用场景,却共享着一些共同属性。
type: 该字段是用于标识声明项类型的必填字段。description: 供最终用户显示的消息,为所有类型声明项的必填字段。为节省网络带宽,钱包在返回声明时可省略此字段。meta: 是适用于所有类型声明项的可选字段。DApp 可在其内放置信息,以便轻松处理 DID Wallet 返回的声明。DID Wallet 必须 在每个声明项中原样返回此字段。
支持的声明类型,具体如下:
认证主体#
这是 DApp 首次提出的声明,旨在通知 钱包 为整个身份验证过程设置身份验证主体。该身份验证主体即为 钱包 发送的 JWT 载荷中的 iss 字段。
为了让 DID Wallet 配置认证主体,DApp 应向其响应此声明。通常情况下,authPrincipal 声明会静默完成,用户无需察觉。但 DApp 也可以通过在声明中将 supervised 字段设为 true,来要求 DID Wallet 显示连接界面:
{
"requestedClaims": [
{
"type": "authPrincipal",
"description": "Please set the authentication principal.",
"supervised": true
}
]
}
有时,DApp 可能希望 DID 钱包证明其为特定用户。在这种情况下,DApp 可以在声明项中添加字段 target。DID 钱包必须将认证主体设置为该特定 DID。
{
"requestedClaims": [
{
"type": "authPrincipal",
"description": "Please set the authentication principal to start this atomic swap.",
"target": "did:abt:z1fw9Ycbb7cJnj1NUm6hyuSYHuTHEwph8yH",
"supervised": false
}
]
}
有时 DApp 可能希望钱包生成一个带有自定义参数的 DID,DApp 可以在声明项中添加以下字段:
{
"requestedClaims": [
{
"type": "authPrincipal",
"description": "Please generate an application account with the following settings",
"declareParams": {
"moniker": "application_moniker",
"issuer": "z1fw9Ycbb7cJnj1NUm6hyuSYHuTHEwph8yH"
},
"targetType": {
"role": "application",
"hash": "sha3",
"key": "ed25519"
},
"supervised": false
}
]
}
默认情况下,所有 DID 均以
base58_btc格式编码。
钱包将根据 targetType 设置生成一个新的 DID,并确保在回应声明之前,该 DID 已通过 `declareParams` 完成声明。钱包仅需随机生成该 DID 的密钥对。
简介#
个人资料作为一种可验证声明,用于收集用户的姓名、电子邮件、年龄等基本信息。所请求的具体信息被定义在 items 子字段中。例如,当 DApp 需要用户提供其名、手机号码和邮寄地址时,可以采用以下方式向 Wallet 发出一个声明。
{
"requestedClaims": [
{
"type": "profile",
"description": "Please provide the basic information.",
"items": ["fullName", "mobilePhone", "mailingAddress"]
}
]
}
钱包应通过以下方式回应此请求:
{
"requestedClaims": [
{
"type": "profile",
"fullName": "Alice Bean",
"mobilePhone": "123456789",
"mailingAddress": {
"addressLine1": "456 123th AVE",
"addressLine2": "Apt 106",
"city": "Redmond",
"state": "WA",
"postalCode": "98052",
"country": "USA"
}
}
]
}
请参阅 附录,查看完整的资料项列表。
协议#
协议是另一种常用的声明类型。它代表着 DApp 要求用户签署的协议。一个 agreement 声明类型包含以下字段:
uri: URI 用于指定协议内容。hash: 一个对象,其method子字段用于指定所使用的算法(如 sha3、sha2 等),而digest子字段则为哈希值。agreed: 由 DID Wallet 添加的布尔值,用于表明用户是否同意该协议。sig:hash的 DSA 签名。
DApp 若需用户签署协议,应在响应中包含此类声明项列表。
{
"requestedClaims": [
{
"type": "agreement",
"description": "The user data usage agreement.",
"meta": {
"name": "user_agreement."
},
"uri": "https://document-1.io",
"method": "sha2",
"digest": "The hash result of the document's content"
},
{
"type": "agreement",
"description": "The service agreement",
"meta": {
"name": "service_agreement"
},
"uri": "ipfs://document-2",
"method": "sha3",
"digest": "The hash result of the document's content"
}
]
}当收到此响应时,DID Wallet 应提示用户签署协议。随后,DID Wallet 应将已签署的声明项列表提交回DApp。如果用户同意,DID Wallet 应添加 agreed 字段和 sig 字段。如果用户拒绝,则 DID Wallet 只需添加值为 false 的 agreed 字段。此情况下无需签名。
{
"requestedClaims": [
{
"type": "agreement",
"uri": "https://document-1.io",
"method": "sha2",
"digest": "The hash result of the document's content",
"meta": {
"name": "user_agreement."
},
"agreed": true,
"sig": "user's signature against the doc digest plus AGREED."
},
{
"type": "agreement",
"uri": "ipfs://document-2",
"method": "sha3",
"digest": "The hash result of the document's content",
"meta": {
"name": "service_agreement"
},
"agreed": false
}
]
}资产#
资产声明项旨在让钱包向 DApp 提供一个链上 Asset DID。通常,DApp 需结合签名和链上资产状态,对资产所有权进行核验。因此,若需钱包提供 Asset DID,DApp 应当遵循以下方式发送声明:
filters:必填字段,用于指定 Wallet 选择资产所依据的筛选条件列表。若指定了多个筛选条件,它们之间应视为逻辑OR关系;同一筛选条件内的多个字段,则应视作逻辑AND关系;一个字段中的多个值,则应视作逻辑OR关系。每个筛选条件可包含以下任一参数:trustedIssuers: 受信任发行者的 DID 列表,默认为空列表trustedParents:受信任的父 DID 列表,通常指 NFT 工厂地址,默认为空列表。tag: 资产标签,用于筛选,默认为空address: 资产的 DID,无论是链上还是链下;默认为空字符串。
optional:此字段指示用户是否可以跳过此声明。若optional为 true,则声明响应可以为空。该optional字段默认为 false。
{
"requestedClaims": [
{
"type": "asset",
"description": "Please provide the coupon you own.",
"optional": false,
"filters": [
{
"address": "zje1uzZTCZN551EWGLyyCEW9AM2wAdjymfHb"
},
{
"trustedIssuers": ["zje1uzZTCZN551EWGLyyCEW9AM2wAdjymfHb"],
"tag": "abcd"
},
{
"trustedParents": ["zje1uzZTCZN551EWGLyyCEW9AM2wAdjymfHb"],
"tag": "abcd"
},
{
"trustedIssuers": ["zje1uzZTCZN551EWGLyyCEW9AM2wAdjymfHb"],
"trustedParents": ["zje1uzZTCZN551EWGLyyCEW9AM2wAdjymfHb"],
"tag": "abcd"
}
],
"meta": {}
}
]
}钱包应以如下方式返回响应:
{
"requestedClaims": [
{
"type": "Asset",
"asset": "did:abt:zje1uzZTCZN551EWGLyyCEW9AM2wAdjymfHb",
"ownerDid": "NFTOwner.address",
"ownerPk": "toBase58(NFTOwner.publicKey)",
"ownerProof": "toBase58(NFTOwner.sign(challenge))",
"meta": {}
}
]
}asset指的是用户所持有的链上资产地址,该用户可以是同一钱包内的任意有效用户。ownerDid指的是链上资产所有者的 DID,其应始终包含在内,因为链上资产所有者有时可能与会话 `userDid` 不同。ownerPk是链上资产所有者的公钥,该字段应始终被包含,因为在某些情况下所有者的公钥无法通过其他途径获取。ownerProof是链上资产所有者针对会话挑战所作的签名。
签名#
签名是 **DID Wallet** 与 DApp 之间一种常见的验证凭证。当 DApp 需要引导 **DID Wallet** 用户完成某项业务操作时,通常最终会涉及对交易进行签名并将其广播到区块链。在这种情况下,DApp 通常会组装一笔交易,并发送给用户请求签名。DApp 应该将交易的原始完整负载和类型 URL 发送至 **DID Wallet**,以便 **DID Wallet** 能够验证哈希并向用户显示交易详情。
除所有声明项共有的通用字段外,签名声明项还包含以下额外字段:
typeUrl:该字段指明了此交易的类型 URL,有助于 Wallet 解码并显示原始交易。origin: 交易的 Base58 编码有效载荷。此有效载荷需通过typeUrl进行解码。method:用于生成origin消息摘要的哈希方法。此值应与用户 DID 中的哈希方法一致。digest:origin的消息摘要。此为钱包签名的数据。钱包将验证此摘要是否与原始数据匹配。display: 交易执行后用户将获得结果的视觉呈现。sig: 待返回的签名。
{
"requestedClaims": [
{
"type": "signature",
"description": "Please sign this exchange transaction.",
"typeUrl": "fg:t:transaction",
"origin": "base58 encoded data",
"method": "sha3",
"display": "JSON stringified display info",
"digest": "base58 encoded digest",
"meta": {
"id": 12345
}
}
]
}
钱包应以如下格式返回签名:
{
"requestedClaims": [
{
"type": "signature",
"typeUrl": "fg:t:transaction",
"origin": "base58 encoded data",
"method": "sha3",
"digest": "base58 encoded digest",
"meta": {
"id": 12345
},
"sig": "the value to return"
}
]
}
已知 typeUrl 列表:
fg:t:transaction:需要 Wallet 将原始数据解码为交易并签名。mime:text/plain: 钱包需要将原始内容解码为文本并展示给用户。mime:text/html:钱包需将原始数据解码成 HTML 内容并展示给用户。eth:transaction: 钱包需将原始数据解码为 JSON 字符串,其格式如下:{钱包将利用此 JSON 数据生成并发送一笔以太坊(ETH)交易。交易发送前,钱包须向用户展示交易详情,并要求用户输入密码进行二次确认,方可最终发送。
"network": 1, // 以太坊网络 ID
"tx": {
"to": "<eth address>",
"value": "<number string>", // 例如:"10000000000000000" 等价于 0.1 ETH
"gasLimit": "<number string>", // 例如:25100, 80000等
"data": "xxxx" // 如果这不是合约调用,请传入空字符串
}
}
准备交易#
prepareTx 通常用于 DApp 需要 Wallet 支付特定数量的通证以完成某个业务流程的场景。在这种情况下,DApp 知晓应发送何种交易,但尚不清楚组装交易所需的某些参数。DApp 会首先组装一个部分交易,并附带支付要求,将其发送给 Wallet。Wallet 收到后,会确定应使用哪些账户支付该交易,然后组装完整的交易,以便在界面上展示并等待用户签名。经用户确认后,Wallet 会将包含签名的完整交易提交给 DApp 进行广播。
除了各类声明项的共有字段外,prepareTx 声明项还包含以下额外字段:
partialTx: 部分交易的 Base58 编码结果。提交时,钱包不得修改该编码结果。要求: 该交易的支付要求。钱包在提交时应保持其不变。requirement.tokens:这是一个列表,用于指定各代币地址所需的数量。对于主代币,其代币地址应留空。如果该列表被设置为空数组,则表示此交易不需要任何代币。requirement.assets: 是一个供 DID Wallet 选取资产列表的对象,支持通过地址或父地址进行筛选。当设置为空对象时,表示该交易无需任何资产。
finalTx:最终签名交易的 Base58 编码结果,无需任何进一步操作即可广播到区块链。钱包可以更改以下字段以创建最终交易:tx.signatures和tx.signature和tx.itx.inputs:如果交易需要由多个账户支付tx.from和tx.delegator:若交易需经委托完成
display: 对交易执行后用户所得内容的视觉呈现。
{
"requestedClaims": [
{
"type": "prepareTx",
"description": "Please pay 2 ABT to buy VIP",
"partialTx": "base58 encoded partial tx",
"display": "JSON stringified display info",
"requirement": {
"tokens": [
{
"address": "TOKEN_ADDRESS",
"value": "TOKEN_AMOUNT_AS_BIG_NUMBER_STRING"
}
],
"assets": {
"address": ["LIST_OF_SPECIFIC_ASSETS"],
"parent": ["LIST_OF_ASSET_PARENTS"],
"amount": 2
}
},
"meta": {
"orderId": 12345
}
}
]
}
钱包将以如下格式返回最终交易:
{
"requestedClaims": [
{
"type": "prepareTx",
"partialTx": "base58 encoded partial tx",
"finalTx": "base58 encoded final tx",
"requirement": {
"tokens": [
{
"address": "TOKEN_ADDRESS",
"value": "TOKEN_AMOUNT_AS_BIG_NUMBER_STRING"
}
],
"assets": {
"address": ["LIST_OF_SPECIFIC_ASSETS"],
"parent": ["LIST_OF_ASSET_PARENTS"],
"amount": 2
}
},
"meta": {
"orderId": 12345
}
}
]
}
证书#
证书的核心是由颁发者签名的 JWT 令牌。
{
"type": "certificate",
"content": "eyJhbGciOiJFZDI1NTE5IiwidHlwZSI6IkpXVCJ9.eyJhZ2VudERpZCI6ImRpZDphYnQ6ek5LcnJQSHdCbnlWb01WWjZaRnRwcW5MR3NDUVh3aXNFdTZqIiwiZXhwIjoxNjA1MDg3MjQyLCJpYXQiOjE1NzM1NTEyNDIsImlzcyI6ImRpZDphYnQ6ek5LZzVweGNaUExvZFJBYTVZcGJoQTRtTWZIdzlRRHFyNjVzIiwibmJmIjoxNTczNTUxMjQyLCJvcHMiOnsicHJvZmlsZSI6WyJmdWxsTmFtZSIsIm1vYmlsZVBob25lIiwibWFpbGluZ0FkZHJlc3MiXX0sInZlcnNpb24iOiIxLjAifQ.3O08a7Dgqlebg-2Pu6eZQ2hOsUdjqCu6yE7DsDKUXI18D2bf6hWOpiGvT2wkIAZyvFdiiD0kQm1PgKXcXLTeBw"
}
令牌负载如下:
{
"iss": "The issuer's did of the certificate.",
"pk": "The pk of the issuer",
"agentDid": "To whom the certificate is issued.",
"iat": 1548703422,
"nbf": 1548703422,
"exp": 1548803422,
"ops": {
"profile": ["fullName", "mobilePhone", "mailingAddress"],
"agreement": ["digest of agreement one", "digest of agreement two"]
}
}
可验证凭证#
DApp 使用此声明来验证钱包是否持有所需的有效可验证凭证。
filters是必填字段,用于指定筛选器列表,以供 Wallet 选择可验证凭证。若指定多个筛选器,它们之间应按OR逻辑进行解释;而单个筛选器内的多个字段,则应按AND逻辑进行解释;单个字段内的多个值,则应按OR逻辑进行解释。每个筛选器可包含以下任一参数:trustedIssuers: 受信任发行者的 DID 列表,默认为空列表type:有效可验证凭证类型列表,默认为空列表tag: 可验证凭证标签,默认为空- target: 可验证凭证的 DID,可以是链上或链下,默认为空字符串
optional字段允许用户跳过此声明。如果optional设为 true,则声明响应可为空。该optional字段默认值为 false。
{
"requestedClaims": [
{
"type": "verifiableCredential",
"description": "Please provide the coupon you own.",
"optional": false,
"filters": [
{
"trustedIssuers": ["did:abt:z1RuF9Xa2AUTJ3VHZKy2xroKzphwWKsLrY6"],
"type": ["ServerOwnershipNFT"],
"tag": "extra tag to filter credential"
},
{
"trustedIssuers": ["did:abt:z1RuF9Xa2AUTJ3VHZKy2xroKzphwWKsLrY6"],
"type": ["BlockletServerPassport"]
},
{
"trustedIssuers": ["did:abt:z1RuF9Xa2AUTJ3VHZKy2xroKzphwWKsLrY6"],
"type": ["BlockletServerPassport"]
},
{
"target": "did:abt:z1RuF9Xa2AUTJ3VH"
}
],
"meta": {}
}
]
}返回
{
"requestedClaims": [
{
"type": "verifiableCredential",
"presentation": "xxxx",
"assetDid": [""]
}
]
}什么是演示
{
"@context": ["https://achema.arcblock.io/v0.1/context.jsonld"],
"challenge": "F16E730BFB914FA1",
"type": ["VerifiablePresentation"],
"verifiableCredential": [{}],
"proof": [{}]
}证明的生成过程与可验证凭证相同。一次呈现可以包含多个VC,如果VC来自不同的DID,则该呈现必须提供多个证明。挑战则来自于DID Auth JWT。
证明的结构是
{
"type": proofTypes[typeInfo.pk],
"created": new Date().toISOString(),
"proofPurpose": "assertionMethod",
"pk": "vc recipience's PK base58",
"jws": toBase64(signature)
}签名由 VC 持有者的私钥签署。
使用场景#
DID Connect 协议是一种通用的点对点协议,可用于任何需要身份验证的场景。它可用于但不限于以下场景:
- 用户注册。
- 用户登录。
- 签署文件。
- 申请/签发证书。
- 申请签证。
- 点对点信息交换。