动态口令(TOTP)接入

本文介绍 TOTP 的接入。

前提条件

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

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

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

  4. SDK&Demo下载

TOTP认证器注册-初始化

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

请求参数

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

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

AuthenticatorType

String

TOTP

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

UserId

String

user-test-1

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

Username

String

张三

用户名

UserDisplayName

String

小张

用户昵称

RegistrationContext

String

{\"algorithm\":\"HmacSHA1\",\"period\":30,\"keySeedRespMode\":\"GOOGLE_QR\",\"issuer\":\"GItHub\"}

TOTP注册上下文, JSON字符串

RegistrationContext参数解析

名称

类型

必填

示例值

描述

algorithm

String

HmacSHA1

令牌算法,固定值:

HmacSHA1

HmacSHA256

HmacSHA512

SM3

period

int

30

令牌周期,默认 30 秒可设置 30 或者 60

keySeedRespMode

String

GOOGLE_QR

密钥返回模式标识位,标识如何返回密钥信息,固定值:

GOOGLE_QR //二维码 RAW_HEX //16进制字符串 RAW_BASE64//BASE64字符串 RAW_BASE32//BASE32字符串

issuer

String

Google

发行人, 一般填写当前系统的名称

qrCodeImgWidth

int

200

二维码图片的宽度, 密钥返回信息是:GOOGLE_QR, 设置才有效

qrCodeImgHeight

int

200

二维码图片的高度, 密钥返回信息是:GOOGLE_QR, 设置才有效

返回数据

名称

类型

示例值

描述

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": "MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==", "options": "{\"algorithm\":\"HmacSHA1\",\"encodedSeed\":\"xxxxxx\",\"period\":30,\"seedEncodedFormat\":\"GOOGLE_QR\",\"user\":{\"displayName\":\"\",\"id\":\"2ue3bxdsbaofhns7x290bkn0u83whndincma\",\"name\":\"\"}}" }

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

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

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

操作失败时,Data字段为空

请求示例

请求方式:POST

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

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

{
  "Success": true,
  "Code": "Operation.Success",
  "Message": "Operation.Success",
  "RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
  "Data": {
  "challengeBase64": "MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==",
    "options": "{\"algorithm\":\"HmacSHA1\",\"encodedSeed\":\"xxxxxx\",\"period\":30,\"seedEncodedFormat\":\"GOOGLE_QR\",\"user\":{\"displayName\":\"\",\"id\":\"2ue3bxdsbaofhns7x290bkn0u83whndincma\",\"name\":\"\"}}"
  }
}

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

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

TOTP认证器注册-验证

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

适用场景:

PC端用户已登录, 为某个用户开启TOTP认证。

请求参数

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

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

AuthenticatorType

String

TOTP

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

UserId

String

user-test-1

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

AuthenticatorName

String

Google认证器

认证器名称

RequireChallengeBase64

String

MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==

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

RegistrationContext

String

{\"base64Challenge\":\"MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==\",\"otpCode\":\"123456\"}

TOTP注册验证上下文, JSON字符串,包含见下面解析

UserSourceIp

String

RegistrationContext参数解析

名称

类型

必填

示例值

描述

base64Challenge

String

MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==

防重放挑战码

otpCode

String

123456

动态口令

返回数据

名称

类型

示例值

描述

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": "138dc94bcd6fb9ed2189474c97444c337kURpzUyQp1" }

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

  • AuthenticatorUuid: 字符串:认证器UUID

操作失败时,Data字段为空

请求示例

请求方式:POST

https://idaas-doraemon.aliyuncs.com/?Action=RegisterAuthenticator
&Version=2021-05-20
&ApplicationExternalId=A0000001
&AuthenticatorType=TOTP
&UserId=user-test-1
&AuthenticatorName=user-test-1
&RequireChallengeBase64="MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw=="
&RegistrationContext="{\"base64Challenge\":\"MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==\",\"otpCode\":\"123456\"}"
&UserSourceIp=1.1.X.X

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

{
  "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
}

TOTP认证器-认证

TOTP认证器认证请求, 适用场景:登录二次认证、敏感操作二次认证。

请求参数

名称

类型

必填

示例值

描述

ApplicationExternalId

String

A0000001

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

ServiceCode

String

TOTP

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

DoraemonAction

String

VerifyOTP

操作类型. 固定值:VerifyOTP

ServerExtendParamsJson

String

eyJ1bmlxdWVJZCI6IjEyMzIzMTIzMTIiLCJ1bmlxdWVJZFR5cGUiOiJVU0VSX0lEIiwiY29kZSI6IjExMDIwNSIsInZlcmlmeU1vZGUiOiJQTEFJTiJ9

需要将ServerExtendParamsJsonJSON字符进行Base64

XClientIp

String

127.0.0.1

客户端IP

ServerExtendParamsJson参数解析

名称

类型

必填

示例值

描述

uniqueId

String

userid-test-1

必填,认证器唯一标识,或者用户唯一ID,根据

uniqueIdType的值不同,含义也不同

code

String

123456

动态口令

uniqueIdType

String

USER_ID

选填,用于说明uniqueId的含义;可选值:

  • OTP_UID 代表uniqueId是认证器唯一标识

  • USER_ID 代表uniqueId是用户唯一标识;

为空时,默认OTP_UID

verifyMode

String

PLAN

验证模式,支持:

  • PLAIN代表传入的 code 就是原始明文

  • CHAP代表传入的 code 就是按照CHAP协议处理后的令牌,此时必须传入chap挑战才可以验证(base64EncodedChapChallenge),适用于网络设备通过Radius协议进行认证

  • MS-CHAP-V2代表传入的 code 就是按照MS-CHAP-V2协议处理后的令牌,此时必须传入服务端挑战、客户端挑战、用户名,适用于网络设备通过Radius协议进行认证

为空时,默认PLAIN

Base64EncodedChapChallenge

String

verifyMode =CHAP时必须传入

Base64EncodedMsChapV2ServerChallenge

String

verifyMode =MS-CHAP-V2时必须传入

Base64EncodedMsChapV2ClientChallenge

String

Base64EncodedMsChapV2ClientChallenge

返回数据

名称

类型

示例值

描述

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

"{\"state\":\"7d36722302b6b323ba28fc064e91d56aq88S6Zih4Bq\"}"

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

  • state: 字符串:认证ID

操作失败时,Data字段为空

请求示例

请求方式:POST

https://idaas-doraemon.aliyuncs.com/?Action=ServiceInvoke
&Version=2021-05-20
&ApplicationExternalId=A0000001
&AuthenticatorType=TOTP
&UserId=user-test-1
&Action=VerifyOTP
&ServerExtendParamsJson=eyJwaG9uZU51bWJlciI6IjAwMDAwMDAwMDAwIn0=
&UserSourceIp=1.1.X.X

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

{
  "Success": true,
  "Code": "Operation.Success",
  "Message": "Operation.Success",
  "RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
  "Data":"{\"state\":\"7d36722302b6b323ba28fc064e91d56aq88S6Zih4Bq\"}"
}

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

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

代码示例(Java)

需要在一个JavaMaven 项目中引入服务端SDK包, 坐标如下。

  <dependency>
   <groupId>com.aliyun</groupId>
   <artifactId>aliyun-java-sdk-idaas-doraemon</artifactId>
   <version>1.2.4</version>
  </dependency>

TOTP认证的示例代码:

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 {
        // TOTP认证器注册初始化
        registerInit();
        // TOTP认证器注册
        registerVerify();
        // TOTP认证
        totpVerify();
    }

    public void registerInit() throws Exception {
        IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //TOTP认证器注册初始化
        CreateAuthenticatorRegistrationRequest request = new CreateAuthenticatorRegistrationRequest();
                request.setApplicationExternalId("testApplication");
                request.setAuthenticatorType("TOTP");
                request.setUserId("1232312312");
                request.setUserName("1232312312");
                request.setUserDisplayName("1232312312");
                request.setRegistrationContext("{\"algorithm\":\"HmacSHA1\",\"keySeedRespMode\":\"GOOGLE_QR\",\"qrCodeImgWidth\":200,\"qrCodeImgHeight\":200,\"issuer\":\"AliIDaaSSecurityAuth\"}");
        // 复制代码运行请自行打印 API 的返回值
        try {
            CreateAuthenticatorRegistrationResponse response = client.getAcsResponse(request);
            System.out.println(response.getChallengeBase64());
        } catch (Exception e) {
            //根据e,getCode()判断异常原因
            System.out.println(e);
        }

   }

    public void registerVerify() throws Exception {
         IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //TOTP认证器注册-验证
        RegisterAuthenticatorRequest request = new RegisterAuthenticatorRequest();
                request.setApplicationExternalId("testApplication");
                request.setAuthenticatorType("TOTP");
                request.setUserId("1232312312");
                request.setAuthenticatorName("测试的认证器");
                request.setRequireChallengeBase64("MjY1M2I3OTA1NWEwMDY2YmYxN2Y1YjA3NDdkZTM5NjdOSHVIU3c2czhPaQ==");
                request.setRegistrationContext("{\"base64Challenge\":\"MjY1M2I3OTA1NWEwMDY2YmYxN2Y1YjA3NDdkZTM5NjdOSHVIU3c2czhPaQ==\",\"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 totpVerify() throws Exception {
        IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
        //TOTP认证器验证
        ServiceInvokeRequest request = new ServiceInvokeRequest();
                request.setApplicationExternalId("testApplication");
                request.setServiceCode("TOTP");
                request.setDoraemonAction("VerifyOTP");
                request.setServerExtendParamsJson("eyJ1bmlx.........FJTiJ9");
              // 复制代码运行请自行打印 API 的返回值
        try {
            ServiceInvokeResponse response = client.getAcsResponse(request);
            System.out.println(response.getData());
        } 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>