连接和登录合成一次弹窗:CAIP-222 的 wallet_authenticate 把两步并作一步 图 1
连接和登录合成一次弹窗:CAIP-222 的 wallet_authenticate 把两步并作一步 · 图 1

老流程为什么要走两步

网站想确认「这个钱包地址真的是你的」,过去的标准动作分两截:第一步,应用请求连接钱包,拿到你在某条链上的地址;第二步,应用再发一个签名请求,让你对一条写着域名、随机数、有效期的验证消息签字,服务端验签通过才算登录完成。两截式流程的问题不在安全,而在体验和时序:连接时钱包并不知道对方想让你登录,签名时应用又必须先知道你的地址才能构造消息,于是一连串先后依赖全压在开发者身上。CAIP-10账户ID为什么必须带链? 讲的正是这条依赖的底层原因——地址离开链标识就说不清是谁的地址。

连接和登录合成一次弹窗:CAIP-222 的 wallet_authenticate 把两步并作一步 图 2
连接和登录合成一次弹窗:CAIP-222 的 wallet_authenticate 把两步并作一步 · 图 2

打包成一条方法

编号 222 的链无关协议(CAIP-222)把上述两个请求合并为一条 JSON-RPC 方法 wallet_authenticate。按原文的说法,它的卖点是「在尚未获知区块链账户的情况下」就能发起:应用直接提交一组登录参数,钱包弹窗让用户挑一个(或几个)账户来签,返回零个、一个或多个签名结果。规范在 frontmatter 里声明依赖编号 2、10、74、122 四个协议,也就是链标识、账户标识、CACAO 能力对象与登录签名数据模型;写作时该提案的状态是 Draft(草案),并非所有钱包都已实现。

参数表逐项读

请求参数里,chains 是一串 CAIP-2 风格的链标识,说明这次登录授权到哪些网络;domain 是发起签名请求的域名 authority,钱包必须核对请求真的来自这个域名;aud 是登录页的 URI;nonce 是防签名重放的随机令牌;iat 标注签发时间,expnbf 两个可选字段框定这条签名的有效时间窗,都按 RFC 3339 写成日期时间。可读文本 statement 如果存在则不允许包含换行。最有特色的是可选的 signatureTypes:调用方按命名空间列出自己能接受的签名算法,例如 eip155 下列 eip191eip1271cosmos 下列 amino。原文特别提醒:不写这个字段等于默认什么都接受,某些场景会得到不稳定的行为。

返回结构与两个错误码

用户批准后,钱包返回一列签名好的 CACAO 对象,每个对应一个被授权的账户。每个对象分三层:h 是头部,记录消息类型;p 是载荷,其中 issdid:pkh 形式的去中心化身份标识写出具体是哪个链上的哪个账户,其余字段必须与请求里的参数逐项一致;s 是签名,带上签名类型与签名字节。请求失败只有两个规定错误码:用户拒绝是 6000「User Rejected Request」,参数校验不过去是 6001「Invalid Request Params」。还有一条容易忽略的规则:请求里列的链如果钱包不支持,钱包应当忽略不支持的部分,只要还剩支持的链可以继续签,就不该自动替你拒绝整个请求。

用户视角:弹窗里该核对什么

对普通用户来说,这条方法改变的是弹窗出现的方式:以前你先「连接」、再被要求「签名登录」,现在一次弹窗完成两件事。核对要点不变,而且更重要——第一看发起域名是否与你正在访问的站点一致,规范在安全章节明确要求钱包通过域绑定核验来源,防止别的页面借壳发起登录签名;第二看时间窗和 nonce 是否存在,缺了这两样,签出来的东西理论上可被反复使用;第三理解签名的后果:规范的隐私章节直言,这条方法在验证归属的同时也把该地址暴露给了应用,对方此后可以索引与这个地址相关的链上历史。若一个只让你「登录看看」的站点还顺带要求长期会话,那已经超出本方法的设计范围,可按 钱包连接过的网站清单怎么清:断开连接和撤销授权是两件事 的思路把连接清单单独清一遍。

边界:草案、社交场景与相邻标准

CAIP-222 的动机章节写得很坦白:它瞄准的是不需要持久会话、只需一次签名确认账户归属的社交类应用,开发者得到的验证能力与 OAuth、OIDC 这类传统认证标准类似。它并不取代「连接后持续收发消息和交易请求」的那套会话协议——那属于 CAIP-25 一族;也不定义登录消息本身长什么样——那是编号 122 的 SIWx 数据模型,见《登录消息到底让你签了什么:CAIP-122 的 SIWx 数据模型逐项拆》。三者拼起来才是完整的钱包登录图景:122 管签什么,222 管怎么一次签完,25 管签完之后连不连。截至本文按原始文本仓库核验时它仍是草案,读写入实现名单前应以规范仓库现状为准。