首页 > 技术文章 > SpringBoot中拦截器配置

clion 2020-12-27 22:54 原文

SpringBoot中拦截器配置

不应该叫springboot拦截器,而是SpringMVC拦截器。主要就是对请求进行拦截,然后进行处理

百度百科对于SpringMVC拦截器的解释

在拦截器的处理中前置(pre)拦截是按顺序进行调用,后置拦截(post)是逆序,究其原因是在springmvc调用过程中pre拦截是顺序调用,然后逆序调用post拦截器。

在我的项目中拦截器是用来做token验证,验证用户是否登录,以及保存验证通过的用户信息在ThreadLocal中,然后在请求完成后清空threadlocal,防止发生内存泄漏,至于为什么发生内存泄漏,以前写过一篇文章此处不在赘述。当然了,拦截器还可能有其他用法,等待我去探究

那么如何在SpringBoot中配置SpringMVC的拦截器呢

首先需要实现HandlerInterceptor,具体如下

@Slf4j
public class JwtVerifyInterceptor implements HandlerInterceptor {
    @Autowired
    UserService userService;
    public static final ThreadLocal<User> USER_INFO_THREAD_LOCAL = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("开始验证用户状态。。。");
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length == 0) {
            return true;
        }
        for (Cookie cookie : cookies) {
            log.info("验证用户状态中");
            if ("token".equals(cookie.getName())) {
                String token = cookie.getValue();
                DecodedJWT decode = JWT.decode(token);
                int uid;
                try {
                    uid = Integer.parseInt(decode.getAudience().get(0));
                    User userInfo = userService.selectByPrimaryKey(uid);
                    if (userInfo == null) {
                        throw new RuntimeException("用户不存在,请重新登录");
                    }
                    USER_INFO_THREAD_LOCAL.set(userInfo);
                } catch (JWTDecodeException jwtDecodeException) {
                    log.error("token被篡改");
                    throw new RuntimeException("token格式不正确");
                }
            }
        }
        log.info("当前操作用户信息:" + USER_INFO_THREAD_LOCAL.get().toString());
        return USER_INFO_THREAD_LOCAL.get() != null;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("请求返回中,清除threadLocal信息");
        USER_INFO_THREAD_LOCAL.remove();
    }
}

这样就配置好了一个拦截器,但是并不能生效,因为此时springmvc还不知道我们创建了这个拦截器,而且这里也只定义了拦截器的行为它所做的一些操作。对于拦截器什么时候生效,作用的范围,这里并没有体现。所以还需要一个配置类对我们的拦截器进行配置,具体如下

@Configuration
public class InterceptorsConfig implements WebMvcConfigurer {
    @Bean
    JwtVerifyInterceptor jwtVerifyInterceptor() {
        return new JwtVerifyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LinkedList<String> excludePathPatterns = new LinkedList<>();
        excludePathPatterns.add("/user/login");
        excludePathPatterns.add("/user/register");
        registry.addInterceptor(jwtVerifyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(excludePathPatterns);
    }

}

这里加了@Configuration注解,表明这是一个配置类,springboot会根据它进行配置

可以看到这里用来一个@bean注解,表示将返回的返回值加入到springioc中,为什么要加入ioc中呢,这是因为在拦截器中我用到了userService查询user的信息,但是一般来说,拦截器是在ioc容器前起作用,这个时候容器中并没有UserService实例,也就无法进行依赖注入了。所以需要提前加入到ioc中。

接着就是具体的配置了,将一些路径不适用拦截器,比如注册登录等不需要用户登录状态下进行操作的的资源

然后就是将拦截器实例通过调用方法的形式加到拦截器配置中,然后指定路径以及前面指定好的不进行拦截的uri

至此,springmvc拦截器 已经配置完毕

推荐阅读