多因素

This commit is contained in:
jlzhangyx5
2023-08-25 09:54:50 +08:00
parent 2c9374c483
commit 62e00afee9
12 changed files with 579 additions and 1 deletions

View File

@ -24,6 +24,15 @@
</dependency>
<!-- 证书加密签名 -->
<dependency>
<groupId>com.cuca</groupId>
<artifactId>cucasecuritysdk</artifactId>
<version>1.7</version>
<!-- <scope>system</scope>-->
<!-- <systemPath>${project.basedir}/libs/cucasecuritysdk-1.7.jar</systemPath>-->
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>

View File

@ -27,6 +27,13 @@ public interface ICrypConfigureService extends IBaseService<CrypConfigure> {
* @return
*/
String callUniInterfaceJson(CrypBean bean);
/**
* 调用天擎接口
* @param bean
* @return true/false
*/
Boolean callUniInterfaceMessage(CrypBean bean);
/**
* 加载失败日志再发送
* @param

View File

@ -207,6 +207,76 @@ public class CrypConfigureServiceImpl extends BaseServiceImpl<CrypConfigureMappe
return str;
}
@Override
public Boolean callUniInterfaceMessage(CrypBean bean) {
log.info("多因素------callUniInterfaceMessage---入参-----" + JSON.toJSONString(bean));
BlockChainLog blockChainLog = new BlockChainLog();
blockChainLog.setId(PropertyUtils.getSnowflakeId());
//天擎地址
if ("1mb6n6635cJkDb3pEQPUFXc2nRJ8RPaS".equals(app_secret)) {
//测试环境
bean.setUrl(bean.getUrl().replace(app_url, app_url_test));
PEM_PATH = "admin_certPrivateNew.pem";
CRT_PATH = "adminNew.crt";
} else {
PEM_PATH = "bidding_certPrivate.pem";
CRT_PATH = "bidding.crt";
//生产环境
bean.setUrl(bean.getUrl().replace(app_url_test, app_url));
}
log.info("加密文件:" + PEM_PATH);
log.info("解密文件:" + CRT_PATH);
log.info("请求路径:" + bean.getUrl());
blockChainLog.setInterfaceUrl(bean.getUrl());
String json = "";
String str = "";
try {
Map<String, Object> map = JSONArray.parseObject(JSONArray.toJSONString(bean.getObject()), Map.class);
log.info("多因素map------callUniInterfaceMessage---入参map-----" + JSON.toJSONString(map));
//传入数据解密
String sign = getSignValue(map);
// map.put("SIGN", sign);
json = getUniBssMessage(bean.getReqName(), map);
blockChainLog.setParam(json);//请求参数
str = UniBssServiceImpl.uniBssHttpPost(bean.getUrl(), json);
blockChainLog.setResult(str);//返回参数
UniBss uniBssRsp = JSONArray.parseObject(str, UniBss.class);
if (uniBssRsp != null && UniBssConstant.RESP_CODE_00000.equals(uniBssRsp.getUniBssHead().getRespCode())) {
System.out.println("返回接口:" + uniBssRsp);
if (str != null && !"".equals(str) && str.indexOf("_RSP\":{\"Code\":200,") >= 0) {
blockChainLog.setStatus(0);//成功
this.iBlockChainLogService.save(blockChainLog);
return true;
} else {
blockChainLog.setStatus(1);//失败
}
} else {
blockChainLog.setStatus(1);//失败
CommonExceptionEnum.FRAME_EXCEPTION_COMMON_DATA_OTHER_ERROR.assertStringNotNullByKey("天擎多因素接口调用错误," +
"RESP_CODE:" + uniBssRsp.getUniBssHead().getRespCode() + "" +
"(" + UniBssConstant.getRESP_CODE_Map(uniBssRsp.getUniBssHead().getRespCode()) + ")。" +
"RESP_DESC:" + uniBssRsp.getUniBssHead().getRespDesc(), bean);
}
} catch (Exception e) {
blockChainLog.setStatus(1);
blockChainLog.setResult(e.getMessage());
}finally {
if(blockChainLog.getStatus().equals(1)){
log.error("多因素调用失败!~-----------------");
operationLogService.addOperationLog("多因素同步失败信息,参数{}"+json+"返回信息{}"+str,false, EbtpLogBusinessModule.OTHER, EbtpLogType.INSERT);
}
}
return false;
}
/**
* 加载失败日志再发送
*
@ -384,7 +454,7 @@ public class CrypConfigureServiceImpl extends BaseServiceImpl<CrypConfigureMappe
req.setBody(map);
req.setHead(reqhead);
log.info("业务参数封装中:" + req);
;
Map reqMap = new HashMap();
reqMap.put(reqName, req);
uniBss.setUniBssBodyMap(reqMap);
@ -393,6 +463,30 @@ public class CrypConfigureServiceImpl extends BaseServiceImpl<CrypConfigureMappe
return JSON.toJSONString(uniBss);
}
/**
* 获取加密签名
*
* @param map
* @return
*/
private String getUniBssMessage(String reqName, Map<String, Object> map) {
UniBss uniBss = new UniBss();
uniBss.setUniBssAttached(new UniBssAttached().setMediaInf(""));
//天擎部分head
UniBssUtil util = new UniBssUtil(app_id, app_secret);
uniBss.setUniBssHead(util.getUniBssHead());
log.info("业务参数封装前:" + map);
Map reqMap = new HashMap();
reqMap.put(reqName, map);
uniBss.setUniBssBodyMap(reqMap);
log.info("业务参数封装后:" + JSON.toJSONString(reqMap));
log.info("业务参数封装后uniBss" + JSON.toJSONString(uniBss));
return JSON.toJSONString(uniBss);
}
/**
* 中信天擎接口 数据格式 获取加密签名
* REQ:{

View File

@ -0,0 +1,141 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.controller;
import com.chinaunicom.mall.ebtp.common.base.entity.BaseResponse;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.SmsSendRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.nio.charset.StandardCharsets;
import java.util.List;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.BizShortMessage;
import com.chinaunicom.mall.ebtp.extend.shortmessage.service.BizShortMessageService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@RestController
@Api(value = "多因素短信发送记录")
@RequestMapping("/v1/bizshortmessage")
public class BizShortMessageController{
@Resource
private BizShortMessageService iBizShortMessageService;
/**
* 认证短信验证码发送
* appCode 应用标识
* bizSn 流水号 调用方生成 保持唯一
* userAccount 应用系统账号
* privateKey 调用方私钥
* mobile 手机号
* authCode 验证码
* callbackUrl UrlEncode编码 应用系统回调确认用户有效性的地址,应用系统传了这个地址则用户有效性由该地址确定
*/
@PostMapping("/send/authCode")
public BaseResponse<Boolean> authCodeSend(@RequestParam String mobile){
return BaseResponse.success(iBizShortMessageService.authCodeSend(mobile));
}
/**
* 认证短信验证码发送
* appCode 应用标识
* bizSn 流水号 调用方生成 保持唯一
* userAccount 应用系统账号
* privateKey 调用方私钥
* mobile 手机号
* authCode 验证码
* callbackUrl UrlEncode编码 应用系统回调确认用户有效性的地址,应用系统传了这个地址则用户有效性由该地址确定
*/
@PostMapping("/check/authCode")
public BaseResponse<Boolean> authCodeCheck(@RequestParam String mobile,
@RequestParam String authCode){
return BaseResponse.success(iBizShortMessageService.authCodeCheck(mobile, authCode));
}
/**
* 插入新数据
*
* @param bizShortMessage
*
* @return
*/
@ApiOperation("插入新数据")
@PostMapping
public BaseResponse<Boolean> insert(@ApiParam(value = "对象数据", required = true) @RequestBody @Valid BizShortMessage bizShortMessage){
Boolean i = iBizShortMessageService.save(bizShortMessage);
return BaseResponse.success(i);
}
/**
* 修改数据
*
* @param bizShortMessage
*
* @return
*/
@ApiOperation("修改数据")
@PutMapping
public BaseResponse<Boolean> update(@ApiParam(value = "对象数据", required = true) @RequestBody BizShortMessage bizShortMessage){
Boolean i = iBizShortMessageService.updateById(bizShortMessage);
return BaseResponse.success(i);
}
/**
* 查询数据
*
* @param id
*
* @return
*/
@ApiOperation("根据id查询数据")
@GetMapping("/{id}")
public BaseResponse<BizShortMessage> get(@ApiParam(value = "主键id", required = true) @PathVariable String id){
BizShortMessage bizShortMessage = iBizShortMessageService.getById(id);
return BaseResponse.success(bizShortMessage);
}
/**
* 删除数据
* @param id 主键id
* @return BaseResponse<Boolean>
* @author dino
* @date 2020/10/21 14:56
*/
@ApiOperation(value = "delete",notes = "删除数据")
@DeleteMapping("/{id}")
public BaseResponse<Boolean> delete(@ApiParam(value = "主键id", required = true) @PathVariable Long id) {
Boolean i = iBizShortMessageService.removeById(id);
return BaseResponse.success(i);
}
/**
* 查询数据
*
* @param param
* @return
*/
@ApiOperation("查询列表数据")
@GetMapping("/list")
public BaseResponse<List<BizShortMessage>> list(@ApiParam(value = "查询对象数据", required = false) BizShortMessage param) {
//查询
LambdaQueryWrapper<BizShortMessage> query = Wrappers.lambdaQuery(param);
List<BizShortMessage> list = iBizShortMessageService.list(query);
//异常处理
//RespsExceptionEnum.FRAME_EXCEPTION_DEMO_NOT_FIND.customValid(list.isEmpty());
return BaseResponse.success(list);
}
}

View File

@ -0,0 +1,11 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.dao;
import com.chinaunicom.mall.ebtp.common.base.dao.IBaseMapper;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.BizShortMessage;
@Repository
public interface BizShortMessageMapper extends IBaseMapper<BizShortMessage> {
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chinaunicom.mall.ebtp.extend.shortmessage.dao.BizShortMessageMapper">
<resultMap id="sysResultMap" type="com.chinaunicom.mall.ebtp.extend.shortmessage.entity.BizShortMessage">
<result column="id" jdbcType="VARCHAR" property="id" />
<result column="appCode" jdbcType="VARCHAR" property="appcode" />
<result column="bizSn" jdbcType="VARCHAR" property="bizsn" />
<result column="mobile" jdbcType="INTEGER" property="mobile" />
<result column="callBackUrl" jdbcType="VARCHAR" property="callbackurl" />
<result column="status" jdbcType="INTEGER" property="status" />
<result column="send_time" jdbcType="VARCHAR" property="sendTime" />
<result column="template_code" jdbcType="VARCHAR" property="templateCode" />
<result column="type" jdbcType="VARCHAR" property="type" />
<result column="send_content" jdbcType="VARCHAR" property="sendContent" />
<result column="attribute1" jdbcType="VARCHAR" property="attribute1" />
<result column="attribute2" jdbcType="VARCHAR" property="attribute2" />
<result column="attribute3" jdbcType="VARCHAR" property="attribute3" />
<result column="attribute4" jdbcType="VARCHAR" property="attribute4" />
<result column="attribute5" jdbcType="VARCHAR" property="attribute5" />
</resultMap>
</mapper>

View File

@ -0,0 +1,78 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.chinaunicom.mall.ebtp.common.base.entity.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 实体类 BizShortMessage-多因素短信发送记录
*
* @author yss
*/
@Data
@Accessors(chain = true)
@TableName(value = "biz_short_message", autoResultMap = true)
@ApiModel(value = "BizShortMessage对象", description = "多因素短信发送记录")
public class BizShortMessage implements Serializable {
private static final long serialVersionUID = 1L;
@TableId
@ApiModelProperty(value = "主键ID")
private String id;
@ApiModelProperty(value = "应用在多因素系统内注册的唯一标识")
private String appcode;
@ApiModelProperty(value = "业务流水号")
private String bizsn;
@ApiModelProperty(value = "接收人手机号")
private String mobile;
@ApiModelProperty(value = "手机号")
private String callbackurl;
@ApiModelProperty(value = "发送状态0-发送中1-发送成功2-发送失败3-校验中4-校验成功5-校验失败")
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "发送时间")
private LocalDateTime sendTime;
@ApiModelProperty(value = "模板ID")
private String templateCode;
@ApiModelProperty(value = "类型sms-短信")
private String type;
@ApiModelProperty(value = "发送内容")
private String sendContent;
@ApiModelProperty(value = "备用字段1")
private String attribute1;
@ApiModelProperty(value = "备用字段2")
private String attribute2;
@ApiModelProperty(value = "备用字段3")
private String attribute3;
@ApiModelProperty(value = "备用字段4")
private String attribute4;
@ApiModelProperty(value = "备用字段5")
private String attribute5;
}

View File

@ -0,0 +1,17 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.entity;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SmsCheckRequest extends BaseVo {
/**
* 手机号
*/
private String mobile;
/**
* 验证码
*/
private String authCode;
}

View File

@ -0,0 +1,27 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.entity;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SmsSendRequest extends BaseVo {
/**
* 手机号
*/
private String mobile;
/**
* 应用系统账号
*/
private String userAccount;
/**
* 验证码
*/
private String authCode;
/**
* UrlEncode编码
* 应用系统回调确认用户有效性的地址,应用系统传了这个地址则用户有效性由该地址确定
*/
private String callBackUrl;
}

View File

@ -0,0 +1,17 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.service;
import com.chinaunicom.mall.ebtp.common.base.service.IBaseService;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.BizShortMessage;
/**
* 对数据表 biz_short_message 操作的 service
* @author yss
*
*/
public interface BizShortMessageService extends IBaseService<BizShortMessage>{
Boolean authCodeSend(String mobile);
Boolean authCodeCheck(String mobile, String authCode);
}

View File

@ -0,0 +1,129 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinaunicom.mall.ebtp.common.util.PropertyUtils;
import com.chinaunicom.mall.ebtp.extend.crypconfigure.entity.CrypBean;
import com.chinaunicom.mall.ebtp.extend.crypconfigure.service.ICrypConfigureService;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.SmsCheckRequest;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.SmsSendRequest;
import com.chinaunicom.mall.ebtp.extend.shortmessage.utils.SignUtil;
import org.bouncycastle.util.encoders.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.chinaunicom.mall.ebtp.common.base.service.impl.BaseServiceImpl;
import com.chinaunicom.mall.ebtp.extend.shortmessage.dao.BizShortMessageMapper;
import com.chinaunicom.mall.ebtp.extend.shortmessage.entity.BizShortMessage;
import com.chinaunicom.mall.ebtp.extend.shortmessage.service.BizShortMessageService;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
* 对数据表 biz_short_message 操作的 serviceImpl
* @author yss
*
*/
@Service
public class BizShortMessageServiceImpl extends BaseServiceImpl<BizShortMessageMapper,BizShortMessage> implements BizShortMessageService {
@Value("${message.sendVerifycodeHttpUrl}")
private String sendVerifycodeHttpUrl;
@Value("${message.checkVerifycodeHttpUrl}")
private String checkVerifycodeHttpUrl;
@Autowired
private ICrypConfigureService iCrypConfigureService;
@Autowired(required = false)
@Qualifier("cacheRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;
/**
* 业务系统私钥在SignUtil会用到--这里在切换对接环境时会变化,由集团多因素项目项目组提供
*/
private static final String PRI_KEY = "MHgCAQECIQCQO3m5phHk2I8SwgCIcQVcF5FkyCjnXWc2uRUz2/54N6AKBggqgRzPVQGCLaFEA0IABOnuKDS5zOzu5dW9bk0881GPpJkCMRa7yK4AopUoAzADZqddHqMmWl9VKI9n2qrIcx8rgRuv08tPGvV2Vo7776Q=";
@Override
public Boolean authCodeSend(String mobile) {
String id = PropertyUtils.getSnowflakeId();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String bizSn = "ebtp"+id+"ebtp"+ LocalDate.now().format(formatter);
BizShortMessage shortMessage = new BizShortMessage();
shortMessage.setId(id)
.setBizsn(bizSn)
.setCallbackurl(sendVerifycodeHttpUrl)
.setMobile(mobile)
.setSendTime(LocalDateTime.now())
.setStatus(0)
.setType("sms");
this.save(shortMessage);
redisTemplate.opsForValue().set("user:" + mobile, bizSn, 10, TimeUnit.MINUTES);
//使用业务系统私钥对业务数据签名Base64编码后的数据对bizSn进行签名的base64字符串签名值
byte[] signBytes = SignUtil.sign(PRI_KEY, bizSn.getBytes(StandardCharsets.UTF_8));
String sign = Base64.toBase64String(signBytes);
//组装参数
SmsSendRequest smsSendRequest = new SmsSendRequest();
//必传参数
//应用标识,调用方使用自己的应用标识
smsSendRequest.setAppCode("appCode");
//流水号,调用方生成,保持唯一
smsSendRequest.setBizSn(bizSn);
smsSendRequest.setSign(sign);
//手机号 未传时使用应用系统账号查询用户手机号
smsSendRequest.setMobile(mobile);
//用户状态验证回调url
smsSendRequest.setCallBackUrl("http://10.124.150.230:8000/api/chinaUnicom/manageCenter/eshop/mobilecheck/v1");
CrypBean bean = new CrypBean();
bean.setReqName("MESSAGE_SEND_VERIFYCODE_REQ");
bean.setUrl(sendVerifycodeHttpUrl);
bean.setObject(smsSendRequest);
boolean result = iCrypConfigureService.callUniInterfaceMessage(bean);
this.saveOrUpdate(shortMessage.setStatus(result?1:2));
return result;
}
@Override
public Boolean authCodeCheck(String mobile, String authCode) {
QueryWrapper<BizShortMessage> query = new QueryWrapper<>(new BizShortMessage().setMobile(mobile).setStatus(1));
BizShortMessage message = this.getBaseMapper().selectOne(query);
// String bizSn = message.getBizsn();
Object value = redisTemplate.opsForValue().get("user:" + mobile);
if (value != null) {
//组装参数
SmsCheckRequest smsCheckRequest = new SmsCheckRequest();
//必传参数
//应用标识
smsCheckRequest.setAppCode(message.getAppcode());
//流水号,使用发送认证短信时的流水号
smsCheckRequest.setBizSn(message.getBizsn());
//生成签名
byte[] signByte = SignUtil.sign(PRI_KEY,value.toString().getBytes(StandardCharsets.UTF_8));
String sign = com.cuca.bouncycastle.util.encoders.Base64.toBase64String(signByte);
smsCheckRequest.setSign(sign);
//手机号
smsCheckRequest.setMobile(mobile);
//验证码,手机收到的验证码
smsCheckRequest.setAuthCode(authCode);
CrypBean bean = new CrypBean();
bean.setReqName("MESSAGE_SEND_VERIFYCODE_REQ");
bean.setUrl(checkVerifycodeHttpUrl);
bean.setObject(smsCheckRequest);
this.saveOrUpdate(message.setStatus(3));
boolean result = iCrypConfigureService.callUniInterfaceMessage(bean);
this.saveOrUpdate(message.setStatus(result?4:5));
return result;
} else {
return false;
}
// if (message!=null){
//
// }
}
}

View File

@ -0,0 +1,25 @@
package com.chinaunicom.mall.ebtp.extend.shortmessage.utils;
import com.cuca.security.algorithm.impl.soft.SoftSM2;
import com.cuca.security.soft.sm2.SM2PrivateKey;
import com.cuca.security.util.KeyFromDER;
/**
* 签名生成演示方法
*/
public class SignUtil {
private static final SoftSM2 SM2 = new SoftSM2();
private static final String SIGN_ALG = "SM3withSM2";
/**
* 签名
* @param priKey Base64私钥字符串
* @param inData 签名原文
* @return 签名值
*/
public static byte[] sign(String priKey, byte[] inData) {
SM2PrivateKey privateKey = KeyFromDER.getSM2PrivateKey("", priKey);
return SM2.externalSign(SIGN_ALG, privateKey, inData);
}
}