Fido扫码认证

FIDO扫码认证

FIDO扫码认证解决了什么问题?我们知道FIDO2的组成:WebAuthn+CTAP。其中CTAP规范了WebAuthn数据如何到达FIDO认证器端。但就目前比较通用的形势有:

  1. BLE
  2. NFC
  3. USB

这几种方式有什么问题:

  1. 需要设备支持,但不一定每个设备都有NFC或者BLE
  2. 基于USB的FIDO设备,一般是硬件形态,容易丢失,硬件漏洞难以修复
  3. BLE协议被发现不够安全,Apple、Google等浏览器和平台都不支持
  4. iOS与Android手机系统有平台限制,不能够很好的跨平台

那么WeKey做了什么?WeKey同样是基于FIDO2标准。实现了标准的认证器与FIDO Server。为了支持FIDO扫码认证,同样WeKey实现了标准FIDO Client。

架构设计

我们这里将需要对接扫码认证的服务称为RP。WeKey提供后台控制台供客户为RP创建密钥用于对接。当RP接入到WeKey认证系统,即可以快速支持基于FIDO的扫码认证。

fido-scan-architecture

开始对接

所有接口均采用 签名机制 进行鉴权,后续不再赘述,建议通过 SDK 进行对接。

后端整个过程对接需要涉及到两个过程:

  1. 注册凭证
    • 预注册
    • 注册
  2. 验证凭证
    • 预认证
    • 认证

接口调用Host:https://api.wekey.com/ta-app

注册凭证

凭证的注册意味凭证的存储,WeKey提供两种存储方式:用户的手机或HSM云存储,

当用户选择将凭证存储在自己的手机中时,凭证的所有信息,WeKey将不会获取,凭证信息将会存储在用户手机的专用安全芯片中,同时也意味着用户更换设备登录, 将无法使用该凭证进行认证操作。

当用户选择HSM云存储时,WeKey会将凭证的信息存储存储在HSM服务中,同样地,在专业的云HSM存储下,WeKey无法获取用户凭证的私钥信息,用户更换设备后, 依旧可以同步并使用该凭证,选用云HSM方式存储凭证既安全又便捷,WeKey推荐您优先选择HSM。

流程如下:

fido-scan-register

简述:

  1. 用户发起注册凭证的请求,RP根据用户信息向WeKey发起预注册凭证的请求
  2. WeKey将响应RP消息地址和该次请求的过期时间,以便RP处理逻辑
  3. RP将消息地址转化为二维码展示,同时开始根据过期时间获取认证结果
  4. 用户使用WeKey的APP在RP处进行扫码,获取认证的信息
  5. 用户在APP上完成授权,同时上传结果至WeKey
  6. WeKey响应RP认证的结果
预注册

获取用于APP扫描的二维码信息。

调用方式:POST,调用地址:/rp/attestation/options

请求参数(body):

字段 类型 选项 说明
user_id string 必填 用户id,需要在您系统内可以唯一标识该用户的
username string 必填 用户名
credential_name string 可选 创建的凭证名字,不填则由WeKey随机生成,建议填写,方便用户标识
display_name string 可选 用户昵称 可选

响应参数:

字段 类型 说明
url string 消息地址,请转化为二维码以便WeKey APP扫码
expires_at int 请求过期时间,时间戳,单位秒

请求示例:

{
  "user_id": "testuserid",
  "username": "jack",
  "credential_name": "my cred",
  "display_name": "imjack"
}

成功响应:

{
  "code": 0,
  "data": {
    "url": "https://get.wekey.com#0cdq8va3tlntsv8hko530",
    "expires_at": 1668583416
  },
  "error": ""
}
注册

通过轮询接口的形式判断手机端是否认证成功。

调用方式:GET,调用地址:/rp/attestation/result?msg_id=xxx

请求参数(query):

字段 类型 选项 说明
msg_id string 必填 消息的ID,由预注册接口返回的url解析而来,解析方式:先对url进行字符串分割(以“#”为分割),取后半部分的字符串,去除第0位即为消息的id。如: https://get.wekey.com#0cdq8va3tlntsv8hko530 解析后的msg_id即为:cdq8va3tlntsv8hko530

响应参数:

字段 类型 说明
wekey_user string 扫码人的信息,可展示在页面方便提示用户
status string 当前认证状态,init:消息初始化,无人扫码,bind:表示已经有人扫码,此时 wekey_user有值,success:表示用户已授权, 此次认证成功,fail:表示此次认证失败 timeout:表示该次认证已超时,无人认证。请注意,success和fail状态只会出现一次,如果解析到这两种状态时,请结束轮询该接口
error string 当为fail时,该字段有值,用以告知具体的错误信息

示例请求:

GET   https://api.wekey.com/ta-app/rp/attestation/result?msg_id=cdq8va3tlntsv8hko530

成功响应:

{
  "code": 0,
  "data": {
    "wekey_user": "133****2345",
    "status": "bind",
    "error": ""
  },
  "error": ""
}

认证

认证即使用免密方式验证用户的身份,可选用扫码认证或推送认证的方式进行,由RP进行自主选择。

流程如下:

fido-scan-login

简述:

  1. 用户发起认证的请求,RP根据用户信息向WeKey发起预认证凭证的请求
  2. WeKey将响应RP消息地址和该次请求的过期时间,以便RP处理逻辑
  3. RP将消息地址转化为二维码展示,同时开始根据过期时间获取认证结果
  4. 用户使用WeKey的APP在RP处进行扫码,获取认证的信息
  5. 用户在APP上完成授权,同时上传结果至WeKey
  6. WeKey响应RP认证的结果
预认证

获取用于APP扫描的二维码信息或者推送到手机端。

调用方式:POST,调用地址:/rp/assertion/options

请求参数(body):

字段 类型 选项 说明
user_id string 必填 用户id,需要在您系统内可以唯一标识该用户的
username string 必填 用户名
method string 必填 认证方式,请填qrcode或push,当值为qecode时,WeKey会返回认证的url,不会进行推送,当为push时,WeKey将会把认证请求推送到用户手机上

响应参数:

字段 类型 说明
url string 消息地址,请转化为二维码以便WeKey APP扫码
expires_at int 请求过期时间,时间戳,单位秒

示例请求:

{
  "user_id": "testuserid",
  "username": "jack",
  "method": "push"
}

成功响应:

{
  "code": 0,
  "data": {
    "url": "https://get.wekey.com#1cdq8va3tlntsv8hko530",
    "expires_at": 1668583416
  },
  "error": ""
}
认证

用户请求认证时,用于获取认证的结果

调用方式:GET,调用地址:/rp/assertion/result?msg_id=xxx

请求参数(query):

字段 类型 选项 说明
id string 必填 消息的ID,由预注册接口返回的url解析而来,解析方式:先对url进行字符串分割(以“#”为分割),取后半部分的字符串,去除第0位即为消息的id。如: https://get.wekey.com#0cdq8va3tlntsv8hko530 解析后的id即为:cdq8va3tlntsv8hko530

响应参数:

字段 类型 说明
wekey_user string 扫码人的信息,可展示在页面方便提示用户
status string 当前认证状态,init:消息初始化,无人扫码,bind:表示已经有人扫码,此时 wekey_user有值,success:表示用户已授权, 此次认证成功,fail:表示此次认证失败 timeout:表示该次认证已超时,无人认证。请注意,success和fail状态只会出现一次,如果解析到这两种状态时,请结束轮询该接口
user_id string 如果认证成功,该字段会有值,为注册凭证时的user id
error string 当为fail时,该字段有值,用以告知具体的错误信息

示例请求:

GET  https://api.wekey.com/ta-app//rp/assertion/result?msg_id=cdq8va3tlntsv8hko530

成功响应:

{
  "code": 0,
  "data": {
    "wekey_user": "133****2345",
    "status": "success",
    "error": "",
    "user_id": "jack"
  },
  "error": ""
}

查询凭证

查询凭证,用于RP处显示用户注册过的凭证

调用方式:GET,调用地址:/rp/credentials

请求参数(query):

字段 类型 选项 说明
user_id string 必填 query参数,用户id,需要在您系统内可以唯一标识该用户的

响应参数:

字段 类型 说明
credential_id string 凭证id,删除凭证时可用
credential_name string 凭证名,创建时填写的
user_id string 用户id
created_at string 凭证创建时间,RFC3339格式
updated_at string 凭证最近使用时间,RFC3339格式

请求示例:

GET  https://api.wekey.com/ta-app/rp/credentials?user_id=jack

成功响应:

{
  "code":0,
  "data":{
    "total":1,
    "list":[
      {
        "credential_id":"cred id",
        "credential_name":"cred name",
        "user_id":"jack",
        "created_at":"2022-11-07T00:00:00Z",
        "updated_at":"2022-11-07T00:00:00Z"
      }
    ]
  },
  "error":""
}

删除凭证

用于用户删除凭证

调用方式:DELETE,调用地址:/rp/credentials

请求参数(body):

字段 类型 选项 说明
user_id string 必填 query参数,用户id,需要在您系统内可以唯一标识该用户的
credential_ids []string 必填 凭证id的数组,查询列表可获得

响应参数:

字段 类型 说明
total int 删除成功的数量

示例请求:

{
  "user_id":"testuserid",
  "credential_ids":[
    "cred1",
    "cred2"
  ]
}

成功响应:

{
  "code":0,
  "data":{
    "total":2
  },
  "error":""
}