動(dòng)態(tài)口令(TOTP)接入
本文介紹 TOTP 的接入。
前提條件
請(qǐng)先完成阿里云賬號(hào)注冊(cè)、實(shí)名認(rèn)證、開通安全認(rèn)證、創(chuàng)建應(yīng)用;
請(qǐng)完成獲取阿里云訪問密鑰;
請(qǐng)確保使用的應(yīng)用,已經(jīng)勾選了“TOTP”的認(rèn)證方式,請(qǐng)查看修改應(yīng)用認(rèn)證方式。
TOTP認(rèn)證器注冊(cè)-初始化
TOTP認(rèn)證器注冊(cè)-初始化請(qǐng)求,返回符合TOTP創(chuàng)建身份證明的參數(shù)對(duì)象。
請(qǐng)求參數(shù)
名稱 | 類型 | 必填 | 示例值 | 描述 |
ApplicationExternalId | String | 是 | A0000001 | 應(yīng)用外部ID,該字段在創(chuàng)建應(yīng)用時(shí)指定,在應(yīng)用詳情頁中查看 |
AuthenticatorType | String | 是 | TOTP | 認(rèn)證方式標(biāo)識(shí),調(diào)用TOTP認(rèn)證接口時(shí),固定值為:TOTP |
UserId | String | 是 | user-test-1 | 用戶的唯一標(biāo)識(shí), 例如:userId、手機(jī)號(hào)、郵箱等 |
Username | String | 否 | 張三 | 用戶名 |
UserDisplayName | String | 否 | 小張 | 用戶昵稱 |
RegistrationContext | String | 否 | {\"algorithm\":\"HmacSHA1\",\"period\":30,\"keySeedRespMode\":\"GOOGLE_QR\",\"issuer\":\"GItHub\"} | TOTP注冊(cè)上下文, JSON字符串 |
RegistrationContext參數(shù)解析
名稱 | 類型 | 必填 | 示例值 | 描述 |
algorithm | String | 否 | HmacSHA1 | 令牌算法,固定值: HmacSHA1 HmacSHA256 HmacSHA512 SM3 |
period | int | 否 | 30 | 令牌周期,默認(rèn) 30 秒可設(shè)置 30 或者 60 |
keySeedRespMode | String | 是 | GOOGLE_QR | 密鑰返回模式標(biāo)識(shí)位,標(biāo)識(shí)如何返回密鑰信息,固定值: GOOGLE_QR //二維碼 RAW_HEX //16進(jìn)制字符串 RAW_BASE64//BASE64字符串 RAW_BASE32//BASE32字符串 |
issuer | String | 是 | 發(fā)行人, 一般填寫當(dāng)前系統(tǒng)的名稱 | |
qrCodeImgWidth | int | 否 | 200 | 二維碼圖片的寬度, 密鑰返回信息是:GOOGLE_QR, 設(shè)置才有效 |
qrCodeImgHeight | int | 否 | 200 | 二維碼圖片的高度, 密鑰返回信息是:GOOGLE_QR, 設(shè)置才有效 |
返回?cái)?shù)據(jù)
名稱 | 類型 | 示例值 | 描述 |
Success | boolean | true | 操作結(jié)果,true 代表成功,false 代表失敗 |
Code | String | Opreation.Success | 狀態(tài)碼。當(dāng) Success=true 時(shí),Code=Operation.Success當(dāng) Success=false 時(shí),Code的值,請(qǐng)參見下方錯(cuò)誤碼 |
Message | String | Opreation.Success | 具體的描述信息,當(dāng) Success=false 時(shí),會(huì)給出Code的對(duì)應(yīng)的具體描述信息 |
RequestId | String | 1C0EE50A-B3BB-42FD-AB59-E3FE88976982 | 請(qǐng)求ID |
Data | String | { "challengeBase64": "MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==", "options": "{\"algorithm\":\"HmacSHA1\",\"encodedSeed\":\"xxxxxx\",\"period\":30,\"seedEncodedFormat\":\"GOOGLE_QR\",\"user\":{\"displayName\":\"\",\"id\":\"2ue3bxdsbaofhns7x290bkn0u83whndincma\",\"name\":\"\"}}" } | 操作成功時(shí),Data中的JSON字符串包含兩個(gè)字段:
操作失敗時(shí),Data字段為空 |
請(qǐng)求示例
請(qǐng)求方式: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
&<公共請(qǐng)求參數(shù)>
正常返回示例 -TOTP注冊(cè)認(rèn)證器-初始化通過
{
"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\":\"\"}}"
}
}
錯(cuò)誤返回示例 - 請(qǐng)求參數(shù)中缺少認(rèn)證方式標(biāo)識(shí)
{
"Success": false,
"Code": "Params.Blank",
"Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
"RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
"Data":null
}
TOTP認(rèn)證器注冊(cè)-驗(yàn)證
TOTP認(rèn)證器注冊(cè)-驗(yàn)證請(qǐng)求, 注冊(cè)認(rèn)證器主要工作是校驗(yàn)合法性、對(duì)用戶ID和認(rèn)證器綁定起來。
適用場景:
PC端用戶已登錄, 為某個(gè)用戶開啟TOTP認(rèn)證。
請(qǐng)求參數(shù)
名稱 | 類型 | 必填 | 示例值 | 描述 |
ApplicationExternalId | String | 是 | A0000001 | 應(yīng)用外部ID,該字段在創(chuàng)建應(yīng)用時(shí)指定,在應(yīng)用詳情頁中查看 |
AuthenticatorType | String | 是 | TOTP | 認(rèn)證方式標(biāo)識(shí),調(diào)用TOTP認(rèn)證接口時(shí),固定值為:TOTP |
UserId | String | 是 | user-test-1 | 用戶的唯一標(biāo)識(shí), 例如:userId、手機(jī)號(hào)、郵箱等 |
AuthenticatorName | String | 否 | Google認(rèn)證器 | 認(rèn)證器名稱 |
RequireChallengeBase64 | String | 否 | MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw== | 創(chuàng)建認(rèn)證器初始化請(qǐng)求返回的ChallengeBase64 |
RegistrationContext | String | 否 | {\"base64Challenge\":\"MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw==\",\"otpCode\":\"123456\"} | TOTP注冊(cè)驗(yàn)證上下文, JSON字符串,包含見下面解析 |
UserSourceIp | String | 否 |
RegistrationContext參數(shù)解析
名稱 | 類型 | 必填 | 示例值 | 描述 |
base64Challenge | String | 是 | MGVhMGViYzYzNjc4YWZlYzMxYmIzODUxYTlhNzViMjFHdU5kMjIySjZtYw== | 防重放挑戰(zhàn)碼 |
otpCode | String | 是 | 123456 | 動(dòng)態(tài)口令 |
返回?cái)?shù)據(jù)
名稱 | 類型 | 示例值 | 描述 |
Success | boolean | true | 操作結(jié)果,true 代表成功,false 代表失敗 |
Code | String | Opreation.Success | 狀態(tài)碼。當(dāng) Success=true 時(shí),Code=Operation.Success當(dāng) Success=false 時(shí),Code的值,請(qǐng)參見下方錯(cuò)誤碼 |
Message | String | Opreation.Success | 具體的描述信息,當(dāng) Success=false 時(shí),會(huì)給出Code的對(duì)應(yīng)的具體描述信息 |
RequestId | String | 1C0EE50A-B3BB-42FD-AB59-E3FE88976982 | 請(qǐng)求ID |
Data | String | { "authenticatorUuid": "138dc94bcd6fb9ed2189474c97444c337kURpzUyQp1" } | 操作成功時(shí),Data中的JSON字符串包含1個(gè)字段:
操作失敗時(shí),Data字段為空 |
請(qǐng)求示例
請(qǐng)求方式: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注冊(cè)認(rèn)證器-驗(yàn)證通過
{
"Success": true,
"Code": "Operation.Success",
"Message": "Operation.Success",
"RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
"Data": {
"authenticatorUuid": "1C0EE50AB3BB42FDAB59E3FE88976982"
}
}
錯(cuò)誤返回示例 - 請(qǐng)求參數(shù)中缺少認(rèn)證方式標(biāo)識(shí)
{
"Success": false,
"Code": "Params.Blank",
"Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
"RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
"Data":null
}
TOTP認(rèn)證器-認(rèn)證
TOTP認(rèn)證器認(rèn)證請(qǐng)求, 適用場景:登錄二次認(rèn)證、敏感操作二次認(rèn)證。
請(qǐng)求參數(shù)
名稱 | 類型 | 必填 | 示例值 | 描述 |
ApplicationExternalId | String | 是 | A0000001 | 應(yīng)用外部ID,該字段在創(chuàng)建應(yīng)用時(shí)指定,在應(yīng)用詳情頁中查看 |
ServiceCode | String | 是 | TOTP | 認(rèn)證方式標(biāo)識(shí),調(diào)用TOTP認(rèn)證接口時(shí),固定值為:TOTP |
DoraemonAction | String | 是 | VerifyOTP | 操作類型. 固定值:VerifyOTP |
ServerExtendParamsJson | String | 是 | eyJ1bmlxdWVJZCI6IjEyMzIzMTIzMTIiLCJ1bmlxdWVJZFR5cGUiOiJVU0VSX0lEIiwiY29kZSI6IjExMDIwNSIsInZlcmlmeU1vZGUiOiJQTEFJTiJ9 | 需要將ServerExtendParamsJson的JSON字符進(jìn)行Base64 |
XClientIp | String | 否 | 127.0.0.1 | 客戶端IP |
ServerExtendParamsJson參數(shù)解析
名稱 | 類型 | 必填 | 示例值 | 描述 |
uniqueId | String | 是 | userid-test-1 | 必填,認(rèn)證器唯一標(biāo)識(shí),或者用戶唯一ID,根據(jù) uniqueIdType的值不同,含義也不同 |
code | String | 是 | 123456 | 動(dòng)態(tài)口令 |
uniqueIdType | String | 否 | USER_ID | 選填,用于說明uniqueId的含義;可選值:
為空時(shí),默認(rèn)OTP_UID |
verifyMode | String | 否 | PLAN | 驗(yàn)證模式,支持:
為空時(shí),默認(rèn)PLAIN |
Base64EncodedChapChallenge | String | 否 | 當(dāng)verifyMode =CHAP時(shí)必須傳入 | |
Base64EncodedMsChapV2ServerChallenge | String | 否 | 當(dāng)verifyMode =MS-CHAP-V2時(shí)必須傳入 | |
Base64EncodedMsChapV2ClientChallenge | String | 否 | Base64EncodedMsChapV2ClientChallenge |
返回?cái)?shù)據(jù)
名稱 | 類型 | 示例值 | 描述 |
Success | boolean | true | 操作結(jié)果,true 代表成功,false 代表失敗 |
Code | String | Opreation.Success | 狀態(tài)碼。當(dāng) Success=true 時(shí),Code=Operation.Success當(dāng) Success=false 時(shí),Code的值,請(qǐng)參見下方錯(cuò)誤碼 |
Message | String | Opreation.Success | 具體的描述信息,當(dāng) Success=false 時(shí),會(huì)給出Code的對(duì)應(yīng)的具體描述信息 |
RequestId | String | 1C0EE50A-B3BB-42FD-AB59-E3FE88976982 | 請(qǐng)求ID |
Data | String | "{\"state\":\"7d36722302b6b323ba28fc064e91d56aq88S6Zih4Bq\"}" | 操作成功時(shí),Data中的JSON字符串包含1個(gè)字段:
操作失敗時(shí),Data字段為空 |
請(qǐng)求示例
請(qǐng)求方式: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注冊(cè)認(rèn)證器-驗(yàn)證通過
{
"Success": true,
"Code": "Operation.Success",
"Message": "Operation.Success",
"RequestId": "337848D2-FF8A-4EDD-BD4D-1B9BC80E58B6",
"Data":"{\"state\":\"7d36722302b6b323ba28fc064e91d56aq88S6Zih4Bq\"}"
}
錯(cuò)誤返回示例 - 請(qǐng)求參數(shù)中缺少認(rèn)證方式標(biāo)識(shí)
{
"Success": false,
"Code": "Params.Blank",
"Message": "Params.Blank.APIInvokeParams.AuthenticatorType",
"RequestId": "1C0EE50A-B3BB-42FD-AB59-E3FE88976982",
"Data":null
}
代碼示例(Java)
需要在一個(gè)Java的Maven 項(xiàng)目中引入服務(wù)端SDK包, 坐標(biāo)如下。
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-idaas-doraemon</artifactId>
<version>1.2.4</version>
</dependency>
TOTP認(rèn)證的示例代碼:
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初始化賬號(hào)Client
*
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
public static IAcsClient createClient(String accessKeyId, String accessKeySecret) throws Exception {
// 阿里云賬號(hào)AccessKey擁有所有API的訪問權(quán)限,風(fēng)險(xiǎn)很高。強(qiáng)烈建議您創(chuàng)建并使用RAM用戶進(jìn)行API訪問或日常運(yùn)維,請(qǐng)登錄RAM控制臺(tái)創(chuàng)建RAM用戶。
// 此處以把AccessKey 和 AccessKeySecret 保存在環(huán)境變量為例說明。您可以根據(jù)業(yè)務(wù)需要,保存到配置文件里。
// 強(qiáng)烈建議不要把 AccessKey 和 AccessKeySecret 保存到代碼里,會(huì)存在密鑰泄漏風(fēng)險(xiǎn)
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認(rèn)證器注冊(cè)初始化
registerInit();
// TOTP認(rèn)證器注冊(cè)
registerVerify();
// TOTP認(rèn)證
totpVerify();
}
public void registerInit() throws Exception {
IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
//TOTP認(rèn)證器注冊(cè)初始化
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\"}");
// 復(fù)制代碼運(yùn)行請(qǐng)自行打印 API 的返回值
try {
CreateAuthenticatorRegistrationResponse response = client.getAcsResponse(request);
System.out.println(response.getChallengeBase64());
} catch (Exception e) {
//根據(jù)e,getCode()判斷異常原因
System.out.println(e);
}
}
public void registerVerify() throws Exception {
IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
//TOTP認(rèn)證器注冊(cè)-驗(yàn)證
RegisterAuthenticatorRequest request = new RegisterAuthenticatorRequest();
request.setApplicationExternalId("testApplication");
request.setAuthenticatorType("TOTP");
request.setUserId("1232312312");
request.setAuthenticatorName("測試的認(rèn)證器");
request.setRequireChallengeBase64("MjY1M2I3OTA1NWEwMDY2YmYxN2Y1YjA3NDdkZTM5NjdOSHVIU3c2czhPaQ==");
request.setRegistrationContext("{\"base64Challenge\":\"MjY1M2I3OTA1NWEwMDY2YmYxN2Y1YjA3NDdkZTM5NjdOSHVIU3c2czhPaQ==\",\"otpCode\":\"304288\"}");
request.setUserSourceIp("47.100.XX.XX");
// 復(fù)制代碼運(yùn)行請(qǐng)自行打印 API 的返回值
try {
RegisterAuthenticatorResponse response = client.getAcsResponse(request);
System.out.println(response.getAuthenticatorUuid());
} catch (Exception e) {
//根據(jù)e,getCode()判斷異常原因
System.out.println(e);
}
}
public void totpVerify() throws Exception {
IAcsClient client = IDaaSAuthSample.createClient("Your AccessKey", "Your AccessSecret");
//TOTP認(rèn)證器驗(yàn)證
ServiceInvokeRequest request = new ServiceInvokeRequest();
request.setApplicationExternalId("testApplication");
request.setServiceCode("TOTP");
request.setDoraemonAction("VerifyOTP");
request.setServerExtendParamsJson("eyJ1bmlx.........FJTiJ9");
// 復(fù)制代碼運(yùn)行請(qǐng)自行打印 API 的返回值
try {
ServiceInvokeResponse response = client.getAcsResponse(request);
System.out.println(response.getData());
} catch (Exception e) {
//根據(jù)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>