生物识别(WebAuthn)接入

本文介绍 WebAuthn 的接入。

前提条件

  1. 请先完成阿里云账号注册、实名认证、开通安全认证创建应用

  2. 请完成获取阿里云访问密钥;

  3. 请确保使用的应用,已经勾选了“WebAuthn”的认证方式,请查看修改应用认证方式。

  4. Demo工程参考

WebAuthn认证器注册-初始化

webAuthn认证器注册-初始化请求,返回符合webAuthn创建身份证明的参数对象。

请求参数

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

应用外部ID,该字段在创建应用时指定,在应用详情页中查看

AuthenticatorType

String

WEBAUTHN

认证方式标识,调用WEBAUTHN认证接口时,固定值为:WEBAUTHN

UserId

String

user-test-1

用户的唯一标识, 例如:userId、手机号、邮箱等

Username

String

张三

用户名

UserDisplayName

String

小张

用户昵称

ServerExtendParamsJson

String

eyJhdHRhY2htZW50IjoicGxhdGZvcm0iLCJ1c2VyVmVyaWZpY2F0aW9uIjoicmVxdWlyZWQifQ==

webAuthn注册上下文, JSON字符串

ServerExtendParamsJson参数解析

名称

类型

必填

示例值

描述

attachment

String

platform

默认platform,可选platform,cross-platformornone

userVerification

String

required

默认required,可选discouragedorrequiredornone

返回数据

名称

类型

示例值

描述

Success

boolean

true

操作结果,true 代表成功,false 代表失败

Code

String

Opreation.Success

状态码。当 Success=true 时,Code=Operation.Success当 Success=false 时,Code的值,请参见下方错误码

Message

String

Opreation.Success

具体的描述信息,当 Success=false 时,会给出Code的对应的具体描述信息

RequestId

String

1C0EE50A-B3BB-42FD-AB59-E3FE88976982

请求ID

Data

String

{"challengeBase64":"AAAAAXzBzvy0MTIzMjMxMjMxMg==","requestId":"2D503C0A-57FB-556E-B7BD-5E117EFA1541","options":"{\"attestation\":\"none\",\"authenticatorSelection\":{\"userVerification\":\"required\"},\"challengeBase64\":\"AAAAAXzBzvy0MTIzMjMxMjMxMg==\",\"excludeCredentials\":[],\"pubKeyCredParams\":[{\"alg\":-7,\"type\":\"public-key\"},{\"alg\":-257,\"type\":\"public-key\"}],\"rp\":{\"id\":\"localhost\",\"name\":\"测试(\"},\"timeout\":60000,\"user\":{\"displayName\":\"1232312312\",\"id\":\"1232312312\",\"name\":\"1232312312\"}}"}

操作成功时,Data中的JSON字符串包含两个字段:

  • ChallengeBase64: 字符串:防重放挑战码

  • Options:创建认证器的Options,包含webAuthn的基本信息

操作失败时,Data字段为空

请求示例

请求方式:POST

https://idaas-doraemon.aliyuncs.com/?Action=CreateAuthenticatorRegistration
&Version=2021-05-20
&ApplicationExternalId=A0000001
&AuthenticatorType=WEBAUTHN
&UserId=user-test-1
&UserName=user-test-1
&UserDisplayName=user-test-1
&ServerExtendParamsJson=eyJhcHBJ...biI6IjEuMCJ9
&<公共请求参数>

正常返回示例 -WebAuthn注册认证器-初始化通过

{
  "Success": true,
  "Code": "Operation.Success",
  "Message": "Operation.Success",
  "RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
  "Data": {"challengeBase64":"AAAAAXzAn9aPMTIzMjMxMjMxMg==",
           "requestId":"91DBDD36-B05C-5AF1-B205-E1708EC5B792",
           "options":"{\"attestation\":\"none\",\"authenticatorSelection\":{\"userVerification\":\"required\"},\"challengeBase64\":\"AAAAAXzAn9aPMTIzMjMxMjMxMg==\",\"excludeCredentials\":[],\"pubKeyCredParams\":[{\"alg\":-7,\"type\":\"public-key\"},{\"alg\":-257,\"type\":\"public-key\"}],\"rp\":{\"id\":\"localhost\",\"name\":\"测试(勿删)\"},\"timeout\":60000,\"user\":{\"displayName\":\"1232312312\",\"id\":\"1232312312\",\"name\":\"1232312312\"}}"
           }
}

错误返回示例 - 请求参数中缺少认证方式标识

{
  "Success": false,
  "Code": "Params.Blank",
  "Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
  "RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
  "Data":null
}

WebAuthn认证器注册-验证

webAuthn认证器注册验证,用于注册webAuthn认证器,注册认证器主要工作是校验合法性、对用户ID和认证器绑定起来。

适用场景:注册场景、开启webAuthn认证用做免密登录、二次认证

请求参数

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

应用外部ID,该字段在创建应用时指定,在应用详情页中查看

AuthenticatorType

String

WEBAUTHN

认证方式标识,调用WEBAUTHN认证接口时,固定值为:WEBAUTHN

UserId

String

user-test-1

用户的唯一标识, 例如:userId、手机号、邮箱等

AuthenticatorName

String

webAuthn认证器

认证器名称

RequireChallengeBase64

String

AAAAAXzAn9aPMTIzMjMxMjMxMg==

创建认证器初始化请求返回的ChallengeBase64

ServerExtendParamsJson

String

eyJhdHRhY2htZW50IjoicGxhdGZvcm0iLCJ1c2VyVmVyaWZpY2F0aW9uIjoicmVxdWlyZWQifQ==

webAuthn注册上下文, JSON字符串

RegistrationContext

String

JS SDK生成的注册信息,JSON字符串,具体包含参数见下方RegistrationContext参数解析

UserSourceIp

String

127.0.0.1

客户端IP

RegistrationContext参数解析:

如果是webauthn,则其中RegistrationContext是一个JSON,包含以下信息:

字段

类型

备注

credentialId

String

身份证明ID,即 URI-ENCODED-BASE64(RAW_ID)

以此信息唯一标识一个webauthn认证器

type

String

当前固定是 public-key

transports

String

办理方式,由 WebAuthn 接口提供

attestationObjectBase64

String

注册认证对象

clientDataJSONBase64

String

客户端数据JSON

ServerExtendParamsJson参数解析:

WebAuthn时,ServerExtendParamsJson可以为空(即默认值),或者配置以下参数:

字段

类型

是否必选

备注

requireUserPresence

Boolean

默认值为 true,是否要求用户出席

requireUserVerification

Boolean

默认值为 true,是否要求验证用户

返回数

名称

类型

示例值

描述

Success

boolean

true

操作结果,true 代表成功,false 代表失败

Code

String

Opreation.Success

状态码。当 Success=true 时,Code=Operation.Success当 Success=false 时,Code的值,请参见下方错误码

Message

String

Opreation.Success

具体的描述信息,当 Success=false 时,会给出Code的对应的具体描述信息

RequestId

String

1C0EE50A-B3BB-42FD-AB59-E3FE88976982

请求ID

Data

String

{"authenticatorUuid": "1C0EE50AB3BB42FDAB59E3FE88976982"}

操作成功时,Data中的JSON字符串包含1个字段:

  • AuthenticatorUuid: 字符串:认证器UUID

操作失败时,Data字段为空

请求示例

请求方式:POST

https://idaas-doraemon.aliyuncs.com/?Action=RegisterAuthenticator
&Version=2021-05-20
&ApplicationExternalId=A0000001
&AuthenticatorType=WEBAUTHN
&UserId=user-test-1
&AuthenticatorName=user-test-1
&RequireChallengeBase64="MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw=="
&ServerExtendParamsJson=eyJhcHBJ...biI6IjEuMCJ9
&RegistrationContext="xxxx"
&UserSourceIp=1.1.1.1
&<公共请求参数>

正常返回示例 -WebAuthn注册认证器-验证通过

{
  "Success": true,
  "Code": "Operation.Success",
  "Message": "Operation.Success",
  "RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
  "Data": {
  "authenticatorUuid": "1C0EE50AB3BB42FDAB59E3FE88976982"
  }
}

错误返回示例 - 请求参数中缺少认证方式标识

{
  "Success": false,
  "Code": "Params.Blank",
  "Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
  "RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
  "Data":null
}

WebAuthn认证器认证-初始化

webAuthn认证器认证-初始化请求。

请求参数

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

应用外部ID,该字段在创建应用时指定,在应用详情页中查看

AuthenticatorType

String

WEBAUTHN

认证方式标识,调用WEBAUTHN认证接口时,固定值为:WEBAUTHN

UserId

String

user-test-1

用户的唯一标识, 例如:userId、手机号、邮箱等

BindHashBase64

String

用于生成Challenge与参数BindHash绑定,在具体业务中可以和用户的一笔交易Hash绑定,也就说一次WebAuthn的认证可以和用户具体的一笔业务发生绑定关系

返回数据

名称

类型

示例值

描述

Success

boolean

true

操作结果,true 代表成功,false 代表失败

Code

String

Opreation.Success

状态码。当 Success=true 时,Code=Operation.Success当 Success=false 时,Code的值,请参见下方错误码

Message

String

Opreation.Success

具体的描述信息,当 Success=false 时,会给出Code的对应的具体描述信息

RequestId

String

1C0EE50A-B3BB-42FD-AB59-E3FE88976982

请求ID

Data

String

"challengeBase64": "AQAAAXydKjV+NlhrSlpPMHAxeHZPWlFJQTBiNXlRWU5s", "options": "{\"allowCredentials\":[{\"idBase64\":\"Z0MkHYJnRDbGfa0LvWvvO6UqcNjFwCIR6mpNTl8jfTA\",\"transports\":[],\"type\":\"public-key\"}],\"challengeBase64\":\"AQAAAXydKjV+NlhrSlpPMHAxeHZPWlFJQTBiNXlRWU5s\",\"rpId\":\"localhost\",\"timeout\":60000,\"userVerification\":\"preferred\"}" }

操作成功时,Data中的JSON字符串包含两个字段:

  • ChallengeBase64: 字符串:防重放挑战码

  • Options:创建认证器的Options,包含webAuthn认证的基本信息

操作失败时,Data字段为空

请求示例

请求方式:POST

https://idaas-doraemon.aliyuncs.com/?Action=CreateUserAuthenticateOptions
&Version=2021-05-20
&ApplicationExternalId=A0000001
&AuthenticatorType=WEBAUTHN
&UserId=user-test-1
&BindHashBase64=xxxxx
&<公共请求参数>

正常返回示例 -WebAuthn认证器认证-初始化通过

{
  "Success": true,
  "Code": "Operation.Success",
  "Message": "Operation.Success",
  "RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
  "Data": {
    "challengeBase64": "AQAAAXydKjV+NlhrSlpPMHAxeHZPWlFJQTBiNXlRWU5s",
    "options": "{\"allowCredentials\":[{\"idBase64\":\"Z0MkHYJnRDbGfa0LvWvvO6UqcNjFwCIR6mpNTl8jfTA\",\"transports\":[],\"type\":\"public-key\"}],\"challengeBase64\":\"AQAAAXydKjV+NlhrSlpPMHAxeHZPWlFJQTBiNXlRWU5s\",\"rpId\":\"localhost\",\"timeout\":60000,\"userVerification\":\"preferred\"}"
  }
}

错误返回示例 - 请求参数中缺少认证方式标识

{

  "Success": false,
  "Code": "Params.Blank",
  "Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
  "RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
  "Data":null
}

WebAuthn认证器认证

webAuthn认证器认证。

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

应用外部ID,该字段在创建应用时指定,在应用详情页中查看

AuthenticatorType

String

WEBAUTHN

认证器类型,固定值为:

WEBAUTHN

AuthenticationContext

String

JS SDK生成的信息

UserId

String

user-test-1

用户ID

ServerExtendParamsJson

String

用于配置UP、UVSignCount递增

RequireChallengeBase64

String

默认无则不校验,只校验Challenge时效及重放

RequireBindHashBase64

String

作用参看"WebAuthn认证器认证-初始化"里的参数"BindHashBase64"

UserSourceIp

String

127.0.0.1

用户IP,用于记录到审计日志中

AuthenticationContext参数解析:

如果是webauthn,则AuthenticationContext是一个JSON,包含以下信息:

字段

类型

备注

userAgent

String

应用代理

credentialId

String

身份证明ID

type

String

当前固定是 public-key

authenticatorDataBase64

String

认证数据JSON

clientDataJSONBase64

String

客户端数据JSON

signatureBase64

String

签名

userHandleBase64

String

用户Handle(也就是UserId)

ServerExtendParamsJson参数解析:

WebAuthn时,ServerExtendParamsJson可以为空(即默认值),或者配置以下参数:

字段

类型

是否必选

备注

requireUserPresence

Boolean

默认值与认证器的UP值一致,是否要求用户出席

requireUserVerification

Boolean

默认值与认证器的UV值一致,是否要求用户验证

requireSignCountIncrement

Boolean

默认值为 true ,当SignCount不为 0 时要求SignCount大于当前值,用于防重放

名称

类型

示例值

描述

Success

boolean

true

操作结果,true 代表成功,false 代表失败

Code

String

Opreation.Success

状态码。

  • 当 Success=true 时,Code=Operation.Success

  • 当 Success=false 时,Code的值,请参见下方错误码

Message

String

Opreation.Success

具体的描述信息,当 Success=false 时,会给出Code的对应的具体描述信息

RequestId

String

1C0EE50A-B3BB-42FD-AB59-E3FE88976982

请求ID

Data

String

{ "verifyResult": true, "authenticateResultInfo": { "credentialId": "Z0MkHYJnRDbGfa0LvWvvO6UqcNjFwCIR6mpNTl8jfTA", "bindHashBase64": null, "userId": "abcdefg" }

操作成功时,Data中的JSON字符串包含5个字段:

  • VerifyResult: Bool :认证器结果

  • AuthenticateResultInfo Object:认证结果对象

  • UserId:认证通过的用户Id

  • CredentialId:认证使用的凭据Id

  • BindHashBase64:这次认证绑定的操作hash

操作失败时,Data字段为空

请求方式:POST

https://idaas-doraemon.aliyuncs.com/?Action=VerifyUserAuthentication
&Version=2021-05-20
&ApplicationExternalId=A0000001
&AuthenticatorType=WEBAUTHN
&UserId=user-test-1
&AuthenticationContext=xxxxx
&ServerExtendParamsJson=eyJwaG9uZU51bWJlciI6IjAwMDAwMDAwMDAwIn0=
&UserSourceIp=1.1.1.1
&<公共请求参数>

正常返回示例 -创建webAuthn认证器认证请求通过

{
  "Success": true,
  "Code": "Operation.Success",
  "Message": "Operation.Success",
  "RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
  "Data":  {
    "verifyResult": true,
    "authenticateResultInfo": {
      "credentialId": "Z0MkHYJnRDbGfa0LvWvvO6UqcNjFwCIR6mpNTl8jfTA",
      "bindHashBase64": null,
      "userId": "abcdefg"
    }
  }
}

错误返回示例 - 请求参数中缺少认证类型标识

{
  "Success": false,
  "Code": "Params.Blank",
  "Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
  "RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
  "Data":null
}

代码示例(Java)

webAuthn认证的示例代码:

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.idaas_doraemon.model.v20210520.*;
import com.aliyuncs.profile.DefaultProfile;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class IDaaSAuthSample {
    /**
     * 使用AK&SK初始化账号Client
     *
     * @param accessKeyId
     * @param accessKeySecret
     * @return Client
     * @throws Exception
     */
    public static IAcsClient createClient(String accessKeyId, String accessKeySecret) throws Exception {
         // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        // 此处以把AccessKey 和 AccessKeySecret 保存在环境变量为例说明。您可以根据业务需要,保存到配置文件里。
        // 强烈建议不要把 AccessKey 和 AccessKeySecret 保存到代码里,会存在密钥泄漏风险
      	String accessKeyId = System.getenv("ACCESS_KEY_ID");
        String accessKeySecret = System.getenv("ACCESS_KEY_SECRET");
        DefaultProfile profile = DefaultProfile.getProfile(
                "cn-hangzhou",
                accessKeyId,
                accessKeySecret);
        // addEndpoint
        DefaultProfile.addEndpoint("cn-hangzhou",
                "idaas-doraemon",
                "idaas-doraemon.aliyuncs.com");
        // 访问的域名
        return new DefaultAcsClient(profile);
    }

    public static void main(String[] args_) throws Exception {
        // webAuthn认证器注册初始化
        registerWebAuthnInit();
        // webAuthn认证器注册
        registerWebAuthnVerify();
        // webAuthn认证初始化
        webAuthnVerifyInit();
        // webAuthnVerify认证
    }

    public void registerWebAuthnInit() throws Exception {
        IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //webAuthn认证器注册初始化
        CreateAuthenticatorRegistrationRequest request = new CreateAuthenticatorRegistrationRequest();
                request.setApplicationExternalId("testApplication");
                request.setAuthenticatorType("WEBAUTHN");
                request.setUserId("1232312312");
                request.setUserName("1232312312");
                request.setUserDisplayName("1232312312");
                request.setServerExtendParamsJson("eyJhdHRhY2htZW50IjoicGxhdGZvcm0iLCJ1c2VyVmVyaWZpY2F0aW9uIjoicmVxdWlyZWQifQ==");
        // 复制代码运行请自行打印 API 的返回值
        try {
            CreateAuthenticatorRegistrationResponse response = client.getAcsResponse(request);
            System.out.println(response.getChallengeBase64());
        } catch (Exception e) {
            //根据e,getCode()判断异常原因
            System.out.println(e);
        }
    }

    public void registerWebAuthnVerify() throws Exception {
        IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //webAuthn认证器注册-验证
        RegisterAuthenticatorRequest request = new RegisterAuthenticatorRequest();
                request.setApplicationExternalId("testApplication");
                request.setAuthenticatorType("WEBAUTHN");
                request.setUserId("1232312312");
                request.setAuthenticatorName("认证器");
                request.setRequireChallengeBase64("AAAAAXy71/wtMTIzMjMxMjMxMg==");
                request.setRegistrationContext("{\"base64Challenge\":\"AAAAAXy71/wtMTIzMjMxMjMxMg==\",\"otpCode\":\"304288\"}");
                request.setUserSourceIp("47.100.XX.XX");
        // 复制代码运行请自行打印 API 的返回值
        try {
            RegisterAuthenticatorResponse response = client.getAcsResponse(request);
            System.out.println(response.getAuthenticatorUuid());
        } catch (Exception e) {
            //根据e,getCode()判断异常原因
            System.out.println(e);
        }
    }

    public void webAuthnVerifyInit() throws Exception {
        IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //WebAuthn认证器-验证初始化
        CreateUserAuthenticateOptionsRequest request = new CreateUserAuthenticateOptionsRequest();
                request.setApplicationExternalId("testApplication");
                request.setAuthenticatorType("WEBAUTHN");
                request.setUserId("1232312312");
        // 复制代码运行请自行打印 API 的返回值
        try {
            CreateUserAuthenticateOptionsResponse response = client.getAcsResponse(request);
            System.out.println(response.getOptions());
        } catch (Exception e) {
            //根据e,getCode()判断异常原因
            System.out.println(e);
        }
    }

    public void webAuthnVerify() throws Exception {
        IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //WebAuthn认证器-验证
        VerifyUserAuthenticationRequest request = new VerifyUserAuthenticationRequest();
                request.setApplicationExternalId("testApplication");
                request.setAuthenticatorType("WEBAUTHN");
                request.setUserId("1232312312");
                request.setAuthenticationContext("");
        // 复制代码运行请自行打印 API 的返回值
        try {
            VerifyUserAuthenticationResponse response = client.getAcsResponse(request);
            System.out.println(response.getAuthenticateResultInfo());
        } catch (Exception e) {
            //根据e,getCode()判断异常原因
            System.out.println(e);
        }
    }
}

示例代码的maven依赖

  <dependency>
   <groupId>com.aliyun</groupId>
   <artifactId>aliyun-java-sdk-idaas-doraemon</artifactId>
   <version>1.2.4</version>
  </dependency>
  <dependency>
   <groupId>com.aliyun</groupId>
   <artifactId>aliyun-java-sdk-core</artifactId>
   <optional>true</optional>
   <version>[4.4.9,5.0.0)</version>
  </dependency>