FIDO Server

此模块包含 FIDO Server 对接的相关接口,用于提供 Web 服务器快速支持 WebAuthn 认证的能力。

首先,在 WebAuthn 的注册和认证过程中。每个过程均需要调用两个接口,我们称为 xxxOptionsxxxResult

  1. xxxOptions 是获取本次操作的挑战,称为 challenge
  2. xxxResult 是应对改挑战产生的结果

就比如,一个登录过程是这样的:

  1. 首先,输入用户名,点击 WebAuthn 登录。
  2. 前端会通过 xxxOptions 获取 challenge
  3. 前端将获取到的 challenge 调用浏览器接口 credential.create()
  4. 浏览器弹出 WebAuthn 认证窗口
  5. 认证器得到相关的提示,进行认证,返回认证结果
  6. 前端将认证结果通过 xxxResult 提交到后端
  7. 后端调用 FIDO Server 接口进行确认
  8. 后端返回结果到前端,结束

这里用伪代码形式示例调用过程。

创建客户端

import (
	"github.com/trustasia-com/go-sdk/pkg/credentials"
	"github.com/trustasia-com/go-sdk/webauthn"
)

opts := credentials.Options {
    AccessKey: "accessKey",
    SecretKey: "secretKey",
    Endpoint: "https://api.wekey.com",
    SignerType: credentials.SignatureDefault,
}

// sess会自动处理签名
sess, err := credentials.New(opts, false)
if err != nil {
	return err
}
webauthnCli := webauthn.New(sess)

添加注册接口

func handleAttestationOptions(w http.ResponseWriter, r *http.Request) {
    // 通过某种方式查询到用户ID,如从cookie里获取到的
    userID := "..." or username := "..."
    // 查询到用户
    user := selectUser(userID)

    // 将 userID 进行 hex 编码
    uid := hex.EncodeToString(userID)
    // 构建注册请求
    req := webauthn.StartSignUpReq {
        Username: user.Username,
        DisplayName: user.Nickname,
        // ...
    }
    // 调用 SDK 方法
    data, err := webauthnCli.StartSignUp(req, uid)
    if err != nil {
        // 打印日志
        log.Error(err)
        // TODO 错误处理
        return
    }
    // 成功,返回合适格式将data带回去
    w.WriteHeader(200)
    w.Write(data)
}

func handleAttestationResult(w http.ResponseWriter, r *http.Request) {
    // 从body里读区data
    data, err := io.ReadAll(r.Body)
    if err != nil {
        // TODO 错误处理
        return
    }
    // 调用 SDK 接口
    data, err := webauthnCli.FinishSignUp(r)
    if err != nil {
        // TODO 错误处理
        return
    }
    // 将结果返回
    w.WriteHeader(200)
    w.Write(data)
}

添加认证接口

func handleAssertionOptions(w http.ResponseWriter, r *http.Request) {
    // 比如登录时传过来的username
    user := selectUserByUsername(username)

    req := webauthn.StartSignInReq{
        Username: user.Username,
        DisplayName: user.Nickname,
        // ...
    }
    // 将userID hex编码
    uid := hex.EncodeToString(user.ID)

    data, err := webuathnCli.StartSignIn(req, uid)
    if err != nil {
        // TODO 错误处理
        return
    }
    // 返回数据
    w.WriteHeader(200)
    w.Write(data)
}

func handleAssertionResult(w http.ResponseWriter, r *http.Request) {
    data, err := webauthnCli.FinishSignIn(r)
    if err != nil {
        // TODO 错误处理
        return
    }
    // 数据返回
    w.WriteHeader(200)
    w.Write(data)
}

具体demo请参考这里:WebAuthn Demo