TIP
# 2.1 使用秘钥授权登录
# 2.1.1 获取接入AccessToken
接口说明:用于第三方系统从外部直接登录勤策系统时获取AccessToken信息,此AccessToken仅用于秘钥授权接入使用和oAuth2接口不可混用。
请求方式: POST(HTTPS)
请求地址: https://{region}/openplat/getTokenFromThirdparty.do
参数说明:
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
region | text | 是 | 企业所在数据中心服务地址,如:数据中心1区地址:https://cloud.region1.qince.com |
tenantId | long | 是 | 企业id |
data | text | 是 | 加密数据体,将数据体原文使用企业参数"OA登录秘钥"进行AES加密DataEncryptUtil.encryptText(DATA, OA_KEY, NONCE, TIMESTAMP) ,加密方法参考 2.1.4 加密方法部分 |
nonce | text | 是 | 随机字符串 |
timestamp | long | 是 | 时间戳 |
请求体加密后示例:
{
"tenantId":4802948302940558496,
"data":"P3EENkBmTTJ2OxZxl+/BTWED4D/GZNQPL6Q6pNqmDkcsCCa/ia/R5mQwWdDsQTa7PF5IguXVNwhrEnotDaT5/B8c/XLHiS9sUPfFRp5vfyWwPKbjzVLJ+j+3SfypAQiI5S8nDhUUHVG1Qy/wYV9MvhtlI0/kgXLsLr8NbFedyPdZzlKEtPZAZCawQqq1Llu0",
"nonce":"1234",
"timestamp":20220708142900
}
data原文格式说明:
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
sourceType | text | 是 | 登录方式 WEB-电脑端 CLIENT-手机APP端 |
redirectUrl | text | 否 | 登录成功后跳转地址,需要使用勤策URL链接相对地址 |
tenantId | long | 是 | 企业ID |
userId | long | 否 | 勤策员工唯一ID和thirdId二者必传其中一个 |
thirdId | text | 否 | 第三方员工唯一ID和userId二者必传其中一个 |
data原文示例:
{
"sourceType": "WEB",
"redirectUrl": "/test.html",
"tenantId": 4802948302940558496,
"thirdId": "123456"
}
响应参数
参数 | 类型 | 说明 |
---|---|---|
code | text | 响应码 1-成功 0-失败 |
access_token | text | SSO请求访问令牌 |
expire_in | long | SSO请求访问令牌过期时间有效期,单位秒。 默认86400秒 |
message | text | 响应信息 |
响应示例:
{
"code": 1,
"data": {
"access_token": "qc4802948302940558496ak5XLynGNh3e7a04a1b6d54fd8bf0451db8958c823",
"expire_in": 86400
},
"message": "ok"
}
# 2.1.2 用AccessToken登录跳转到勤策WEB端
接口说明:用于第三方系统直接使用AccessToken从外部打开勤策系统的功能界面的接口。
请求方式: GET(HTTPS)
请求地址: https://{region}/openplat/redirectFromThirdparty.do?accessToken=<accessToken>
请求体示例:
https://cloud.region1.qince.com/openplat/redirectFromThirdparty.do?accessToken=qc4802948302940558496ak5XLynGNh3e7a04a1b6d54fd8bf0451db8958c823
参数说明:
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
region | text | 是 | 企业所在数据中心服务地址,如:数据中心一区地址:https://cloud.region1.qince.com |
accessToken | text | 是 | 请求跳转令牌 2.1.1获取AccessToken |
# 2.1.3 用AccessToken登录勤策APP端
接口说明:用于第三方APP可以使用URL Schemes唤起勤策APP,第三方APP在手机端直接唤起勤策APP时需要携带AccessToken参数以便单点登录到勤策系统主界面。
# 2.1.3.1 安卓客户端唤起
请求地址: <Schema>://<HOST>?access_token=<accessToken>
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
Schema | text | 是 | 应用Schema,由勤策厂商提供 |
HOST | text | 是 | 应用HOST,由勤策厂商提供 |
accessToken | text | 是 | 登录授权AccessToken信息, 2.1.1获取AccessToken |
示例:
qince://qince?access_token=qc4802948302940558496ak5XLynGNh3e7a04a1b6d54fd8bf0451db8958c823
# 2.1.3.2 苹果客户端唤起
请求地址: <Schema>://access_token=<accessToken>
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
Schema | text | 是 | 应用Schema,由勤策厂商提供 |
accessToken | text | 是 | 登录授权AccessToken信息,2.1.1获取AccessToken |
示例:
qince://access_token=qc4802948302940558496ak5XLynGNh3e7a04a1b6d54fd8bf0451db8958c823
# 2.1.4 生成加密数据方法
接口说明:用于第三方系统获取的AccessToken信息时获取加密数据的方法。需要传递4个参数text为加密文本信息,nonce随机字符串,
参数 | 类型 | 是否必传 | 说明 |
---|---|---|---|
text | text | 是 | 待加密的文本信息 |
oaKey | text | 是 | 企业OA登录秘钥,在企业参数中设置 |
nonce | text | 是 | 随机字符串 |
timestamp | long | 是 | 时间戳 |
加密算法:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Base64;
public class DataEncryptUtil
{
private static final int KEY_SIZE = 256;
/** 加密/解密算法名称 */
private static final String ALGORITHM = "AES";
//"算法/模式/补码方式"
private static final String TRANSFORM_CBC_PKCS5 = "AES/ECB/PKCS5Padding";
private static final String CHARSET = "UTF-8";
private static byte[] decrypt(byte[] cipherBytes, byte[] key) throws Exception
{
// 生成密钥对象
SecretKey secKey = generateKey(key);
// 获取 AES 密码器
Cipher cipher = Cipher.getInstance(TRANSFORM_CBC_PKCS5);
// 初始化密码器(解密模型)
cipher.init(Cipher.DECRYPT_MODE, secKey);
// 解密数据, 返回明文
byte[] plainBytes = cipher.doFinal(cipherBytes);
return plainBytes;
}
public static String decrypt(String decryptText, String key) throws Exception
{
byte[] plainBytes = decrypt(Base64.getDecoder().decode(decryptText.getBytes(CHARSET)), key.getBytes(CHARSET));
return new String(plainBytes, CHARSET);
}
/**
* 生成密钥对象
*/
private static SecretKey generateKey(byte[] key) throws Exception
{
return new SecretKeySpec(key, ALGORITHM);
}
private static byte[] encrypt(byte[] plainBytes, byte[] key) throws Exception
{
// 生成密钥对象
SecretKey secKey = generateKey(key);
// 获取 AES 密码器
Cipher cipher = Cipher.getInstance(TRANSFORM_CBC_PKCS5);
// 初始化密码器(加密模型)
cipher.init(Cipher.ENCRYPT_MODE, secKey);
// 加密数据, 返回密文
byte[] cipherBytes = cipher.doFinal(plainBytes);
return cipherBytes;
}
public static String encrypt(String text, String key) throws Exception
{
byte[] cipherBytes = encrypt(text.getBytes(CHARSET), key.getBytes(CHARSET));
String base64encodedString = Base64.getEncoder().encodeToString(cipherBytes);
return base64encodedString;
}
private static synchronized String md5(String data)
{
MessageDigest digest = null;
if(digest == null)
{
try
{
digest = MessageDigest.getInstance("MD5");
digest.update(data.getBytes(CHARSET));
}
catch(Exception nsae)
{
throw new RuntimeException("Failed to load the MD5 MessageDigest.");
}
}
return byteToHex(digest.digest());
}
private static String byteToHex(byte[] hash)
{
StringBuffer buf = new StringBuffer(hash.length * 2);
int i;
for(i = 0; i < hash.length; i++)
{
if((hash[i] & 0xff) < 0x10)
{
buf.append("0");
}
buf.append(Long.toString(hash[i] & 0xff, 16));
}
return buf.toString();
}
public static String encryptText(String text, String oaKey, String nonce , long timestamp) throws Exception
{
String key = String.format("%s|%s|%s", oaKey, nonce, timestamp);
return encrypt(text, md5(key));
}
public static String decryptText(String text, String oaKey, String nonce , long timestamp) throws Exception
{
String key = String.format("%s|%s|%s", oaKey, nonce, timestamp);
return decrypt(text, md5(key));
}
public static void main(String[] args) throws Exception
{
String e = encryptText("aaaa", "xyr","1234", 12345667);
System.out.println("Base64 编码字符串 (加密) :" + e);
String d = decryptText(e, "xyr","1234", 12345667);
System.out.println("Base64 编码字符串 (原文) :" + d);
}
}
← 1.6 最佳实现示例 2.2 最佳实现示例 →