SpringBoot项目采用Aspec(切面)的方式实现对指定接口请求及相应进行加解密操作

在项目中对携带敏感信息的接口进行加解密

1、创建一个切面类

PassAspec
package com.XXX.XXX.XXX.XXX.aspect;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.jinmdz.fmis.api.pass.PassApi;
import com.jinmdz.fmis.common.util.EmptyUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

/**
 * @Author:caohuohuo
 * @Date:2024/8/30 16:13
 * @Filename:PassAspec
 */
@Aspect //定义一个切面
@Component //让Spring能够在应用程序启动时自动扫描并加载此切面
@Slf4j //Logger 实例并记录日志
public class PassAspec {

    private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    @Resource
    private PassApi passApi;//这里调用外部加解密接口API,可以根据自己的实际情况去加解密

    // 定义切点,监听使用此注解的方法
    @Pointcut("@annotation(com.XXX.XXX.XXX.XXX.XXX.PassAnnotation)")
    public void pointCut() {
    }

    //环绕通知
    //调用接口调用前进行解密处理
    @Around("pointCut()")
    public Object getCapCode(ProceedingJoinPoint joinPoint) {
        try {
            Object[] args = joinPoint.getArgs();
            if (null != args) {
                JSONObject inParamJSON = (JSONObject) JSONObject.toJSON(args[0]);
                //解密 ciphertext字段为设置的加密参数,这里判断加密字段存在并且不为null时进行解密
                if (inParamJSON.containsKey("ciphertext")&&EmptyUtil.isNotEmpty(inParamJSON.getString("ciphertext"))){
                    String ciphertext = inParamJSON.getString("ciphertext");
                    JSONObject inParam=new JSONObject();//组装解密报文
                    inParam.put("data",ciphertext);
                    JSONObject decryptJson = passApi.decrypt(inParam);//调用外部解密接口进行解密
                    if (EmptyUtil.isNotEmpty(decryptJson)){
                        if (decryptJson.containsKey("code")&&decryptJson.getInteger("code")==200){
                            args[0]=changObjectValue(args[0],decryptJson.getString("data"));//解密成功后进行类型转换,转换完重新赋值
                        }
                    }
                }
            }
            return joinPoint.proceed(args);//调用相应方法,加密也可以在此之后进行加密,这里使用后置通知进行加密
        } catch (Throwable e) {
            log.error("目标方法执行异常,目标类:" + joinPoint.getTarget() + "方法:" + joinPoint.getSignature().getName(), e);
            throw new RuntimeException("系统繁忙,请稍后再试!");
        }
    }

    //后置通知
    //接口返回之后对结果加密处理
    @AfterReturning(value = "pointCut()",returning = "methodResult")//value:引用自定义的切点方法;returning:返回值
    public Object afterReturningPublish(Object methodResult) {

        //将返回值转成自己框架相应的实体用作返回
        BaseResult result = (BaseResult) methodResult;
        ObjectMapper objectMapper = new ObjectMapper();

        //设置时间格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN)));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        //设置时区
        objectMapper.registerModule(javaTimeModule);
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));

        //加密信息
        JSONObject inParam=new JSONObject();
        try {//这里将返回值整体转成字符串进行加密
            inParam.put("data", objectMapper.writeValueAsString(methodResult));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new RuntimeException("系统繁忙,请稍后再试!");
        }//调用外部加密接口进行加密,这里根据项目实际情况处理
        JSONObject encryptJson = passApi.encrypt(inParam);
        if (EmptyUtil.isNotEmpty(encryptJson)){
            if (encryptJson.containsKey("code")&&encryptJson.getInteger("code")==200){//加密成功后将加密串返回
                result.setData(encryptJson.getString("data"));
            }else {
                result.setCode(0);
                result.setMessage("加密失败");
            }
        }
        return result;
    }

    /***
     * 修改入参具体字段值,这里需要修改请求体所有所以整体转换了,注意转换时的类型
     */
    private Object changObjectValue(Object obj, String obj2) throws Exception {

        return JSONObject.parseObject(obj2,obj.getClass());
    }
}

2、注解类

PassAnnotation
package com.XXX.XXX.XXX.XXX.aspect;

import java.lang.annotation.*;

/**
 * @Author:caohuohuo
 * @Date:2024/8/30 16:25
 * @Filename:PassAnnotation
 */
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //使用注解的方法生成 Javadoc 时,当前注解 会被包括在内
public @interface PassAnnotation {
}

这里在需要使用加解密的接口上加上@PassAnnotation注解就OK了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值