@18612183942
2019-04-15T09:18:06.000000Z
字数 8698
阅读 49
| 文档版本 | 修订记录 | 修订人 | 修订时间 |
|---|---|---|---|
| v1.0 | 文档创建 | 杨金奎 | 2019-04-15 |
本文档定义了酒店客户信息与助销客平台的对接。
用户名:yangjinkui
密钥:12345678
版本号:v1.0
接口地址:http://service.zhuxiaoke.cn/Tongcheng/ProcessRequest/
测试产品:1000101639
双方按约定的加密规则进行加密认证,防止数据篡改和伪造。
(1) 加密方式:MD5,32 位小写;
(2) 拼接接口中的公用参数,请求内容报文requestBody,user_key;
(3) 签名方法:
sign=md5(user_id+method+timestamp+version+requestBody+user_key) ;
(4)平台接收到请求报文后,按照相同的签名算法进行加密,将双方的 sign 进行比对,如果一致,则验证通。
(1)接口采用http post方式,返回数据格式为json格式;
(2)统一采用utf-8编码。
| 参数名 | 说明 | 参数类型 | 是否必须 |
|---|---|---|---|
| user_id | 用户标识,由助销客提供 | string | 是 |
| method | 方法名 | string | 是 |
| timestamp | 时间戳,时间标准为 UTC,取当前请求时间时间格式为 2016/5/25 21:36:44 精确到秒然后转化为时间戳 | int | 是 |
| version | 版本号,根据接口版本传入 | string | 是 |
| sign | 签名,用于安全校验 | string | 是 |
| 参数名 | 说明 | 参数类型 | 是否必须 |
|---|---|---|---|
| pageIndex | 查询页索引 | int | 是 |
| pageSize | 查询数量 | int | 是 |
| productNo | 产品编号 | string | 否 |
| sceneryNo | 景区编号 | string | 否 |
sign:计算方法 Md5(user_id+method+timestamp+version+requestBody+user_key)
明文(MD5 前):yangjinkuiGetProductInfo1458871246v1.0IPd5HD/HsjyMK7b1JALkopqhDlrgrV3zTEzyThrof28=12345678
签名(MD5 后-小写):2ba56cd0a986fe8e4d9815444594620b
将json格式的业务参数进行des加密,加密模式ECB充方式 PKCS7Padding,密钥为user_key。
传入requestBody参数 {"pageIndex": 1,"pageSize": 10}
传入Userkey参数12345678
Des(requestBody,userkey)= IPd5HD/HsjyMK7b1JALkopqhDlrgrV3zTEzyThrof28
{
"requestHead": {
"user_id": "yangjinkui",
"method": "GetProductInfo",
"timestamp": 1458871246,
"version": "v1.0",
"sign": "2ba56cd0a986fe8e4d9815444594620b"
},
"requestBody": "IPd5HD/HsjyMK7b1JALkopqhDlrgrV3zTEzyThrof28="
}
| 参数名 | 说明 | 参数类型 | 是否必须 |
|---|---|---|---|
| res_code | 响应码 | string | 是 |
| res_msg | 响应消息 | string | 是 |
| timestamp | 时间戳,时间标准为 UTC,取当前请求时间 | int | 是 |
| 参数名 | 说明 | 参数类型 | 是否必须 |
|---|---|---|---|
| totalCount | 产品总数量 | long | 是 |
| productList | 产品列表 | object[] | 是 |
将json格式的业务参数进行des加密,密钥为user_key。
responseBody: {
"totalCount": 1,
"productList": [
{
"productNo": "Test01",
"productName": "测试产品 01",
"retailPrice": 5000,
"webPrice": 4700,
"contractPrice": 4300,
"sceneryNo": "",
"sceneryName": "",
"payType": 2,
"beginDate": "2016-05-01",
"endDate": "2016-06-11",
"shieldDate": "",
......
}
]
}
{
"responseHead": {
"res_code": "1000",
"res_msg": "成功",
"timestamp": 1529979752
},
"responseBody": "des加密字符串,需解密"
}
方法名:PushHotelMember
调用方:酒管系统
响应方:助销客开放平台
接口说明:酒管系统调用此接口向助销客平台传送酒店客户信息。
| 参数名 | 类型 | 描述 | 是否必传 |
|---|---|---|---|
| hotelName | string | 酒店名称 | 是 |
| name | string | 姓名 | 是 |
| checkinDate | string | 入住日期(yyyy-MM-dd) | 是 |
| checkoutDate | string | 退房日期(yyyy-MM-dd) | 是 |
| roomName | string | 房间名称 | 是 |
| idType | int | 证件类型(10 身份证 20 其他) | 是 |
| idNo | string | 证件号码 | 是 |
| address | string | 详细地址 | 否 |
| sex | string | 性别 | 否 |
无
{
"requestHead": {
"user_id": "yangjinkui",
"method": "PushHotelMember",
"timestamp": 1458871246,
"version": "v1.0",
"sign": "55af2e19e8efa6f7609c9a7e23903fc1"
},
"requestBody": {
"hotelName": "城市之家酒店",
"name":"代",
"checkinDate":"2019-04-15",
"checkoutDate":"2019-04-16",
"roomName":"B201",
"idType":10,
"idNo":"110222199501016410",
"address":"河北邯郸",
"sex":"男"
}
}
注:实际交互中 requestBody 是用 des 加密后的一串文本。
{
"requestHead": {
"user_id": "yangjinkui",
"method": "PushHotelMember",
"timestamp": 1458871246,
"version": "v1.0",
"sign": "55af2e19e8efa6f7609c9a7e23903fc1"
},
"requestBody": "h6MmkCEzEpQJDu+vvRJiFPGfM9oZ2Z0zsf1wuMLt34r48wJVk0gUHA=="
}
{
"responseHead": {
"res_code": "1000",
"res_msg": "操作成功",
"timestamp": 1530681252
},
"responseBody": ""
}
注:实际交互中 responseBody 是用 des 加密后的一串文本。
{
"responseHead": {
"res_code": "1000",
"res_msg": "成功",
"timestamp": 1530681252
},
"responseBody": ""
}
| 类型 | 错误码 | 说明 |
|---|---|---|
| 成功 | 1000 | 成功(如果贵方系统中订单已经生成或者已经取消就按正常返回) |
| 推送酒店客户信息失败 | 6001 | 推送酒店客户信息失败 |
| 通用错误 | 5001 | 订单号不存在或已作废 |
| 通用错误 | 5002 | 余额不足 |
| 通用错误 | 5003 | 签名验证失败 |
| 通用错误 | 5004 | 数据出错或为空 |
| 通用错误 | 5005 | 合作方系统出错 |
/// <summary>
/// des加密
/// </summary>
/// <param name="encryptString"></param>
/// <param name="encryptKey"></param>
/// <returns></returns>
private string Encrypt(string encryptString, string encryptKey)
{
string returnValue;
try
{
byte[] temp = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
byte[] byteEncrypt = Encoding.UTF8.GetBytes(encryptString);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(Encoding.UTF8.GetBytes(encryptKey), temp), CryptoStreamMode.Write);
cryptoStream.Write(byteEncrypt, 0, byteEncrypt.Length);
cryptoStream.FlushFinalBlock();
returnValue = Convert.ToBase64String(memoryStream.ToArray());
}
catch (Exception ex)
{
throw ex;
}
return returnValue;
}
/// <summary>
/// des解密
/// </summary>
/// <param name="decryptString"></param>
/// <param name="decryptKey"></param>
/// <returns></returns>
public static string Decrypt(string decryptString, string decryptKey)
{
string returnValue;
try
{
byte[] temp = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
byte[] byteDecryptString = Convert.FromBase64String(decryptString);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateDecryptor(Encoding.UTF8.GetBytes(decryptKey), temp), CryptoStreamMode.Write);
cryptoStream.Write(byteDecryptString, 0, byteDecryptString.Length);
cryptoStream.FlushFinalBlock();
returnValue = Encoding.UTF8.GetString(memoryStream.ToArray());
}
catch (Exception ex)
{
throw ex;
}
return returnValue;
}
package com.afreon.util;
import java.io.IOException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* Description 根据键值进行加密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception {
byte[] bt = encrypt(data.getBytes("UTF-8"), key.getBytes("UTF-8"));
String strs = new BASE64Encoder().encode(bt);
return strs;
}
/**
* Description 根据键值进行解密
* @param data
* @param key 加密键byte数组
* @return
* @throws IOException
* @throws Exception
*/
public static String decrypt(String data, String key) throws Exception,
Exception {
if (data == null)
return null;
BASE64Decoder decoder = new BASE64Decoder();
byte[] buf = decoder.decodeBuffer(data);
byte[] bt = decrypt(buf,key.getBytes("UTF-8"));
return new String(bt, "UTF-8");
}
/**
* Description 根据键值进行加密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密钥初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return cipher.doFinal(data);
}
/**
* Description 根据键值进行解密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密钥初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
return cipher.doFinal(data);
}
<?php
class Des
{
private $key = "";
private $iv = "";
/**
* 构造,传递二个已经进行base64_encode的KEY与IV
*
* @param string $key
* @param string $iv
*/
function __construct($key, $iv)
{
if (empty($key) || empty($iv)) {
echo 'key and iv is not valid';
exit();
}
$this->key = $key;
$this->iv = $iv;
}
/**
*加密
* @param <type> $value
* @return <type>
*/
public function encrypt($value)
{
$td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
$iv = base64_decode($this->iv);
$value = $this->PaddingPKCS7($value);
$key = base64_decode($this->key);
mcrypt_generic_init($td, $key, $iv);
$ret = base64_encode(mcrypt_generic($td, $value));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $ret;
}
/**
*解密
* @param <type> $value
* @return <type>
*/
public function decrypt($value)
{
$td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
$iv = base64_decode($this->iv);
$key = base64_decode($this->key);
mcrypt_generic_init($td, $key, $iv);
$ret = trim(mdecrypt_generic($td, base64_decode($value)));
$ret = $this->UnPaddingPKCS7($ret);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $ret;
}
private function PaddingPKCS7($data)
{
$block_size = mcrypt_get_block_size('tripledes', 'cbc');
$padding_char = $block_size - (strlen($data) % $block_size);
$data .= str_repeat(chr($padding_char), $padding_char);
return $data;
}
private function UnPaddingPKCS7($text)
{
$pad = ord($text{strlen($text) - 1});
if ($pad > strlen($text)) {
return false;
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
return false;
}
return substr($text, 0, -1 * $pad);
}
private function pkcs5_unpad($text)
{
$pad = ord($text{strlen($text)-1});
if ($pad > strlen($text)) return false;
return substr($text, 0, -1 * $pad);
}
}
//使用
$key = 'test1234';
$iv = 'test1234';
$msg = '{"pageIndex":1,"pageSize":10,"productNo":"","sceneryNo":""}';
$des = new Des(base64_encode($key), base64_encode($iv));
$rs1 = $des->encrypt($msg);
echo $rs1 . '<br />';
$rs2 = $des->decrypt($rs1);
echo $rs2;
?>