添加请求校验

This commit is contained in:
DB 2024-02-29 15:18:56 +08:00
parent 124c3acfaa
commit 761a2f08d4
9 changed files with 332 additions and 5 deletions

View File

@ -0,0 +1,133 @@
package com.cpop.core.utils;
import com.alibaba.fastjson2.JSONObject;
import com.cpop.core.base.entity.CpopSignBase;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author DB
* @version 1.0.0
* @since 2024-02-28 14:50
*/
@Component
public class CpopSignatureUtils {
@Autowired
private RsaUtils rsaUtils;
private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
//数币
put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB"});
//系统
put("100", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDdtx3eLzoUbm0qr8xv4XXew0raUsv98eOmdxS4jDgFkajzK3H02fnWg99y2CRcZNnEFA6MlE/0RrAuWnuIehazQBR5dpnzoOht4WweRO0DEciRTdQ5Uf5T4YOlwmNKhE2S9jsmBP8X5Gi2r65G4miBG8r4AJJ9Pxtq8fjZUkCpKrk3y167mSunDUtZZOAimQ7W235Oh7fIqOSNQN+KxvhFSkiSqFIaXjDY50eONdSBaPYV1NsbW5A6VHrsvcG/2uzcEAfINFoRsmF9SxsckvnVsVfKgN+ONvnQdFmAJaiwtXJ9eJ4TfMt+HPTZk8pMfAUEj8vfz/98g39kKY42b2QIDAQAB"});
}};
/**
* 发送签名http请求
* @author DB
* @since 2024/2/28
* @param url 路径
* @param data 数据
* @param appid appid
* @return Response
*/
public JSONObject sendSignaturePost(String url, Object data, String appid) throws IOException, IllegalAccessException {
OkHttpClient client = new OkHttpClient().newBuilder().build();
MediaType mediaType = MediaType.Companion.parse("application/json;charset=utf-8");
RequestBody body = RequestBody.Companion.create(JSONObject.toJSONString(data), mediaType);
String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String signType = "RSA";
CpopSignBase cpopSignBase = new CpopSignBase();
cpopSignBase.setSignType(signType);
cpopSignBase.setDateTime(now);
cpopSignBase.setAppId(appid);
cpopSignBase.setSignature(md5(data, appid));
Request request = new Request
.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("appId", appid)
.addHeader("signature", signature(cpopSignBase,APP_IDS.get(appid)[0]))
.addHeader("dateTime", now)
.addHeader("signType", signType)
.build();
Response response = null;
try {
response = client.newCall(request).execute();
return JSONObject.parseObject(response.body().string());
} finally {
assert response != null;
response.close();
}
}
private String md5(Object object, String appId) throws IllegalAccessException {
//验签拼接字段
List<String> signString = new ArrayList<String>();
//获取父类公共类必传属性
Field[] fatherFields = object.getClass().getSuperclass().getDeclaredFields();
for (Field field : fatherFields) {
field.setAccessible(true);
signString.add(field.getName() + "=" + field.get(object));
}
//可能为空参
Field[] fields = object.getClass().getDeclaredFields();
if (fields.length > 0) {
for (Field field : fields) {
field.setAccessible(true);
if (null == field.get(object)) {
signString.add(field.getName() + "=");
} else {
signString.add(field.getName() + "=" + field.get(object));
}
}
}
//按照字母排序
String sign = signString.stream().sorted().collect(Collectors.joining("&")) + appId;
return DigestUtils.md5DigestAsHex(sign.getBytes());
}
/**
* 签名
*
* @param data 数据
* @return String
* @author DB
* @since 2024/2/28
*/
private String signature(CpopSignBase data, String publicKey) {
return rsaUtils.encrypt(JSONObject.toJSONString(data), stringToPublicKey(publicKey));
}
private PublicKey stringToPublicKey(String publicKey) {
byte[] decode = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode);
//返回转换指定算法的KeyFactory对象
KeyFactory keyFactory = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
//根据PKCS8编码密钥规范产生私钥对象
return keyFactory.generatePublic(x509EncodedKeySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -169,8 +169,7 @@ public class RsaUtils {
* @param source 源数据
* @return 加密后的字符串
*/
public String encrypt(String source) {
Key publicKey = getKeyFromFile(keyPairConfig.getPublicKeyFile());
public String encrypt(String source, Key publicKey) {
Base64.Encoder encoder = Base64.getEncoder();
String encryptSource = null;
try {
@ -187,6 +186,15 @@ public class RsaUtils {
return encryptSource;
}
/**
* 加密方法
* @param source 源数据
* @return 加密后的字符串
*/
public String encrypt(String source) {
return encrypt(source, getKeyFromFile(keyPairConfig.getPublicKeyFile()));
}
/**
* 解密方法
* @param source 密文

View File

@ -64,7 +64,7 @@ public class EasyLearnUnionPayBo {
/**
* 订单类型
*/
@NotNull(message = "联合支付类型不能为空")
@NotBlank(message = "联合支付类型不能为空")
@ApiModelProperty(value = "联合支付类型(WX_PAY:微信支付;PREPAYMENT:预付;REPAYMENT:还款;MEMBER:会员)",required = true)
private String easyLearnUnionPay;

View File

@ -51,7 +51,7 @@ public enum EasyLearnPayPayEnum {
}
/**
* 分账比例
* 订单类型
*/
private Integer orderType;

View File

@ -3,14 +3,22 @@ package com.cpop.oam.web;
import com.alibaba.fastjson.JSONObject;
import com.cpop.api.tencent.location.handler.TencentLocationHandler;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.core.annontation.StringArrayConvert;
import com.cpop.core.utils.CpopSignatureUtils;
import com.cpop.core.utils.RsaUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.oam.business.bo.ApiTenantRequest;
import com.cpop.pay.framewok.handler.ecpp.EcppHandler;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.experimental.Accessors;
import okhttp3.Response;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@ -60,4 +68,18 @@ public class CpopApiTests {
JSONObject geocoder = SpringUtils.getBean(TencentLocationHandler.class).geocoder("114.4246835", "23.12707132", "UGLBZ-LBF3I-ETCGO-UUH5X-QDV45-3LFKA");
System.out.println(geocoder);
}
/**
* 新增租户
* @author DB
* @since 2024/2/28
*/
@Test
public void insertTenant() throws IOException, IllegalAccessException {
com.alibaba.fastjson2.JSONObject jsonObject = SpringUtils.getBean(CpopSignatureUtils.class).sendSignaturePost("http://localhost:9440/Jambox-System/api/tenant/insertTenant",
new ApiTenantRequest().setName("测试租户").setIsSuper(false), "100");
System.out.println(jsonObject);
}
}

View File

@ -0,0 +1,93 @@
package com.cpop.oam.business.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.experimental.Accessors;
import java.time.LocalDate;
/**
* @author DB
* @version 1.0.0
* @since 2024-02-28 16:50
*/
@Data
@Accessors(chain = true)
public class ApiTenantRequest {
/**
* 主键
*/
private String id;
/**
* 租户名
*/
private String name;
/**
* 是否是超管
*/
private Boolean isSuper;
/**
* 外部id
*/
private String outId;
/**
* logo
*/
private String logo;
/**
* 排序
*/
private Integer orderNo;
/**
* 手机号
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 地址
*/
private String address;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 昵称
*/
private String nickname;
/**
* 状态(0:停用;1:启用)
*/
private Boolean status;
/**
* 到期日期
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate maturityDate;
/**
* 加密签名
*/
private String signature;
}

View File

@ -1,7 +1,9 @@
package com.cpop.oam.framework.tasks;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.table.SysConfig;
import com.cpop.core.service.CoreService;
import com.cpop.core.service.RedisService;
@ -14,7 +16,9 @@ import com.cpop.oam.business.entity.table.DataImportTableDef;
import com.cpop.oam.business.mapper.ClueMapper;
import com.cpop.oam.business.service.*;
import com.cpop.oam.business.vo.SignGoalConfigInfoVo;
import com.cpop.oam.business.vo.StaffInfoVo;
import com.cpop.oam.framework.constant.OamConfigKey;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import com.cpop.oam.framework.enums.OamConfigEnum;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.update.UpdateChain;
@ -25,6 +29,7 @@ import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
@ -212,4 +217,46 @@ public class OamScheduledTasks {
}
}
}
/**
* 任务逾期提醒
* @author DB
* @since 2023/12/11
*/
@Scheduled(cron = "0 30 9 * * *")
public void taskOverdueRemind() {
log.info("==============开始检查即将逾期任务===========");
TaskService taskService = SpringUtils.getBean(TaskService.class);
//进行中的任务提醒任务负责人
List<Task> dealTasks = taskService.queryChain().where(TASK.TASK_STATUS.eq(2)).and(TASK.TASK_TYPE.in(0, 1)).and(TASK.EXPECTED_COMPLETION_DATE.eq(LocalDate.now())).list();
if (!dealTasks.isEmpty()) {
dealTasks.forEach(item->{
ArrayList<String> phoneList = new ArrayList<>();
StaffInfoVo staffInfo = SpringUtils.getBean(StaffService.class).getStaffInfo(item.getResponsibleStaffId());
phoneList.add(staffInfo.getPhoneNumber());
try {
SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, phoneList,
"==========您有一个任务今天即将到期,请及时处理==========\n" + item.getTaskContent(),
false);
} catch (IOException e) {
throw new ServiceException("发送消息通知失败!");
}
});
}
List<Task> testTasks = taskService.queryChain().where(TASK.TASK_STATUS.eq(3)).and(TASK.TASK_TYPE.in(0, 1)).and(TASK.EXPECTED_COMPLETION_DATE.eq(LocalDate.now().minusDays(1))).list();
if (!testTasks.isEmpty()) {
String testStaffPhones = SpringUtils.getBean(RedisService.class).getCacheObject(OamConfigKey.OAM_CONFIG_KEY + OamConfigEnum.TEST_STAFF_PHONE.getKey());
testTasks.forEach(item->{
ArrayList<String> phoneList = new ArrayList<>();
phoneList.add(testStaffPhones);
try {
SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT, phoneList,
"==========您有一个测试任务今天即将到期,请及时处理==========\n" + item.getTaskContent(),
false);
} catch (IOException e) {
throw new ServiceException("发送消息通知失败!");
}
});
}
}
}

View File

@ -1,15 +1,24 @@
package com.cpop.oam.framework.tasks;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.utils.SpringUtils;
import com.cpop.oam.business.entity.Task;
import com.cpop.oam.business.entity.TaskWorkOrder;
import com.cpop.oam.business.service.StaffService;
import com.cpop.oam.business.service.TaskService;
import com.cpop.oam.business.service.TaskWorkOrderService;
import com.cpop.oam.business.vo.StaffInfoVo;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.cpop.oam.business.entity.table.TaskTableDef.TASK;
/**
@ -32,6 +41,21 @@ public class WorkOrderPauseRecoverTask implements Job {
Task task = taskService.getById(taskWorkOrder.getTaskId());
if (task.getTaskStatus() == 5) {
taskService.updateChain().set(TASK.TASK_STATUS, 2).where(TASK.ID.eq(taskWorkOrder.getTaskId())).update();
// 发送消息通知
List<String> phoneList = new ArrayList<String>();
StaffInfoVo responsibleStaff = SpringUtils.getBean(StaffService.class).getStaffInfo(task.getResponsibleStaffId());
StaffInfoVo recordStaff = SpringUtils.getBean(StaffService.class).getStaffInfo(task.getRecordStaffId());
phoneList.add(responsibleStaff.getPhoneNumber());
phoneList.add(recordStaff.getPhoneNumber());
try {
SpringUtils.getBean(WebHookSendHandler.class)
.webHookSendText(WebHookKeyConstant.ORDER_INFO_BOT,
phoneList,
"==========您有一条工单已经到期,请及时处理==========\n" + task.getTaskContent(),
false);
} catch (IOException e) {
throw new ServiceException("发送消息通知失败!");
}
}
}
}

View File

@ -75,7 +75,7 @@ public class BackstageBrandController {
Row row = Db.selectOneByQuery("cp_j_brand_extend", QueryWrapper.create().where("brand_id = ?", bo.getId()));
if (row != null){
CloudBrandDto cloudBrandDto = new CloudBrandDto();
cloudBrandDto.setBrandCloudId(row.getString("brand_cloud_id"));
cloudBrandDto.setBrandCloudId(row.getString("brandCloudId"));
cloudBrandDto.setBrandName(bo.getBrandName());
SpringUtils.getBean(CloudBrandHandler.class).updateBrand(cloudBrandDto);
}