在應(yīng)用中有時(shí)需要集成第三方接口,比如:支付寶、微信支付等,但是也會(huì)有己方作為服務(wù)提供方的時(shí)候。
這里提供一種簡單而安全的方式實(shí)現(xiàn)這種需求,考慮的因素比較少,就像是前后端分離的普通接口,只是換了驗(yàn)證方式。
準(zhǔn)備
建一張第三方賬戶表:transa_user_ip
,里面邏輯字段是:ipKey(請求key)、ipSecret(請求密鑰)、ipAddress(請求IP地址集)、ifIp(是否開啟驗(yàn)證)。
每個(gè)接入方都有一條數(shù)據(jù),ipKey相當(dāng)于用戶名,ipSecret相當(dāng)于用戶密碼,使用一些復(fù)雜字符串,比如32位長度隨機(jī)生成,會(huì)在每次請求中攜帶。
可以考慮再建一張請求日志流水表,只是做記錄,為每次請求記錄,最好加上隨機(jī)時(shí)間戳,扯皮的時(shí)候就拿出來。
以上兩張表考慮性能的話可以放在Redis里面。
示例:ipKey=key、ipSecret=secret
請求 API
假如接口邏輯是請求交易,提交字段如下:
- 請求路徑:transa/exchange
- 請求方法:POST
- 請求參數(shù)
參數(shù)名稱 | 必選 | 類型 | 說明 |
---|---|---|---|
key | 是 | string | key標(biāo)識(shí) |
sign | 是 | string | 簽名 |
rechargeTime | 是 | string | 充值時(shí)間 |
rechargeAmount | 是 | double | 充值數(shù)額,精度兩位,如:111.23 |
requestUserUuid | 是 | string | 登錄人uuid |
outTradeNo | 是 | string | 交易流水號 |
- 提交參數(shù)示例
{
"rechargeTime": "1542194359409",
"rechargeAmount": 11.1,
"requestUserUuid": "70925caa-5933-4a8a-bcc4-8f88d7116983",
"outTradeNo": "xp1542194359455",
"key": "key",
"sign": "4686ee448dd14047d845fa3cb589e938"
}
- 請求Java示例代碼
@Test
public void exchange() throws Exception {
// 待提交數(shù)據(jù)
String rechargeTime = System.currentTimeMillis()+"";
Double rechargeAmount = 11.10;
String requestUserUuid = UUID.randomUUID().toString();
String outTradeNo = "xp"+System.currentTimeMillis();
// 對 密鑰 md5加密,文檔表明加密方式
String secret = DigestUtils.md5Hex("secret");
// 拼接 sign 原始數(shù)據(jù)
StringBuffer sb = new StringBuffer();
sb.append("rechargeTime=").append(rechargeTime);
sb.append("&rechargeAmount=").append(rechargeAmount);
sb.append("&requestUserUuid=").append(requestUserUuid);
sb.append("&outTradeNo=").append(outTradeNo);
sb.append("&secret").append(secret);
// 生成 sign
String sign = DigestUtils.md5Hex(sb.toString());
logger.info("....sb:"+sb.toString());
logger.info("....sign:"+sign);
// 提交請求對象
RechargeTransaRequest request = new RechargeTransaRequest();
request.setKey("key");
request.setRechargeTime(rechargeTime);
request.setRechargeAmount(rechargeAmount);
request.setRequestUserUuid(requestUserUuid);
request.setOutTradeNo(outTradeNo);
request.setSign(sign);
// 轉(zhuǎn)成JSON 提交
HttpClientUtil.executePost(url, ConfigInfo.getGson().toJson(request));
}
服務(wù)器處理
思路是把上面的過程再做一遍。
- 判斷 key 是否非空,然后在數(shù)據(jù)庫里查找
- 判斷請求字段非空
- 請求字段驗(yàn)證通過,通過 key 找到服務(wù)器保存的 secret
- 生成驗(yàn)證sign,并與請求過來的sign比較,sign簽名原始數(shù)據(jù)順序保存一致
服務(wù)器響應(yīng)編碼與說明需要注意整齊
,看起來很專業(yè)。
ipAddress 字段可以進(jìn)一步加強(qiáng)安全,看情況使用。