springboot项目接口加解密_springboot项目 请求接口加密(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
img

正文

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import sun.misc.IOUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;

@ControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {

@Autowired
private ObjectMapper objectMapper;

/**
 * 方法上有DecryptionAnnotation注解的,进入此拦截器
 * @param methodParameter 方法参数对象
 * @param targetType 参数的类型
 * @param converterType 消息转换器
 * @return true,进入,false,跳过
 */
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
    return methodParameter.hasMethodAnnotation(DecryptionAnnotation.class);
}

@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
    return inputMessage;
}

/**
 * 转换之后,执行此方法,解密,赋值
 * @param body spring解析完的参数
 * @param inputMessage 输入参数
 * @param parameter 参数对象
 * @param targetType 参数类型
 * @param converterType 消息转换类型
 * @return 真实的参数
 */
@SneakyThrows
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {

    // 获取request
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
    if (servletRequestAttributes == null) {
        throw new ParamException("request错误");
    }

    HttpServletRequest request = servletRequestAttributes.getRequest();

    // 获取数据
    ServletInputStream inputStream = request.getInputStream();
    RequestData requestData = objectMapper.readValue(inputStream, RequestData.class);

    if (requestData == null || StringUtils.isBlank(requestData.getText())) {
        throw new ParamException("参数错误");
    }

    // 获取加密的数据
    String text = requestData.getText();

    // 放入解密之前的数据
    request.setAttribute(CryptoConstant.INPUT_ORIGINAL_DATA, text);

    // 解密
    String decryptText = null;
    try {
        decryptText = AESUtil.decrypt(text);
    } catch (Exception e) {
        throw new ParamException("解密失败");
    }

    if (StringUtils.isBlank(decryptText)) {
        throw new ParamException("解密失败");
    }

    // 放入解密之后的数据
    request.setAttribute(CryptoConstant.INPUT_DECRYPT_DATA, decryptText);

    // 获取结果
    Object result = objectMapper.readValue(decryptText, body.getClass());

    // 强制所有实体类必须继承RequestBase类,设置时间戳
    if (result instanceof RequestBase) {
        // 获取时间戳
        Long currentTimeMillis = ((RequestBase) result).getCurrentTimeMillis();
        // 有效期 60秒
        long effective = 60*1000;

        // 时间差
        long expire = System.currentTimeMillis() - currentTimeMillis;

        // 是否在有效期内
        /*if (Math.abs(expire) > effective) {
            throw new ParamException("时间戳不合法");
        }*/

        // 返回解密之后的数据
        return result;
    } else {
        throw new ParamException(String.format("请求参数类型:%s 未继承:%s", result.getClass().getName(), RequestBase.class.getName()));
    }
}

/**
 * 如果body为空,转为空对象
 * @param body spring解析完的参数
 * @param inputMessage 输入参数
 * @param parameter 参数对象
 * @param targetType 参数类型
 * @param converterType 消息转换类型
 * @return 真实的参数
 */
@SneakyThrows
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
    String typeName = targetType.getTypeName();
    Class<?> bodyClass = Class.forName(typeName);
    return bodyClass.newInstance();
}

}


**2、DecryptionAnnotation.java(解密注解)**



package com.soft.common.annotation;

import java.lang.annotation.*;

/**

  • @author Administrator
    */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface DecryptionAnnotation {

}


**3、EncryptResponseBodyAdvice.java(加密切面)**



package com.soft.common.advice;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.soft.common.annotation.EncryptionAnnotation;
import com.soft.common.entity.RequestBase;
import com.soft.common.exception.CryptoException;
import com.soft.common.result.Result;
import com.soft.common.util.AESUtil;
import com.soft.common.util.StringUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.ResponseEntity;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Type;

@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Result<?>> {

@Autowired
private ObjectMapper objectMapper;

@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    ParameterizedTypeImpl genericParameterType = (ParameterizedTypeImpl)returnType.getGenericParameterType();

    // 如果直接是Result,则返回
    if (genericParameterType.getRawType() == Result.class && returnType.hasMethodAnnotation(EncryptionAnnotation.class)) {
        return true;
    }

    if (genericParameterType.getRawType() != ResponseEntity.class) {
        return false;
    }

    // 如果是ResponseEntity<Result>
    for (Type type : genericParameterType.getActualTypeArguments()) {
        if (((ParameterizedTypeImpl) type).getRawType() == Result.class && returnType.hasMethodAnnotation(EncryptionAnnotation.class)) {
            return true;
        }
    }

    return false;
}

@SneakyThrows
@Override
public Result<?> beforeBodyWrite(Result<?> body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    // 加密
    Object data = body.getData();

    // 如果data为空,直接返回
    if (data == null) {
        return body;
    }

    // 如果是实体,并且继承了Request,则放入时间戳
    if (data instanceof RequestBase) {
        ((RequestBase)data).setCurrentTimeMillis(System.currentTimeMillis());
    }

    String dataText = JSONUtil.toJsonStr(data);

    // 如果data为空,直接返回
    if (StringUtils.isEmpty(dataText)) {
        return body;
    }

    // 如果位数小于16,报错
    if (dataText.length() < 16) {
        throw new CryptoException("加密失败,数据小于16位");
    }

    String encryptText = AESUtil.encryptHex(dataText);
    System.out.println("加密后的参数:"+encryptText);

    return Result.builder()
            .status(body.getStatus())
            .data(encryptText)
            .message(body.getMessage())
            .build();
}

}


**4、EncryptionAnnotation.java(加密注解)**



package com.soft.common.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncryptionAnnotation {
}


#### 五、实体类


**1、RequestData.java**



package com.soft.common.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode
public class RequestData implements Serializable{
// 加密的文本
private String text;
}


**2、RequestBase.java**



package com.soft.common.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@EqualsAndHashCode
public class RequestBase {

@TableField(exist = false)
private Long currentTimeMillis;

}


**3、User.java**



package com.soft.entity;

import com.soft.common.entity.RequestBase;
import lombok.Data;

import java.io.Serializable;

/**

  • @ClassName User
  • @Description
    **/
    @Data
    public class User extends RequestBase implements Serializable {
    private Integer id;
    private String name;
    private String password;

}


#### 六、测试



@Api(tags = “请求方”)
@RestController
@RequestMapping(“/test/request”)
public class TestController implements ResultBuilder {

@PostMapping("/userInfo")
public void get() {

    //请求远程接口获取id=2的user(CurrentTimeMillis,对方根据该值判断请求有效期,跟user没有关系)
    User user = new User();
    user.setId(2);
    user.setCurrentTimeMillis(DateUtils.millis(LocalDateTime.now()));
    //请求参数加密
    String text = AESUtil.encryptHex(JSONObject.toJSONString(user));
    
    //请求参数封装
    Map<String,Object> params = new HashMap<>();
    params.put("text", text);
    

    //设置请求头
    Map<String, String> headers = new HashMap<>();
    headers.put("Content-Type", "application/json;charset=UTF-8");
    HttpRequest httpRequest = HttpUtil.createPost("http://x.x.x.x:8088/test/response/getUserInfo");
    httpRequest.addHeaders(headers);
    httpRequest.body(JSONUtil.toJsonStr(params));
    //执行请求
    HttpResponse httpResponse = httpRequest.execute();
    //返回数据
    JSONObject jsonObject = JSON.parseObject(httpResponse.body());
    //返回数据解密
    String result = AESUtil.decrypt(jsonObject.get("data").toString());
    
    User data = JSONObject.parseObject(result, User.class);
    
}

}



package com.soft.controller;

@Api(tags = “响应方”)
@RestController
@RequestMapping(“/test/response”)
public class TestController implements ResultBuilder {

/**
 * 直接返回对象,不加密
 * @param teacher Teacher对象
 * @return 不加密的对象
 */
@PostMapping("/get")
public ResponseEntity<Result<?>> get(@Validated @RequestBody Teacher teacher) {
    return success(teacher);
}

/**
 * 返回加密后的数据
 * @param teacher Teacher对象
 * @return 返回加密后的数据 ResponseBody<Result>格式
 */
@PostMapping("/encrypt")
@EncryptionAnnotation
public ResponseEntity<Result<?>> encrypt(@Validated @RequestBody Teacher teacher) {
    return success(teacher);
}

/**
 * 返回加密后的数据
 * @param teacher Teacher对象
 * @return 返回加密后的数据 Result格式
 */
@PostMapping("/encrypt1")
@EncryptionAnnotation
public Result<?> encrypt1(@Validated @RequestBody Teacher teacher) {
    return success(teacher).getBody();
}

/**
 * 返回解密后的数据
 * @param teacher Teacher对象
 * @return 返回解密后的数据
 */
@PostMapping("/decrypt")
@DecryptionAnnotation
public ResponseEntity<Result<?>> decrypt(@Validated @RequestBody Teacher teacher) {
    return success(teacher);
}


/**
 * 返回加密后的数据
 * @EncryptionAnnotation:只对return 的结果加密

写在最后

在结束之际,我想重申的是,学习并非如攀登险峻高峰,而是如滴水穿石般的持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。

需要完整版PDF学习资源私我

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

持久累积。尤其当我们步入工作岗位之后,持之以恒的学习变得愈发不易,如同在茫茫大海中独自划舟,稍有松懈便可能被巨浪吞噬。然而,对于我们程序员而言,学习是生存之本,是我们在激烈市场竞争中立于不败之地的关键。一旦停止学习,我们便如同逆水行舟,不进则退,终将被时代的洪流所淘汰。因此,不断汲取新知识,不仅是对自己的提升,更是对自己的一份珍贵投资。让我们不断磨砺自己,与时代共同进步,书写属于我们的辉煌篇章。**

需要完整版PDF学习资源私我

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-ju0hrQah-1713175805217)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值