当多个过滤器添加到HttpSecurity配置方法时,它们似乎重叠,因为当时只有一个有效。
这是配置方法:
@Override
public void configure(HttpSecurity http) throws Exception {
http
.logout().and().antMatcher("/**")
.addFilterBefore(ssoFilter(), RequestHeaderAuthenticationFilter.class)
.authenticationProvider(preauthAuthProvider())
.authorizeRequests()
.antMatchers("/index.html", "/home.html", "/", "/login").permitAll()
.anyRequest().authenticated().and().csrf()
.csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
我已尝试指定订单,但问题仍然存在:
@Bean
public FilterRegistrationBean securityFilterChain(@Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
registration.setOrder(Integer.MAX_VALUE - 2);
registration.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
return registration;
}
@Bean
public FilterRegistrationBean ssoFilterRegistrationBean() throws Exception {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(ssoFilter());
registrationBean.setOrder(Integer.MAX_VALUE-1);
return registrationBean;
}
@Bean
public FilterRegistrationBean csrfFilterRegistrationBean() throws Exception {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(csrfHeaderFilter());
registrationBean.setOrder(Integer.MAX_VALUE);
return registrationBean;
}
我跟着以下帖子没有成功。
https://github.com/spring-projects/spring-boot/issues/1640
https://github.com/spring-projects/spring-boot/issues/677
任何帮助将不胜感激!
更新:
CSRF过滤器定义
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request
.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null
|| token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
SSO过滤器定义:
public class SSORequestHeaderAuthenticationFilter extends RequestHeaderAuthenticationFilter {
private boolean allowPreAuthenticatedPrincipals = true;
public SSORequestHeaderAuthenticationFilter() {
super();
//TODO Pull this value from a properties file (application.properties, or localstrings.properties)
//NOTE SM_USER is the default, but you can change it like this (your company may use some other header)
//this.setPrincipalRequestHeader("SM_USER");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
/**
* This is called when a request is made, the returned object identifies the
* user and will either be {@literal null} or a String. This method will throw an exception if
* exceptionIfHeaderMissing is set to true (default) and the required header is missing.
*
* @param request {@link javax.servlet.http.HttpServletRequest}
*/
@Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String userName = (String) (super.getPreAuthenticatedPrincipal(request));
if (userName == null || userName.trim().equals("")) {
return userName;
}
return userName;
}
public boolean isAllowPreAuthenticatedPrincipals() {
return allowPreAuthenticatedPrincipals;
}
}
答案 0 :(得分:0)
我的猜测是你并不总是在两个过滤器中执行FilterChain.doFilter方法。然后过滤器链停止,只执行一个自定义过滤器。在这个简单的例子中,两个过滤器都执行了:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new Filter1(), RequestHeaderAuthenticationFilter.class)
.addFilterAfter(new Filter2(), CsrfFilter.class)
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
static class Filter1 extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("executed filter 1");
filterChain.doFilter(request, response);
}
}
static class Filter2 extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("executed filter 2");
filterChain.doFilter(request, response);
}
}
}
答案 1 :(得分:0)
您正在混淆容器注册(使用HttpSecurity
)并在安全过滤器链中注册(使用FilterRegistrationBeans
),也可能使用Spring Security中的过滤器链的顺序。如果Spring Security选择了给定的过滤器链,那么它中的所有过滤器甚至都不需要被激活(过滤器总是可以关闭其他下游过滤器)。
我建议您不要担心@Order
中的订单,并使用它们来禁用容器注册(通过将其启用标志设置为false)。然后考虑WebSecurityConfigurers
上addFilter{Before,After}
指定的过滤器链的顺序。最后,您可以决定给定链中过滤器的顺序是否重要,以及它是否使用{{1}}方法。
答案 2 :(得分:0)
执行您要执行的操作的过滤器已存在。它是OAuth2AuthenticationProcessingFilter
。
如果使用@EnableResourceServer
注释应用程序,则使用此过滤器。如果这样做,这将导致仅基于令牌的身份验证现在可以正常工作。
您必须将此过滤器的无状态标志设置为false
,以允许其他身份验证方式。
我所做的是创建一个扩展ApiTokenAccessFilter
的班级OAuth2AuthenticationProcessingFilter
。此过滤器采用ResourceServerTokenServices
构造函数参数,并将无状态标志设置为false。
public class ApiTokenAccessFilter extends OAuth2AuthenticationProcessingFilter {
public ApiTokenAccessFilter(ResourceServerTokenServices resourceServerTokenServices) {
super();
setStateless(false);
setAuthenticationManager(oauthAuthenticationManager(resourceServerTokenServices));
}
private AuthenticationManager oauthAuthenticationManager(ResourceServerTokenServices tokenServices) {
OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();
oauthAuthenticationManager.setResourceId("oauth2-resource");
oauthAuthenticationManager.setTokenServices(tokenServices);
oauthAuthenticationManager.setClientDetailsService(null);
return oauthAuthenticationManager;
}
}
在我的安全配置中,我使用此过滤器如下:
@Configuration
@EnableOAuth2Sso
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ResourceServerTokenServices tokenServices;
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(new ApiTokenAccessFilter(tokenServices), AbstractPreAuthenticatedProcessingFilter.class);
}
}
我认为这可能会更容易,所以我在spring-security-oauth Github repo上打开了一个问题。我不确定这种解决方案是否可行,但我没有找到另一种选择。