diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/annotation/SecurityParameter.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/annotation/SecurityParameter.java new file mode 100644 index 0000000000000000000000000000000000000000..c362e78f82e80973f4e24450e0bbb06c16359f11 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/annotation/SecurityParameter.java @@ -0,0 +1,25 @@ +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; +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionRequest.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..32bb7ba0422f208dacf340f8e3b7cfd0931e75b8 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionRequest.java @@ -0,0 +1,21 @@ +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; +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionResponse.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..93bab0b1dcf242e41890a487315c12f00829c8b5 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionResponse.java @@ -0,0 +1,8 @@ +package cn.sh.stc.sict.theme.common.crypto; + +/** + * @author gao + * @date 2023/05/30 13:59 + */ +public class EncryptionResponse { +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionUtil.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..be6d89fe57fbfe342290cc721887d6aaece3c779 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/crypto/EncryptionUtil.java @@ -0,0 +1,68 @@ +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); + + } + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/rsa/RSADecodeData.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/rsa/RSADecodeData.java new file mode 100644 index 0000000000000000000000000000000000000000..a9f11451c1045708b5dea5bf06358b7f0fd3c093 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/common/rsa/RSADecodeData.java @@ -0,0 +1,27 @@ +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; + + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/config/DecodeRequestAdvice.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/config/DecodeRequestAdvice.java new file mode 100644 index 0000000000000000000000000000000000000000..f547cf5a2cb5389b8e9bf58f79862f3e8c7e707d --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/config/DecodeRequestAdvice.java @@ -0,0 +1,70 @@ +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> aClass) { + // 判断方法是否需要进行解密 + return methodParameter.hasMethodAnnotation(SecurityParameter.class) && methodParameter.getMethodAnnotation(SecurityParameter.class).inDecode(); + } + + @Override + public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class> 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> aClass) { + return o; + } + + @Override + public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class> aClass) { + return o; + } + + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/config/EncodeResponseAdvice.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/config/EncodeResponseAdvice.java new file mode 100644 index 0000000000000000000000000000000000000000..7d67809b4d589234cc1a42a231e2d25d8a77f89b --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/config/EncodeResponseAdvice.java @@ -0,0 +1,52 @@ +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; + } + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java index 2a058d4ce3a06842be64cf018bb281d7226f6fe7..dd551b31e5acb1db1d45e30c1d075e1ff0971467 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java @@ -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); diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpSecurityController.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpSecurityController.java new file mode 100644 index 0000000000000000000000000000000000000000..923359e84d00151c00568e7e1a0d0ddca75ac3be --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpSecurityController.java @@ -0,0 +1,31 @@ +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 getPublicKey() { + log.info("获取公钥"); + return new R<>(EncryptionUtil.PUBLIC_KEY); + } + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpStatisticsController.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpStatisticsController.java index b57fc362d80aefc328b16ae1cb70e6e75c24c3cf..3a0771a1dea39c5e9f41129b23e6c1d99d8263be 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpStatisticsController.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/web/HpStatisticsController.java @@ -1,18 +1,8 @@ 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 getPublicKey() { + log.info("获取公钥"); + return new R<>(EncryptionUtil.PUBLIC_KEY); + } + }