问题描述:

在我的项目中,给/system/user/login接口配置了anonmous的访问规则,给/system/user/refresh-token接口配置了permitall的访问规则。在一次测试中,我错误在访问的登录接口时携带了旧的Jwt token,却出现了接口报错,而错误的来源是我自定义的过滤器 JwtAuthenticationTokenFilter

而在自定义过滤器中,会从请求中取出token,并验证token是否合法,从而进行认证。而访问时携带的旧token显然无法通过认证,于是就报错了。

但是为什么请求会通过自定义过滤器呢?That’s confuse me.

SecurityConfig.java

    @Bean  
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {  
        http  
                .csrf(AbstractHttpConfigurer::disable)// 关闭csrf  
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) 
                .authorizeHttpRequests(authorize -> authorize  
                        .requestMatchers("/system/user/login").anonymous()  
                        .requestMatchers("/system/user/refresh-token").permitAll()  
                        .anyRequest().authenticated() // 除上面外的所有请求全部需要鉴权认证  
                )  
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);  
        return http.build();  
    }

问题解决:

显然security和shiro的认证流程不太一样,在shiro中是可以指定请求被哪些过滤器处理的。permitAll() 仅表示Spring Security 的授权机制不会拦截这些请求,即允许匿名用户访问,但并不影响 FilterChain 继续执行。如果不想让请求进入到过滤器,我们可以使用web.ignore()

@Bean  
public WebSecurityCustomizer webSecurityCustomizer() {  
    return (web) -> web.ignoring()  
            .requestMatchers(  
                    "/system/user/login",  
                    "/system/user/refresh-token"
            );  
}

但是它仍旧不完美,比如:如何避免重复登录呢?比较可行的方案应该是,在JwtAuthenticationTokenFilter之前再添加一个过滤器,如果是anonymous的接口,就在这个过滤器中去掉请求头中的token。