飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

我自定义的拦截器为什么会靠后执行?

时间:2022-01-23  作者:eaglelihh  
项目中自定义了拦截器`Filter`,项目中使用了`spring security`,它也有对应的拦截器,我想让我自定义的`Filter`在`spring security`的拦截器前执行,那就一起来看看`spring security`设置的拦截器的默认优先级等级是多少吧。

目录
  • 背景
  • 模拟场景
  • 是不是因为order的值
  • 找出在哪里赋予的order值
  • 解决办法

背景

项目中自定义了拦截器Filter,项目中使用了spring security,它也有对应的拦截器,我想让我自定义的Filterspring security的拦截器前执行。

因为我自定义的拦截器,需要提前做一些逻辑处理;然后spring security的拦截器需要用到这部分的处理结果;所以我必须要想办法让我自定义的拦截器靠前执行。

那就一起来看看spring security设置的拦截器的默认优先级等级是多少吧。

模拟场景

自定义拦截器如下:

@Slf4j
public class MyOncePerRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        域名("======== MyOncePerRequestFilter ========");
        域名lter(request, response);
    }
}

@Configuration
public class Config {
    @Bean
    public FilterRegistrationBean<MyOncePerRequestFilter> i18nFilterRegistrationBean() {
        FilterRegistrationBean<MyOncePerRequestFilter> registrationBean = new FilterRegistrationBean();
        MyOncePerRequestFilter myOncePerRequestFilter = new MyOncePerRequestFilter();
        域名ilter(myOncePerRequestFilter);
        域名rlPatterns("/*");
        域名rder(-1);
        return registrationBean;
    }
}

spring security的简单配置如下:

@Slf4j
public class MyTokenStore implements TokenStore {
    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        域名("======== readAccessToken ========");
        return new DefaultOAuth2AccessToken(tokenValue);
    }

    @Override
    public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
        Authentication authentication = new AbstractAuthenticationToken(域名ashSet()) {
            {
                域名uthenticated(true);
            }
            @Override
            public Object getCredentials() {
                return null;
            }
            @Override
            public Object getPrincipal() {
                return 域名Y;
            }
        };
        OAuth2Request request =
                new OAuth2Request(null, null, null, true,
                        域名ashSet(), 域名ashSet(), null, null, null);
        return new OAuth2Authentication(request, authentication);
    }

    @Override public OAuth2Authentication readAuthentication(String token) {
        return null;
    }

    @Override
    public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
    }

    @Override public void removeAccessToken(OAuth2AccessToken token) {

    }

    @Override public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
    }

    @Override public OAuth2RefreshToken readRefreshToken(String tokenValue) {
        return null;
    }

    @Override public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
        return null;
    }

    @Override public void removeRefreshToken(OAuth2RefreshToken token) {
    }

    @Override public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
    }

    @Override public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
        return null;
    }

    @Override public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
        return null;
    }

    @Override public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
        return null;
    }
}

@Configuration
@EnableResourceServer
@EnableWebSecurity
public class MyResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        MyTokenStore tokenStore = new MyTokenStore();
        域名nStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        域名().disable()
                .authorizeRequests().anyRequest().authenticated()
                .and().anonymous().key("anonymousUser")
                .and().httpBasic();
    }
}

启动类如下:

@RestController
public class MyController {
    @GetMapping("/hello")
    public String hello() {
        return "hello,world!";
    }
}

@SpringBootApplication(exclude = {域名s})
public class Starter {
    public static void main(String[] args) {
        域名(域名s, args);
    }
}

启动后,访问 http://127.0.0.1:8080/hello?access_token=123

日志打印如下:

102149 [http-nio-8080-exec-1] INFO  c.e.域名.域名kenStore - ======== readAccessToken ======== 
102149 [http-nio-8080-exec-1] INFO  c.e.l.s.域名cePerRequestFilter - ======== MyOncePerRequestFilter ======== 

从结果可以看出,spring security的拦截器是比我们自定义的拦截器先执行的,而我们自定义的拦截器的优先级是域名rder(-1)

我猜应该是这个值决定了执行顺序,那就带着这个猜想往下看一下吧。

是不是因为order的值

在之前的配置中,我们将自定义的拦截器顺序置为-1

我们先在域名lterInternal打个断点,看一下执行链的顺序:

从这条链中,我们猜测springSecurityFilterChainorder-100,我们自定义的拦截器是在它后面的

那我们直接把我们的拦截器设置成-101域名rder(-101);,再来尝试一下:

从断点结果可以看出,我们的设置是有效的,并且起到了作用,而且打印日志也说明了结果,如下:

11956 [http-nio-8080-exec-1] INFO  c.e.l.s.域名cePerRequestFilter - ======== MyOncePerRequestFilter ======== 
98419 [http-nio-8080-exec-1] INFO  c.e.域名.域名kenStore - ======== readAccessToken ======== 

找出在哪里赋予的order

这个过程是极其枯燥的,所以就先给结果了,如下:

spring security的拦截器链是在下面这部分创建的:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = 域名LET)
@EnableConfigurationProperties(域名s)
@ConditionalOnClass({ 域名s, 域名s })
@AutoConfigureAfter(域名s)
public class SecurityFilterAutoConfiguration {
	private static final String DEFAULT_FILTER_NAME = 域名ULT_FILTER_NAME;
	@Bean
	@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
	public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
			SecurityProperties securityProperties) {
		DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
				DEFAULT_FILTER_NAME);
		域名rder(域名ilter().getOrder()); // 这里
		域名ispatcherTypes(getDispatcherTypes(securityProperties));
		return registration;
	}
}

public abstract class AbstractSecurityWebApplicationInitializer implements WebApplicationInitializer {
    public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";
}

@ConfigurationProperties(prefix = "域名rity")
public class SecurityProperties {
	public static final int DEFAULT_FILTER_ORDER = 域名EST_WRAPPER_FILTER_MAX_ORDER - 100; // 这里

	private final Filter filter = new Filter();
	public Filter getFilter() {
		return 域名er;
	}
	public static class Filter {
		private int order = DEFAULT_FILTER_ORDER; // 这里
		public int getOrder() {
			return 域名r;
		}
		public void setOrder(int order) {
			域名r = order;
		}
	}
}

public interface OrderedFilter extends Filter, Ordered {
	int REQUEST_WRAPPER_FILTER_MAX_ORDER = 0; // 这里
}

从上面的代码可以看出,默认值是-100,同样也可以使用域名域名r来自定义值。

下面是寻找此过程的历程:

继续从这里开始,域名rnalDoFilter如下:

可以看出所有的拦截器都是在filters中,我们可以看这个值是怎么来的,通过调试,是在域名ilter这个地方,如下:

它是被域名teFilterChain调用的,如下:

所以filters是根据filterMaps来添加的,我们再来看一下filterMaps是怎么来的,一共涉及到两个地方,如下:

域名ilterMap域名ilterMapBefore如下:

看一下调用链:

原来是被域名Initialize调用的,如下:

域名ervletContextInitializerBeans如下:

ServletContextInitializerBeans构造函数如下:

所有的拦截器都是通过addServletContextInitializerBeans(beanFactory);addAdaptableBeans(beanFactory);来把bean加进来的

经过一番调试,终于找到spring security这个拦截器定义顺序的位置,域名rityFilterChainRegistration如下:

可以看到SecurityProperties securityProperties是注入进来的,找到这个类看一下,域名r如下:

@ConfigurationProperties(prefix = "域名rity")
public class SecurityProperties {
	public static final int DEFAULT_FILTER_ORDER = 域名EST_WRAPPER_FILTER_MAX_ORDER - 100;
	private final Filter filter = new Filter();
	private final User user = new User();
	public static class Filter {
		/**
		 * Security filter chain order.
		 */
		private int order = DEFAULT_FILTER_ORDER;
		public int getOrder() {
			return 域名r;
		}
		public void setOrder(int order) {
			域名r = order;
		}
	}
}
public interface OrderedFilter extends Filter, Ordered {
	/**
	 * Filters that wrap the servlet request should be ordered less than or equal to this.
	 */
	int REQUEST_WRAPPER_FILTER_MAX_ORDER = 0;
}

到此我们也找到了这个默认值,是根据域名域名r来决定的,默认值是-100

解决办法

第一种就是修改自己的顺序:

@Configuration
public class Config {
    @Bean
    public FilterRegistrationBean<MyOncePerRequestFilter> i18nFilterRegistrationBean() {
        FilterRegistrationBean<MyOncePerRequestFilter> registrationBean = new FilterRegistrationBean();
        MyOncePerRequestFilter myOncePerRequestFilter = new MyOncePerRequestFilter();

        域名ilter(myOncePerRequestFilter);
        域名rlPatterns("/*");
        域名rder(-101); // 这里
        return registrationBean;
    }
}

第二种就是修改\'spring security\'拦截器的顺序:

spring:
  security:
    filter:
      order: 0

大家可以自己跑跑试试看,完结撒花~~~~~~

标签:编程
湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。