SpringBoot 中注解方式的拦截过滤

Posted 上善若水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 中注解方式的拦截过滤相关的知识,希望对你有一定的参考价值。

使用场景

公司运行的App 登陆-验证码短信接口,遭到大量的恶意攻击。处于安全的考虑,需要客户端api目前的一些接口加上验证签名的功能,以提高安全性。

现行的App之前也有过签名的秘钥在,后来出于性能考虑,验签功能并没有用上。所以并不是所有的接口都需要验签,只需要要在需要的接口及时加入验签功能即可。

实现步骤

我们运行的api项目,是基于Spring Cloud的一个项目,所以都是基于Spring Boot 的,版本是1.5.3

1.先定义一个注解,我们只需要对需要验签的接口加上注解即可。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Signature {
  String value() default "";
}
2.再写一个扩展org.springframework.web.servlet.handler.HandlerInterceptorAdapter的拦截器 SignatureInterceptor

这里我们只需要重写前置拦截的方法即可

public class SignatureInterceptor extends HandlerInterceptorAdapter {
    private final static Logger logger = LoggerFactory.getLogger(SignatureInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {

        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            Signature signature = hm.getMethodAnnotation(Signature.class);
            if (signature == null) {
                return true;
            }
            //验证签名的方法
            ApiError result = checkSigature(request, response);
            if (result == null) {
                return true;
            }

            SimpleResponse simResponse = new SimpleResponse(result, request.getRequestURI());
            String strResponseJson = JsonUtil.toJson(simResponse);
            response.setContentType("application/json;charset=UTF-8");
            try (OutputStream out = response.getOutputStream()) {
                out.write(strResponseJson.getBytes("UTF-8"));
                out.flush();
            }
            request.setAttribute(Constants.RESPONSE_BODY_STRING, strResponseJson);

            return false;
        }

        return super.preHandle(request, response, handler);
    }

3. 把这个拦截器加入到配置类中

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter{


    @Bean
    @Autowired
    public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet){
        ServletRegistrationBean dispatcherRegistration = new ServletRegistrationBean(dispatcherServlet);
        dispatcherRegistration.addUrlMappings("*.do");
        dispatcherRegistration.addUrlMappings("*.htm");
        dispatcherRegistration.addUrlMappings("/*");
        dispatcherRegistration.setLoadOnStartup(1);
        return dispatcherRegistration;
    }

    /**
     *  通过 @Bean 注入这个 拦截器
     * @return
     */

    @Bean
    public HandlerInterceptor signatureInterceptor(){
        return new SignatureInterceptor();
    }

    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // signatureInterceptor 定义 拦截的URL 的类型 
        registry.addInterceptor(signatureInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/dss/**")
                .excludePathPatterns("/mappings","/trace","/info","/metrics","/health","/env","/refresh","/configprops")
                .excludePathPatterns("/archaius","/proxy.stream","/hystrix","/hystrix/**","/hystrix.stream")
                .excludePathPatterns("/heapdump","/dump")
                .excludePathPatterns("/error","/loggers","/loggers/**");
    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        AppExceptionResolver appExceptionResolver = new AppExceptionResolver();
        appExceptionResolver.setOrder(1);
        exceptionResolvers.add(appExceptionResolver);
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MMHFastjsonHttpMessageConverter messageConverter = new MMHFastjsonHttpMessageConverter();
        messageConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.APPLICATION_JSON_UTF8));
        messageConverter.setDefaultCharset(Charset.forName("UTF-8"));
        converters.add(messageConverter);
    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false);
    }
}

4. 在需要验签的接口前加入注解@Signature

	@RequestMapping(value = {"/V2/sms/vcode/sendSmsVcodeForLoginOrReg.htm","/s/V2/sms/vcode/sendSmsVcodeForLoginOrReg.htm"})
	@Signature
	public void sendSmsVcodeForLoginOrRegV2() {

			responseSuccessJson(response);
	
	}

通过以上4部,再启动项目的时候,拦截器节开始了它的拦截功能,会针对添加了@Signature的接口,运行前置拦截功能,验签通过才执行接口本来的业务逻辑。

源码分析

本段代码的核心是HandlerInterceptorAdapter这个类,拦截适配器 它提供了4个方法:

  • preHandle 预处理,该方法将在请求处理之前进行调用
  • postHandle 后置处理, 该方法将在请求处理之后,DispatcherServlet进行视图返回渲染之前进行调用
  • afterCompletion 在请求后处理,并在DispatcherServlet进行视图返回渲染之后调用

可以参考看https://blog.csdn.net/qq_35246620/article/details/68487904?1491374806898

以上是关于SpringBoot 中注解方式的拦截过滤的主要内容,如果未能解决你的问题,请参考以下文章

基于Springboot搭建java项目(二十三)——SpringBoot使用过滤器拦截器和监听器

SaToken使用SpringBoot整合SaToken关于数据权限

springboot环境下配置过滤器和拦截器

重学SpringBoot系列之生命周期内的拦截过滤与监听

SpringBoot | 第七章:过滤器监听器拦截器

SpringBoot —— AOP注解式拦截与方法规则拦截