SpringBoot 接口数据加解密

xx项目有于安全问题,需要对接口整体进行加密处理,我们怎么处理呢。

和产品、前端讨论需求后,梳理了相关技术方案,主要的需求点如下:

  • 尽量少改动,不影响之前的业务逻辑;

  • 考虑到时间紧迫性,可采用对称性加密方式,服务需要对接安卓、IOS、H5三端,另外考虑到H5端存储密钥安全性相对来说会低一些,故分针对H5和安卓、IOS分配两套密钥;

  • 要兼容低版本的接口,后面新开发的接口可不用兼容;

  • 接口有GET和POST两种接口,需要都要进行加解密;

需求解析:

  • 服务端、客户端和H5统一拦截加解密,网上有成熟方案,也可以按其他服务中实现的加解密流程来搞;

  • 使用AES放松加密,考虑到H5端存储密钥安全性相对来说会低一些,故分针对H5和安卓、IOS分配两套密钥;

  • 本次涉及客户端和服务端的整体改造,经讨论,新接口统一加 /secret/ 前缀来区分

那我们可以使用 @ControllerAdvice + RequestBodyAdvice/ResponseBodyAdvice 轻松实现

@ControllerAdvice / @RestControllerAdvice 区别?

@ControllerAdvice + @ExceptionHandler来实现全局异常捕获;陌生在于你除了copy代码时看到过外,自己似乎从来没有真正使用过它。
在前面关于@ModelAttribute和@InitBinder 的相关文章中其实和这个注解是打过照面的:在此注解标注的类上使用@InitBinder等注解可以使得它对"全局"生效实现统一的控制。本文将把@ControllerAdvice此注解作为重点进一步的去了解它的使用以及工作机制。

此类的命名是很有信息量的:Controller的Advice通知。关于Advice的含义,熟悉AOP相关概念的同学就不会陌生了,因此可以看到它整体上还是个AOP的设计思想,只是实现方式不太一样而已。
 

@ControllerAdvice使用AOP思想可以这么理解:此注解对目标Controller的通知是个环绕通知,织入的方式是注解方式,增强器是注解标注的方法。如此就很好理解@ControllerAdvice搭配@InitBinder/@ModelAttribute/@ExceptionHandler起到的效果喽~

官方doc说它可以和如上我指出的三个注解的一起使用。关于它的使用我总结有如下注意事项:

@ControllerAdvice只需要标注上即可,Spring MVC会在容器里自动探测到它(请确保能被扫描到,否则无效哦~)
若有多个@ControllerAdvice可以使用@Order或者Ordered接口来控制顺序
basePackageClasses属性最终也是转换为了basePackages拿去匹配的

RequestBodyAdvice/ResponseBodyAdvice
顾名思义,它们和@RequestBody和@ResponseBody有关,ResponseBodyAdvice是Spring4.1推出的,另外一个是4.2后才有。它哥俩和@ControllerAdvice一起使用会有很好的化学反应

RequestBodyAdvice

官方解释为:允许body体转换为对象之前进行自定义定制;也允许该对象作为实参传入方法之前对其处理。

public interface RequestBodyAdvice {

	// 第一个调用的。判断当前的拦截器(advice是否支持) 
	// 注意它的入参有:方法参数、目标类型、所使用的消息转换器等等
	boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType);

	// 如果body体木有内容就执行这个方法(后面的就不会再执行喽)
	Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
	
	// 重点:它在body被read读/转换**之前**进行调用的
	HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;

	// 它在body体已经转换为Object后执行。so此时都不抛出IOException了嘛~
	Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType);

}

它的内置实现有这些:

RequestResponseBodyAdviceChain比较特殊,放在后面重点说明。RequestBodyAdviceAdapter没啥说的,因此主要看看JsonViewRequestBodyAdvice这个实现。

JsonViewRequestBodyAdvice
Spring MVC的内置实现,它支持的是Jackson的com.fasterxml.jackson.annotation.@JsonView这个注解,@JsonView一般用于标注在HttpEntity/@RequestBody上,来决定处理入参的哪些key。
该注解指定的反序列视图将传递给MappingJackson2HttpMessageConverter,然后用它来反序列化请求体(从而做对应的过滤)。
 

// @since 4.2
public class JsonViewRequestBodyAdvice extends RequestBodyAdviceAdapter {

	// 处理使用的消息转换器是AbstractJackson2HttpMessageConverter类型
	// 并且入参上标注有@JsonView注解的
	@Override
	public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return (AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType) &&
				methodParameter.getParameterAnnotation(JsonView.class) != null);
	}

	// 显然这里实现的beforeBodyRead这个方法:
	// 它把body最终交给了MappingJacksonInputMessage来反序列处理消息体
	// 注意:@JsonView能处理这个注解。也就是说能指定把消息体转换成指定的类型,还是比较实用的
	// 可以看到当标注有@jsonView注解后 targetType就没啥卵用了
	@Override
	public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> selectedConverterType) throws IOException {
		JsonView ann = methodParameter.getParameterAnnotation(JsonView.class);
		Assert.state(ann != null, "No JsonView annotation");

		Class<?>[] classes = ann.value();
		// 必须指定class类型,并且有且只能指定一个类型
		if (classes.length != 1) {
			throw new IllegalArgumentException("@JsonView only supported for request body advice with exactly 1 class argument: " + methodParameter);
		}
		// 它是一个InputMessage的实现
		return new MappingJacksonInputMessage(inputMessage.getBody(), inputMessage.getHeaders(), classes[0]);
	}

}

ResponseBodyAdvice

它允许在@ResponseBody/ResponseEntity标注的处理方法上在用HttpMessageConverter在写数据之前做些什么。

// @since 4.1 泛型T:body类型
public interface ResponseBodyAdvice<T> {
	boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
	@Nullable
	T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response);
}

@JsonView的使用:它可以放入参时接收指定的字段;也可以让返回值中敏感字段(如密码、盐值等)不予返回,可做到非常灵活的配置和管理,实现一套代码多处使用的目的,提高集成程度

需要注意的是:xxxBodyAdvice虽然使用方便,但是它的普适性还是没有HandlerInterceptor那么强的,下面我列出使用它的几点局限/限制

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值