Commit c6fc236d authored by gaozhaochen's avatar gaozhaochen

add: 敏感数据加密解密处理

parent bc0056a2
package cn.sh.stc.sict.theme.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author gao
* @date 2023/05/30 13:50
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityParameter {
/**
* 入参是否解密,默认解密
*/
boolean inDecode() default true;
/**
* 出参是否加密,默认加密
*/
boolean outEncode() default true;
}
package cn.sh.stc.sict.theme.common.crypto;
import lombok.Data;
/**
* @author gao
* @date 2023/05/30 13:49
*/
@Data
public class EncryptionRequest {
/**
* rsa加密后的aes秘钥
*/
private String encryptionKey;
/**
*aes加密后的数据内容
*/
private String encryptionData;
}
package cn.sh.stc.sict.theme.common.crypto;
/**
* @author gao
* @date 2023/05/30 13:59
*/
public class EncryptionResponse {
}
package cn.sh.stc.sict.theme.common.crypto;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import sun.misc.BASE64Encoder;
import java.io.InputStream;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
/**
* @author gao
* @date 2023/05/30 13:48
*/
public class EncryptionUtil {
private static final String SIGN_TYPE_RSA = "RSA";
private static final int DEFAULT_RSA_KEY_SIZE = 1024;
public static final String PRIVATE_KEY = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAjQnqX7O3S6eDLzw4tw9K2IsWUuS9WCptg32AmaNMN+1YawmqDVOtrnkOyECZleuir62Y6ptw8yN0cyYzMFezDQIDAQABAkB9c5Jr6flia+/+Nfzkp8+VabJDrX7WS3b5/MpE3sHPBBQ/9HhAyg7k/MHTFZ8wScziFLPQ/wb6+szacNvA1RrpAiEA2Ei7JY6L/dv9hQ+YKYblCeGIQG8FUi4Uy7xheg1M/ZMCIQCm7/xBJCMubyyKHgRXr6MonqPdu2IE51IqmerXQV/w3wIgZ9jMGuVNrC8zk+7/5XiCgnMKg72KtYGwtH4X4419WQcCIExumHpix1DdSfE66RYUrolMiQ5eWvSPzMkAi8tefUTVAiB6F4fXbtKbqpJxW5dQttJl0RsEB39HGgOjy4mLaYZgvg==";
public static final String PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI0J6l+zt0ungy88OLcPStiLFlLkvVgqbYN9gJmjTDftWGsJqg1Tra55DshAmZXroq+tmOqbcPMjdHMmMzBXsw0CAwEAAQ==";
// 创建rsa加密对象 服务端公钥是不需要的,公钥提供给前端就行
private final static cn.hutool.crypto.asymmetric.RSA RSA = new RSA(PRIVATE_KEY, PUBLIC_KEY);
/**
* 获取加密返回
*/
public static String getEncodeResponse(String encryptionData) {
return Base64.encode(encryptionData);
}
/**
* 获取解密返回流
*/
public static InputStream getDecodeInputStream(EncryptionRequest request) {
String encryptionKey = request.getEncryptionKey();
// rsa解密 获取aes秘钥
byte[] decryptKey = RSA.decrypt(encryptionKey, KeyType.PrivateKey);
// aes进行解密内容 获取输入流(方便整合springMVC)
AES aes = SecureUtil.aes(decryptKey);
byte[] decryptData = aes.decrypt(request.getEncryptionData());
return IoUtil.toStream(decryptData);
}
public static void main(String[] args) {
KeyPair kp = SecureUtil.generateKeyPair(SIGN_TYPE_RSA, DEFAULT_RSA_KEY_SIZE);
PublicKey pbkey = kp.getPublic();
PrivateKey prkey = kp.getPrivate();
String pubkey = (new BASE64Encoder()).encode(pbkey.getEncoded());
String prikey = (new BASE64Encoder()).encode(prkey.getEncoded());
//logger.info("{}生成秘钥成功,公钥:{},私钥:{}",appkey,pubkey,prikey);
Map map = new HashMap();
map.put("pub", pubkey);
map.put("pri", prikey);
}
}
package cn.sh.stc.sict.theme.common.rsa;
import lombok.Data;
/**
* @author gao
* @date 2023/05/30 11:16
*/
@Data
public class RSADecodeData {
/**
* Aes密钥
*/
private String key;
/**
* 偏移量
*/
private String keyVI;
/**
* 时间
*/
private String time;
}
package cn.sh.stc.sict.theme.config;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.common.crypto.EncryptionRequest;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
* @author gao
* @date 2023/05/30 13:55
*/
@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
public class DecodeRequestAdvice implements RequestBodyAdvice {
private final ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
// 判断方法是否需要进行解密
return methodParameter.hasMethodAnnotation(SecurityParameter.class) && methodParameter.getMethodAnnotation(SecurityParameter.class).inDecode();
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
// 读取body对象,获取EncryptionRequest对象
InputStream body = httpInputMessage.getBody();
EncryptionRequest encryptionRequest = objectMapper.readValue(body, EncryptionRequest.class);
if (encryptionRequest.getEncryptionKey() == null) {
throw new IllegalArgumentException("encryption error,request is null");
}
// 转换成解密后的HttpInputMessage对象
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
// 解密后的输入流
@Override
public InputStream getBody() {
return EncryptionUtil.getDecodeInputStream(encryptionRequest);
}
};
}
@Override
public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
@Override
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
}
package cn.sh.stc.sict.theme.config;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author gao
* @date 2023/05/30 13:52
*/
@Slf4j
@ControllerAdvice
public class EncodeResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
// 方法上有SecurityParameter注解的进行加密 根据需求可以在判断SecurityParameter注解中的outEncode是否为true
return methodParameter.hasMethodAnnotation(SecurityParameter.class) && methodParameter.getMethodAnnotation(SecurityParameter.class).outEncode();
}
@Override
public Object beforeBodyWrite(Object o,
MethodParameter methodParameter,
MediaType mediaType,
Class aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
try {
// 要支持接口返回string的话,response需要序列化成string对象,因为接口返回string和对象使用消息转换器不是一样的
// 把返回结果序列化成json
String dataJson = objectMapper.writeValueAsString(o);
// 进行加密返回
return EncryptionUtil.getEncodeResponse(dataJson);
} catch (JsonProcessingException e) {
log.error("json processing error", e);
}
return o;
}
}
......@@ -14,6 +14,7 @@ import cn.sh.stc.sict.cloud.common.core.util.WoaUtil;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.hphy.constant.PatientConstant;
import cn.sh.stc.sict.theme.hphy.model.HpPatientCard;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
......@@ -56,6 +57,7 @@ public class HphyPatientBaseController {
@SysLog
@ApiOperation("注册")
@PostMapping("/register")
@SecurityParameter(outEncode = false)
public R register(@RequestBody HphyPatientBase patient) {
CurrentUser current = SecurityUtils.getCurrentUser();
HphyPatientBase base = hphyPatientBaseService.getCurrentBase();
......@@ -108,6 +110,7 @@ public class HphyPatientBaseController {
* @return
*/
@GetMapping
@SecurityParameter(inDecode = false)
public R getInfo() {
log.error("获取患者信息1");
CurrentUser current = SecurityUtils.getCurrentUser();
......@@ -130,6 +133,7 @@ public class HphyPatientBaseController {
@ApiOperation("第三方公众号进入系统时,获取患者信息")
@GetMapping("/third-party")
@SecurityParameter(inDecode = false)
public R getInfoByToken(@RequestParam("source") String source,
@RequestParam("token") String token) {
log.error("source = {}, token = {}", source, token);
......
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author gao
* @date 2023/05/30 14:30
*/
@Api(value = "[黄浦]安全密钥", tags = "[黄浦]安全密钥")
@RestController
@RequestMapping("hpSecurity")
@AllArgsConstructor
@Slf4j
public class HpSecurityController {
@ApiOperation("获取公钥")
@GetMapping("/public-key")
public R<String> getPublicKey() {
log.info("获取公钥");
return new R<>(EncryptionUtil.PUBLIC_KEY);
}
}
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.enums.LoginTypeEnum;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserCardInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.XSZYUserInfo;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.SsbUtil;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.theme.hphy.constant.PatientConstant;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import cn.sh.stc.sict.theme.hphy.service.HpStatisticsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
......@@ -23,8 +13,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 黄埔医导统计
*
......@@ -42,10 +30,18 @@ public class HpStatisticsController {
@ApiOperation("统计用户使用情况")
@GetMapping("/usage-overview")
@SecurityParameter(inDecode = false)
public R statisticsUsage(@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime) {
log.error("统计用户使用情况:startTime = {}, token = {}", startTime, endTime);
return new R(hpStatisticsService.getUsageOverviewStatistics(startTime, endTime));
}
@ApiOperation("获取公钥")
@GetMapping("/public-key")
public R<String> getPublicKey() {
log.info("获取公钥");
return new R<>(EncryptionUtil.PUBLIC_KEY);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment