|
|
@@ -0,0 +1,183 @@
|
|
|
+package org.thyy.thirdpartapi.casign.service;
|
|
|
+
|
|
|
+import cn.hutool.core.bean.BeanUtil;
|
|
|
+import cn.hutool.core.util.IdUtil;
|
|
|
+import cn.hutool.core.util.URLUtil;
|
|
|
+import cn.hutool.http.HttpRequest;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import jakarta.validation.constraints.NotNull;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.thyy.thirdpartapi.YesOrNo;
|
|
|
+import org.thyy.thirdpartapi.casign.CaConfig;
|
|
|
+import org.thyy.thirdpartapi.casign.UserCaInterface;
|
|
|
+import org.thyy.thirdpartapi.casign.CaUtils;
|
|
|
+import org.thyy.thirdpartapi.casign.dto.CaSendParams;
|
|
|
+import org.thyy.thirdpartapi.casign.dto.CaSignClass;
|
|
|
+import org.thyy.thirdpartapi.casign.vo.CaReturn;
|
|
|
+import org.thyy.thirdpartapi.emr.service.CaWSDL;
|
|
|
+import org.thyy.thirdpartapi.emr.vo.CaSendByCodeVo;
|
|
|
+import org.thyy.utils.exception.BizException;
|
|
|
+import org.thyy.utils.exception.ExceptionEnum;
|
|
|
+import org.thyy.utils.result.R;
|
|
|
+import org.thyy.utils.result.ResultVo;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class ShangHaiCa implements UserCaInterface {
|
|
|
+ private final CaConfig config;
|
|
|
+ private final String SUCCRSS = "success";
|
|
|
+
|
|
|
+ public ShangHaiCa(CaConfig config) {
|
|
|
+ this.config = config;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultVo<List<CaSendByCodeVo>> sendBatchByCode(CaSignClass.Send send) {
|
|
|
+ List<CaSendByCodeVo> returnValue = new ArrayList<>();
|
|
|
+ send.setCount(send.getCount() == null ? 1 : send.getCount());
|
|
|
+ for (int i = 0; i < send.getCount(); i++) {
|
|
|
+ ResultVo<CaSendByCodeVo> caSendByCodeVoResultVo = sendByCode(send);
|
|
|
+ if (ExceptionEnum.SUCCESS.getCode().equals(caSendByCodeVoResultVo.getCode())) {
|
|
|
+ returnValue.add(caSendByCodeVoResultVo.getData());
|
|
|
+ } else {
|
|
|
+ return R.fail(caSendByCodeVoResultVo.getCode(), caSendByCodeVoResultVo.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return R.ok(returnValue);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultVo<CaSendByCodeVo> sendByCode(CaSignClass.Send send) {
|
|
|
+ if (config.getMobileApp() == null) {
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR, "未配置ca签名请联系管理员");
|
|
|
+ }
|
|
|
+ String msg = CaUtils.GetSHA256FormString(send.getMsg());
|
|
|
+ CaSendParams params = CaSendParams.builder()
|
|
|
+ .id(send.getId())
|
|
|
+ .bizSn(IdUtil.simpleUUID())
|
|
|
+ .msg(msg)
|
|
|
+ .desc(send.getDesc())
|
|
|
+ .appId(config.getMobileApp().getAppId())
|
|
|
+ .msgWrapper("0")
|
|
|
+ .desc(URLUtil.encode(send.getDesc()))
|
|
|
+ .url(URLUtil.encode("http://127.0.0.1"))
|
|
|
+ .mode("redirect")
|
|
|
+ .sign(CaUtils.getSign(config.getMobileApp().getPrivatekey(), msg))
|
|
|
+ .build();
|
|
|
+
|
|
|
+ Map<String, Object> stringObjectMap = BeanUtil.beanToMap(params);
|
|
|
+
|
|
|
+ String execute = HttpRequest.post(config.getMobileApp().getUrl() + "/v1/push/sign")
|
|
|
+ .header("Content-Type", "application/x-www-form-urlencoded")
|
|
|
+ .form(stringObjectMap)
|
|
|
+ .execute().body();
|
|
|
+ String decode = URLUtil.decode(execute);
|
|
|
+ log.info("返回数据:{}", decode);
|
|
|
+ CaReturn caReturn = JSONUtil.toBean(decode, CaReturn.class);
|
|
|
+
|
|
|
+ if (!SUCCRSS.equals(caReturn.getRet())) {
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR, "签名失败。" + caReturn.getMsg());
|
|
|
+ }
|
|
|
+ if (Integer.valueOf(1).equals(caReturn.getData().getIsTrust())) {
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR, "签名失败,请用户打开免密签名。");
|
|
|
+ }
|
|
|
+
|
|
|
+ CaReturn.CaData data = caReturn.getData();
|
|
|
+
|
|
|
+ signatureAuthentication(msg, caReturn);
|
|
|
+ String timeStamp = generateTimestampByInData(msg);
|
|
|
+
|
|
|
+ CaSendByCodeVo build = CaSendByCodeVo
|
|
|
+ .builder()
|
|
|
+ .timeStamp(timeStamp)
|
|
|
+ .bizSn(params.getBizSn())
|
|
|
+ .cert(data.getCert())
|
|
|
+ .signAlg(data.getSignAlg())
|
|
|
+ .certSn(data.getCertSn())
|
|
|
+ .signValue(data.getSignValue())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ return R.ok(build);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void signatureAuthentication(String msg, CaReturn caReturn) {
|
|
|
+ CaConfig.SignAuthentication signData = config.getSignAuthentication();
|
|
|
+ CaWSDL caWSDL = new CaWSDL(signData.getUrl());
|
|
|
+ String replace = getVerifySignDataParams(msg, caReturn, signData);
|
|
|
+ JSONObject rst = caWSDL.invoke("verifySignData", replace);
|
|
|
+ log.info("认证签名xml:{}\n认证签名返回值:{}\n", replace, rst.toString());
|
|
|
+ Integer code = rst.getByPath("Root.RetCode", Integer.class);
|
|
|
+ if (!YesOrNo.YES.getCode().equals(code)) {
|
|
|
+ String rstmsg = rst.getByPath("Root.RetMsg", String.class);
|
|
|
+ throw new BizException(ExceptionEnum.LOGICAL_ERROR, rstmsg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static @NotNull String getVerifySignDataParams(String msg, CaReturn caReturn, CaConfig.SignAuthentication signData) {
|
|
|
+ String request = """
|
|
|
+ <?xml version="1.0" encoding="UTF-8" ?>
|
|
|
+ <Root>
|
|
|
+ \t<AppCode>${AppCode}</AppCode>
|
|
|
+ \t<AppPWD>${AppPWD}</AppPWD>
|
|
|
+ \t<Request>
|
|
|
+ \t\t<Cert>${Cert}</Cert>
|
|
|
+ \t\t<SignAlg>${SignAlg}</SignAlg>
|
|
|
+ \t\t<InData>${InData}</InData>
|
|
|
+ \t\t<SignData>${SignData}</SignData>
|
|
|
+ \t</Request>
|
|
|
+ </Root>""";
|
|
|
+
|
|
|
+ return request.replace("${AppCode}", signData.getAppCode())
|
|
|
+ .replace("${AppPWD}", signData.getAppPwd())
|
|
|
+ .replace("${Cert}", caReturn.getData().getCert())
|
|
|
+ .replace("${SignAlg}", signData.getSignAig())
|
|
|
+ .replace("${InData}", msg)
|
|
|
+ .replace("${SignData}", caReturn.getData().getSignValue());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 认证时间戳并返回
|
|
|
+ *
|
|
|
+ * @param msg 数据
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String generateTimestampByInData(String msg) {
|
|
|
+ String data = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
|
|
|
+ "<Root>\n" +
|
|
|
+ "\t<AppCode>${AppCode}</AppCode>\n" +
|
|
|
+ "\t<AppPWD>${AppPWD}</AppPWD>\n" +
|
|
|
+ "\t<Request>\n" +
|
|
|
+ "\t\t<InData>${InData}</InData>\n" +
|
|
|
+ "<HashAlg>${HashAlg}</HashAlg>\n" +
|
|
|
+ "<CertReq>${CertReq}</CertReq>\n" +
|
|
|
+ "\t</Request>\n" +
|
|
|
+ "</Root>";
|
|
|
+
|
|
|
+ CaConfig.TimestampAuthentication timeData = config.getTimestampAuthentication();
|
|
|
+ String request = data.replace("${AppCode}", timeData.getAppCode())
|
|
|
+ .replace("${AppPWD}", timeData.getAppPwd())
|
|
|
+ .replace("${InData}", msg)
|
|
|
+ .replace("${HashAlg}", "SHA256")
|
|
|
+ .replace("${CertReq}", "true");
|
|
|
+
|
|
|
+ CaWSDL caWSDL = new CaWSDL(timeData.getUrl());
|
|
|
+ JSONObject ret = caWSDL.invoke("generateTimestampByInData", request);
|
|
|
+ Integer code = ret.getByPath("Root.RetCode", Integer.class);
|
|
|
+ log.info("认证时间戳xml:{}\n认证时间戳返回值:{}\n", request, ret);
|
|
|
+ if (code != 1) {
|
|
|
+ String retmsg = ret.getByPath("Root.RetMsg", String.class);
|
|
|
+ throw new BizException(ExceptionEnum.LOGICAL_ERROR, retmsg);
|
|
|
+ }
|
|
|
+ return ret.getByPath("Root.Response.TimeStamp", String.class);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|