# 1. 免密授权登录
# 请求URL
/api/jt/wallet/open/user/getLoginToken
# 请求方式
- POST
# 请求头
| 参数名 | 必选 | 类型 | 说明 |
|---|---|---|---|
| Content-Type | 是 | string | application/json |
# 请求体参数
| 参数名 | 必选 | 类型 | 说明 | 示例(加密前) | 示例(加密后) |
|---|---|---|---|---|---|
| appId | 是 | string | Application APPID | ||
| aesKey | 是 | string | AES Key (RSA加密后) | "{\"key\": \"qwertasdfgzxcvbn\", \"iv\": \"bvcxzgfdsatrewqy\"}" | YDPeqH0+MJiW5Jfi9CQXy/Btz4YkiZCOp5njAy5G5s87HaS/zgmQZBnDeNjFrSduAL1tC329XIJGX+u6SKZtRvtrCx5UhZGRviBBhA575mt99TcUqAVEjXRn+ShpZmg6U8N0IHl8TX8psyWiAzxIBkrDCqIlXODfNdr8/LgZcuQFgwQGurZ8QX9L9BZxBdOH1ksLqP0Dlr5awQYD9LAstA8nzZ9C9qXt7OD+XvE6qK/8pi9YYr02oqdaXyo2ypITz6HkXKibYSv6HDtPIy6h44Qgnc6psmE4bBmH7k6q27u0mqe3zFzXiZlF7NOIkl8inFKaR59jD06L/xbuM+oTOrKHThY7+FaObf1gVSRqrzucuv9gNgI2tZRkG5AzYCMTIER0zXfx2QtVUxmOvkl6+OAVBNnLC+N9KdzXSiUU1zehg3+VrosJqyNTfYT/8iY4NVa2IPzX5CN89lA3zYoDeiyBpzH71H86oU3xzoNQS00QrgWi0tK4WXaU+duPO+wLzfGv9/2G0I5Hgf2XkjFD+Ab8wWiDxJ0YfT1mBHtjkNtlvtrD4Sc48UClxE4vGMp4ekapd6+2yEzMYEVY4o/HUgE6QgeiGcE25yT8RC8yMxw4eHQnE4NTjwowdqm+Vq28iOw2IufRxjfcPyz7f9TgGGwhu/IHwh24exfJx73RKFA= |
| param | 是 | string | Parameter body (AES加密字符) | "{\"timestamp\":1715595802,\"userId\":\"1095595801938341100\",\"mobile\":\"639123456778\"}" | u+wP+tVHRCDT21oIC32X+RogU3x5blBdikNSvRFuM9TkWMtc9WrZKCX6YIS1uezJZXR925qEBR6oVyCQ9tO6t7d0Z3xm/wKlufx2hQEfRbE= |
| sign | 是 | string | Signature (参数-param使用加密前) | EJeMHGDlLu3DdbIK/52aID1soLrD0rfGcEEsAQ8cXFWaXQHioVwfZUD82U5g67NTXP/F/0Mhg6bK7n6rJlC/clYzqZ1kHmO2FbCdujw0ATY+FfM6VkgVT4pXr1jYmg3Xe23RDqhFvkDcOfRvaGPtnf64yrQG32MZps23TsbnafitDbtfqSoDIZkDCw1j1EH3Shhd64xKh9L3O8ivyF2UDOiHSAD8+18JXOxMWMFcR01STKE5B+zlEu5OA98+ClDBdroekBVKDeBeagwwQr+0zDFUvAb+2QIPKA2o0JM3ooituiaKVCgCVfndNjk8wIzKz2QYp+RhjVOC/u+8+Yoqb4KoWjGkMXgDbM1GZpdHG/BmzqXqhnNF0Y0LYS4bkITstlOm30nnHSljT5bxjk2Sq1hp9259SqMdp52OyoznxbRwEva5Wk5YPo+zD8IHOctEjkwWXz9/jo2evK6QcWCOH2LM6cG7EoP6Cg+5P2AUTofSMZsn/ZnAy6h9MXIuirDBiujrKMk85EY74s8i7yCNmjQ5NRbPbKsNTJbkxp2cRSMPzYPzOXXqEgKMmYzVQ5SSAcqFZIj2fAOL/3fG+2aEMn/8AFjJuD3/160BmYCZbAY4A2LJow6SGP/OcifvWPwoziJv0IP5Jff59w0mv6h0+3HnJg5YAcqK7dani1C0cAQ= |
# param 解密之后参数
| 参数名 | 必选 | 类型 | 长度 | 示例 | 说明 |
|---|---|---|---|---|---|
| timestamp | 是 | long | - | 1677495496979 | 毫秒时间戳 |
| userId | 是 | string | 1-32 | - | 极兔用户uuid唯一标识号 |
| mobile | 是 | string | - | - | 639开头,共12位数字 |
| terminalType | 否 | string | 20 | PC | 设备类型,枚举值:PC, 默认值: PC |
| isIframe | 否 | string | 20 | N | 是否需要在iframe中打开网页,枚举值:Y、N,当设备类型为PC时该值生效。如果需要设置为Y,否则设置为N。 |
# 请求示例
# 请求体
{
"appId": "733b887a4a784708bb369524db5b6ded",
"aesKey": "YDPeqH0+MJiW5Jfi9CQXy/Btz4YkiZCOp5njAy5G5s87HaS/zgmQZBnDeNjFrSduAL1tC329XIJGX+u6SKZtRvtrCx5UhZGRviBBhA575mt99TcUqAVEjXRn+ShpZmg6U8N0IHl8TX8psyWiAzxIBkrDCqIlXODfNdr8/LgZcuQFgwQGurZ8QX9L9BZxBdOH1ksLqP0Dlr5awQYD9LAstA8nzZ9C9qXt7OD+XvE6qK/8pi9YYr02oqdaXyo2ypITz6HkXKibYSv6HDtPIy6h44Qgnc6psmE4bBmH7k6q27u0mqe3zFzXiZlF7NOIkl8inFKaR59jD06L/xbuM+oTOrKHThY7+FaObf1gVSRqrzucuv9gNgI2tZRkG5AzYCMTIER0zXfx2QtVUxmOvkl6+OAVBNnLC+N9KdzXSiUU1zehg3+VrosJqyNTfYT/8iY4NVa2IPzX5CN89lA3zYoDeiyBpzH71H86oU3xzoNQS00QrgWi0tK4WXaU+duPO+wLzfGv9/2G0I5Hgf2XkjFD+Ab8wWiDxJ0YfT1mBHtjkNtlvtrD4Sc48UClxE4vGMp4ekapd6+2yEzMYEVY4o/HUgE6QgeiGcE25yT8RC8yMxw4eHQnE4NTjwowdqm+Vq28iOw2IufRxjfcPyz7f9TgGGwhu/IHwh24exfJx73RKFA=",
"sign": "EJeMHGDlLu3DdbIK/52aID1soLrD0rfGcEEsAQ8cXFWaXQHioVwfZUD82U5g67NTXP/F/0Mhg6bK7n6rJlC/clYzqZ1kHmO2FbCdujw0ATY+FfM6VkgVT4pXr1jYmg3Xe23RDqhFvkDcOfRvaGPtnf64yrQG32MZps23TsbnafitDbtfqSoDIZkDCw1j1EH3Shhd64xKh9L3O8ivyF2UDOiHSAD8+18JXOxMWMFcR01STKE5B+zlEu5OA98+ClDBdroekBVKDeBeagwwQr+0zDFUvAb+2QIPKA2o0JM3ooituiaKVCgCVfndNjk8wIzKz2QYp+RhjVOC/u+8+Yoqb4KoWjGkMXgDbM1GZpdHG/BmzqXqhnNF0Y0LYS4bkITstlOm30nnHSljT5bxjk2Sq1hp9259SqMdp52OyoznxbRwEva5Wk5YPo+zD8IHOctEjkwWXz9/jo2evK6QcWCOH2LM6cG7EoP6Cg+5P2AUTofSMZsn/ZnAy6h9MXIuirDBiujrKMk85EY74s8i7yCNmjQ5NRbPbKsNTJbkxp2cRSMPzYPzOXXqEgKMmYzVQ5SSAcqFZIj2fAOL/3fG+2aEMn/8AFjJuD3/160BmYCZbAY4A2LJow6SGP/OcifvWPwoziJv0IP5Jff59w0mv6h0+3HnJg5YAcqK7dani1C0cAQ=",
"param": "u+wP+tVHRCDT21oIC32X+RogU3x5blBdikNSvRFuM9TkWMtc9WrZKCX6YIS1uezJZXR925qEBR6oVyCQ9tO6t7d0Z3xm/wKlufx2hQEfRbE="
}
// 解密后
"aesKey": "{\"key\": \"qwertasdfgzxcvbn\", \"iv\": \"bvcxzgfdsatrewqy\"}"
"param": "{\"timestamp\":1715595802,\"userId\":\"1095595801938341100\",\"mobile\":\"639123456778\"}"
# Rsa 加签与AES加密工具类
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class SignAndEncryptUtil {
/**
*
* @param param Param JsonString
*/
public static boolean verifySign(String param, String sign, String publicKey) throws NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))));
signature.update(param.getBytes());
return signature.verify(Base64.getDecoder().decode(sign));
}
/**
*
* @param param Param JsonString
* @return sign
*/
public static String generateSign(String param, String privateKey) throws NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey))));
signature.update(param.getBytes());
byte[] bytes = signature.sign();
return Base64.getEncoder().encodeToString(bytes);
}
public static String encryptWithPrivateKey(String data, String privateKeyStr) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey =keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decryptWithPublicKey(String encryptedData, String publicKeyStr) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] decodedBytes = Base64.getDecoder().decode(encryptedData);
return new String(cipher.doFinal(decodedBytes));
}
public static final String PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCV+0mJmN5wOrfcPuAF6JKHQg066WX4/QYOAbhFe/yPJ+tu5QfKau9yptJcwenwV8Mj5DM1QWBAY/d0ThYpRkuPjL9zjWuOzrWFfMuB7EktY13a9F32QlnGJ4JIW5PAoRXl/fsbeZQbrKxnAHvZqOl/LFpNA/eSz4TZ2EegIfILFjTgOnL+g1ZgRiSRBk4DVhDtdDhwvwb0BBK1TAMV0btBJIykcNR7YYAG2+rMwpgtSlDkKB9KuSdtG72GeyAwRqMJJrl77+m1XfR9Py2r8cQ/O3Og7wzE/V1gFhwvZADludFZhgP8pskr9j1gJmU58S1+Xz9Bv5cdLFinzyNNadpTAgMBAAECggEAA3JM1E6g/e87fmIrf7dCdr071Ji8cSZPV08Ozvn0ac2/CUNWFH60levjdaI3IADESTTbQGQKNDCX5SJOPBCTd+8CD0O2rwdtAG5HtuqZG+PmqjtnVVtc+MK7qbIBCTIqcKiPdqgqkSA8rflC31OUWgnI4XAv5j3Cjcb8jl95UmvdNXYQlLeaDnFG24pf1pgbExJndM0fjz9bxFNHVYGa6RxCwbrNLdsKgB2sNg5dKxmZw7JvZtmCcDnb1LTC2sftJJVds4NlmMbWfTS8NVIQa3mKSuwD0jV79xQa+Ec7V6xsod73jz3nbAcKhTPN5B6DJKYtO+aqQKIUlmbSYHAiAQKBgQDHGIX7gIAqIP2gtOpmsvi1mRJeh9F4psaLGU3DMFSAl/Ht/Zs/SYP70mHFYtYvUEjLgpw+V9W48f7mRuAZoRJCKMlKkXlCfCqTImioXUXiPsOBeuglewwmVzw/hOVVh5v+xwIbDu6P8IexXtmAVroBwO3Jdxutsat79iGAr9H80wKBgQDA2SrFNpY/9UhLSQfzY2mm8Yng2Cu1rPTxZRRn4T/2i2vCArPFW/wNspPttEengnE5r7TUJr/a+jZUQz6gpSuNU4eKpOwYZ7QD2szC1UEs39Z/f7pIe7JKUUDdnubECCSR7Vs1uiKFvOILdCf9t/hmsq3+yaM0rGG3jhTa1kg8gQKBgQCZRykHanPBe2qoCgCYFlthu7onqtq6z3L1bgKvLgswgUpRljiqbZe+DMcW5rPM8ztH6oMNgCPbYfuDH7eyI45h/vKRhRPc+qjwY8I9NKnzt6xeh9gn2uaMsgaBRHgm8+NGL8JQQJurl1twU3yR0LMdXIH0480cWTeTlPdQEoxQ3wKBgQCs7U+j/lnmyjzkfX1qq3de4vJfM5imVYxjNd+BcwOXQdgD5cZsMBqp8bsiiOlD9P0w3DULlB+v7XRwRMhQ5ytRlFhTY6XuEHfkiPvZrb6+zY0bUV6qhnkOmSPQVx/ZIvAgBrYmTF2OjRwpZyRBKAnPlWPet9Lodbc+EGL1BPdLgQKBgBSUxIChyE3oo4rAMzCenOtywvyrOhjc5v4UrlvyhWuqej3T9rQ7NMDG0ba+F/guqj3ZruePNsU24X6nd1uiJvHW8XdvtZuGIfDDMOzFgn0G3m9hSXQNTCwaaaQaeuE7G5z1S+x07s6jyv2LfOBHwRuhOshg0bz96jpOIUkKipYH";
public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlftJiZjecDq33D7gBeiSh0INOull+P0GDgG4RXv8jyfrbuUHymrvcqbSXMHp8FfDI+QzNUFgQGP3dE4WKUZLj4y/c41rjs61hXzLgexJLWNd2vRd9kJZxieCSFuTwKEV5f37G3mUG6ysZwB72ajpfyxaTQP3ks+E2dhHoCHyCxY04Dpy/oNWYEYkkQZOA1YQ7XQ4cL8G9AQStUwDFdG7QSSMpHDUe2GABtvqzMKYLUpQ5CgfSrknbRu9hnsgMEajCSa5e+/ptV30fT8tq/HEPztzoO8MxP1dYBYcL2QA5bnRWYYD/KbJK/Y9YCZlOfEtfl8/Qb+XHSxYp88jTWnaUwIDAQAB";
/**
* main方法:演示签名验证和加密解密
*/
public static void main(String[] args) {
try {
// 测试数据
String param = "{\"timestamp\":1715595802,\"userId\":\"1095595801938341100\",\"mobile\":\"639123456778\"}";
String aesKey = "{\"key\": \"qwertasdfgzxcvbn\", \"iv\": \"bvcxzgfdsatrewqy\"}";
System.out.println("\n========== 原始数据 ==========");
System.out.println("param: " + param);
System.out.println("aesKey: " + aesKey);
// 0. 使用AES加密param内容
System.out.println("\n========== 0. AES加密与解密 ==========");
JSONObject aesKeyJson = JSON.parseObject(aesKey);
String key = aesKeyJson.getString("key");
String iv = aesKeyJson.getString("iv");
// 创建AES加密器 (CBC模式, PKCS5Padding填充)
AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, key.getBytes(), iv.getBytes());
// 加密param
String encryptedParam = aes.encryptBase64(param);
System.out.println("AES加密后的param: " + encryptedParam);
// 解密验证
String decryptedParam = aes.decryptStr(encryptedParam);
System.out.println("AES解密后的param: " + decryptedParam);
System.out.println("AES加解密验证: " + (param.equals(decryptedParam) ? "✓ 成功" : "✗ 失败"));
// 1. 使用RSA私钥对param进行加签,获得签名并验证
System.out.println("\n========== 1. RSA签名与验证 ==========");
String sign = generateSign(param, PRIVATE_KEY);
System.out.println("生成的签名: " + sign);
boolean verifyResult = verifySign(param, sign, PUBLIC_KEY);
System.out.println("签名验证结果: " + (verifyResult ? "✓ 通过" : "✗ 失败"));
// 2. 使用RSA私钥对aesKey进行加密,获得加密数据并验证
System.out.println("\n========== 2. RSA加密与解密 ==========");
String encryptedAesKey = encryptWithPrivateKey(aesKey, PRIVATE_KEY);
System.out.println("加密后的aesKey: " + encryptedAesKey);
String decryptedAesKey = decryptWithPublicKey(encryptedAesKey, PUBLIC_KEY);
System.out.println("解密后的aesKey: " + decryptedAesKey);
System.out.println("解密验证: " + (aesKey.equals(decryptedAesKey) ? "✓ 成功" : "✗ 失败"));
} catch (Exception e) {
System.err.println("发生错误: " + e.getMessage());
e.printStackTrace();
}
}
}
# 响应参数
| 参数名 | 类型 | 说明 |
|---|---|---|
| code | integer | response code |
| message | string | response message |
| data | Object | data |
# data参数
| 参数名 | 类型 | 说明 |
|---|---|---|
| expireSeconds | int | 3600秒(过期时间) |
| authUrl | string | 免密登录地址 |
| accountNo | string | 钱包用户账号(钱包侧用户唯一标识号) |
| token | string | 钱包用户登录token |
# 响应示例
# 响应数据体
{
"code": 1000,
"message": "success",
"data": {
"expireSeconds": 3600,
"authUrl": "https://www.paycools.com.ph/#/splash?token=V0xUX1VTRVI6YTBiMjliZmItMzAxMy00ZWVjLTkzY2QtMGRiMzJjYjUxNmUx",
"accountNo": "2200636699666629",
"token": "V0xUX1VTRVI6ZjQ4NjdkYjQtYzAxYy00OTNmLWJhODEtM2Q3MWU1NTM3NmFm"
}
}
# 返回失败案例 响应code列表
{
"code":1002,
"message":"merchant white ip forbidden"
}