package com.gustz.dove.cli.api.security.service.impl;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import com.gustz.dove.cli.api.security.service.wxaes.WXBizMsgCrypt;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.gustz.dove.cli.api.app.service.impl.ClientAppService;
import com.gustz.dove.cli.api.app.vo.ClientAppVo;
import com.sinovatech.rd.wcsb.cli.api.security.service.EncryptService;
import com.sinovatech.rd.wcsb.cli.api.security.service.SignService;
import com.gustz.dove.cli.api.service.conf.BaseWcsbConf;
import com.gustz.dove.cli.api.service.impl.AbstBaseService;
import com.gustz.dove.cli.api.service.util.AppLogStyle;
import com.gustz.dove.cli.api.service.util.ClientConstants;
/**
*
* TODO: 验证签名服务的接口实现
*
* @author ZHENFENG ZHANG
* @since [ Aug 3, 2015 ]
*/
@Service
public class SignServiceImpl extends AbstBaseService<String> implements SignService {
@Autowired
private EncryptService encryptService;
@Autowired
private BaseWcsbConf baseWcsbConf;
@Autowired
private ClientAppService clientAppService;
/**
* 验证订阅、服务号加密签名
*
* <pre>
* 1.将token、timestamp、nonce三个参数进行字典序排序。
* 2.将三个参数字符串拼接成一个字符串进行sha1加密。
* 3.开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。
* </pre>
* @param signature 加密签名
* @param timestamp 时间戳
* @param nonce 随机数
* @return
*/
@Override
public boolean checkMpSign(String signature, String timestamp, String nonce) {
boolean flag = false;
AppLogStyle appLogs = new AppLogStyle();
appLogs.begin(String.format("验证订阅、服务号加密签名,signature[ %1$s ],timestamp[ %2$s ],nonce[ %3$s ].", signature, timestamp,
nonce));
//
long _nowTt = (new Date().getTime() / 1000);
try {
// 签名有效时间间隔,单位:秒。 1439783917499 1439783899
long _ttLimit = baseWcsbConf.getTimestampLimit();
if (Math.abs(_nowTt - Long.parseLong(timestamp)) <= _ttLimit) {
// 将token、timestamp、nonce三个参数进行字典排序
String[] _tmps = new String[] { this.getCurrDevToken(), timestamp, nonce };
Arrays.sort(_tmps);
String content = "";
for (int i = 0, len = _tmps.length; i < len; i++) {
content += _tmps[i];
}
// 将三个参数字符串拼接成一个字符串进行sha1加密
MessageDigest md = MessageDigest.getInstance(ClientConstants.SHA_ALGO);
content = Hex.encodeHexString(md.digest(content.getBytes()));
// 将sha1加密后的字符串与signature对比
flag = (content != null && !content.isEmpty()) ? content.equals(signature) : false;
if (flag) {
clientAppService.enableCliApp(); // 配置授权成功,修改APP状态为启用。
appLogs.runtime("验证订阅、服务号加密签名成功,启用该客户端APP。");
}
} else {
appLogs.runtimeWarn(String.format("订阅、服务号重复签名signature[ %1$s ],timestamp[ %2$s ],nonce[ %3$s ]. \n", signature,
timestamp, nonce));
}
} catch (Exception e) {
appLogs.error("验证订阅、服务号加密签名异常 \n", e);
} finally {
appLogs.end(String.format("验证订阅、服务号加密签名,flag=:%1$s ", flag));
}
return flag;
}
private String getCurrDevToken() throws NoSuchAlgorithmException {
ClientAppVo vo = clientAppService.getCurrCliApp();
//
return encryptService.getDevToken(vo.getAccountCode(), vo.getWecAppId());
}
/**
* 验证企业号加密签名
*
* @param msgSignature
* @param timestamp
* @param nonce
* @param echoStr
* @return
* @throws Exception
*/
@Override
public String checkCpSign(String signature, String timestamp, String nonce, String echoStr) throws Exception {
AppLogStyle appLogs = new AppLogStyle();
appLogs.begin(String.format("验证企业号加密签名,signature[ %1$s ],timestamp[ %2$s ],nonce[ %3$s ].", signature, timestamp, nonce));
//
ClientAppVo _appVo = clientAppService.getCurrCliApp();
if (_appVo == null) {
throw new IllegalStateException("该客户端APP不是接入状态");
}
final String cliAppCode = _appVo.getCliAppCode();
final String devAcCode = _appVo.getAccountCode();
final String wecAppId = _appVo.getWecAppId();
//
final String devToken = encryptService.getDevToken(devAcCode, wecAppId);
final String devAesKey = encryptService.getDevAesKeyt(cliAppCode, devAcCode, wecAppId);
//
WXBizMsgCrypt msgCrypt = new WXBizMsgCrypt(devToken, devAesKey, _appVo.getWecAppId());
// 执行校验
String _retVal = msgCrypt.verifyUrl(signature, timestamp, nonce, echoStr);
if (StringUtils.isNotBlank(_retVal)) {
clientAppService.enableCliApp(); // 配置授权成功,修改APP状态为启用。
appLogs.runtime("验证企业号加密签名成功,启用该客户端APP。");
}
return _retVal;
}
@Override
protected void setAccessTokenX(long sn, String cliAppCode, String devAcCode) {
//ignored
}
}