SpringBoot UsernamePasswordAuthenticationFilter问题

时间:2015-05-17 13:56:13

标签: spring-security spring-boot

我正在扩展UsernamePasswordAuthenticationFilter,以便我可以添加自定义字段以将其保存到会话中。

public class AuthFilter extends UsernamePasswordAuthenticationFilter {

@Override
public Authentication attemptAuthentication(HttpServletRequest request,
        HttpServletResponse response) throws AuthenticationException {
    //String dbValue = request.getParameter("dbParam");
    //request.getSession().setAttribute("dbValue", dbValue);
    System.out.println("attempting to authentificate");
    while (request.getAttributeNames().hasMoreElements()) {
        String e = (String) request.getAttributeNames().nextElement();
        System.out.println("param name : " + e + " and param value : " + request.getAttribute(e));
    }

    return super.attemptAuthentication(request, response);
    }
}

我的WebSecurityConfig

@Configuration
@EnableWebMvcSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;


@Bean
public AuthFilter customUsernamePasswordAuthenticationFilter()
        throws Exception {
    AuthFilter customUsernamePasswordAuthenticationFilter = new AuthFilter();
    customUsernamePasswordAuthenticationFilter
            .setAuthenticationManager(authenticationManagerBean());
   return customUsernamePasswordAuthenticationFilter;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterAfter(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

    http.exceptionHandling().accessDeniedPage("/403").and()
            .authorizeRequests().antMatchers("/login", "/public/**").permitAll()
            .antMatchers("/users/**").hasAuthority("ADMIN")
            .anyRequest()
            .authenticated().and().formLogin().loginPage("/login")
            .defaultSuccessUrl("/index").permitAll().and().logout()
            .permitAll();


    http.sessionManagement().maximumSessions(1)
            .expiredUrl("/login?expired").and()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
            .invalidSessionUrl("/");
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws  Exception {
    auth.eraseCredentials(false)
    .userDetailsService(userDetailsService);
}

映射过滤器:' customUsernamePasswordAuthenticationFilter'致:[/ *]

所以我确定已经正确添加了过滤器,但是我永远无法打印出内部的内容,因此在验证过程中不会调用它。

我使用的是Thymeleaf,没有xml配置。

作为@M。 Deinum建议, 我将UsernamePasswordAuthenticationFilter改为AbstractAuthenticationProcessingFilter,称为super(new AntPathRequestMatcher("/login","POST")); addFilterAfter更改为addFilterBefore,以及一些代码,并且有效!

2 个答案:

答案 0 :(得分:8)

假设您使用的是最新的Spring Boot(1.2.3),那么您使用的是Spring Security 3.2.7。此版本将UsernamePasswordAuthenticationFilter映射到/j_spring_security_check。但是,使用基于java的配置时,这将更改为/login

您仍然会映射到旧网址。要修复此扩展AbstractAuthenticationProcessingFilter,请添加一个默认的no-args构造函数,该构造函数调用带有RequestMatcher的超级构造函数。这样做的缺点是,如果您仍然需要(或想要扩展)UsernamePasswordAuthenticationFilter的功能,则必须复制它。

public AuthFilter() {
    super(new AntPathRequestMatcher("/login","POST"));
}

另一种解决方案是继续扩展UsernamePasswordAuthenticationFilter并从那里调用setRequiresAuthenticationRequestMatcher

public AuthFilter() {
    super();
    setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
}

或者您从工厂方法调用该方法。

@Bean
public AuthFilter customUsernamePasswordAuthenticationFilter()
    throws Exception {
    AuthFilter customUsernamePasswordAuthenticationFilter = new AuthFilter();
    customUsernamePasswordAuthenticationFilter
        .setAuthenticationManager(authenticationManagerBean());
    customUsernamePasswordAuthenticationFilter
        .setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
    return customUsernamePasswordAuthenticationFilter;
}

您的配置还有另一个问题,您的过滤器将永远不会被执行,因为它在默认UsernamePasswordAuthenticationFilter之后执行,并且身份验证已经发生,您的过滤器将永远不会执行。确保它在默认过滤器之前执行。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    ...
}

答案 1 :(得分:1)

为了使您的自定义UsernamePasswordAuthenticationFilter实现起作用,请将.loginProcessingUrl(“ / dologin”)添加到您的HttpSecurity中 WebSecurityConfig,这里的“ / dologin”是html表单元素的动作属性值:

@Override
//@Order(Ordered.HIGHEST_PRECEDENCE)
public void configure(HttpSecurity http) throws Exception { // @formatter:off
    http
        ...
        ...
        .formLogin().loginPage("/login")
   -->  .loginProcessingUrl("/dologin") <-- add here
        ...
   -->  .addFilterBefore(new AuthFilter(authenticationManagerBean()),UsernamePasswordAuthenticationFilter.class)
 }

下一步是提供自定义的UsernamePasswordAuthenticationFilter实现:

public class AuthFilter extends UsernamePasswordAuthenticationFilter {

   AuthenticationManager authenticationManager;

   private boolean continueChainBeforeSuccessfulAuthentication = false;


   public AuthFilter( AuthenticationManager authenticationManager){
      this.authenticationManager = authenticationManager;
      //idk why I have to do this, otherwise it's null
      super.setAuthenticationManager(authenticationManager);
   }

    public AuthFilter() {}

   private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
   //path to which this filter will intercept
   RequestMatcher customFilterUrl = new AntPathRequestMatcher("/dologin"); <--

  //dofilter method is copied from AbstractAuthenticationProcessingFilter
  @Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
      HttpServletRequest request = (HttpServletRequest)req;
      HttpServletResponse response = (HttpServletResponse)res;
      //if no match then go to next filter
      if (!customFilterUrl.matches(request)) {
         chain.doFilter(request, response);
      } else {

        Authentication authResult;
        try {
            authResult = this.attemptAuthentication(request, response);
            if (authResult == null) {
                return;
            }

            this.sessionStrategy.onAuthentication(authResult, request, response);
        } catch (InternalAuthenticationServiceException var8) {
            this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
            this.unsuccessfulAuthentication(request, response, var8);
            return;
        } catch (AuthenticationException var9) {
            this.unsuccessfulAuthentication(request, response, var9);
            return;
        }

        if (this.continueChainBeforeSuccessfulAuthentication) {
            chain.doFilter(request, response);
        }

        successfulAuthentication(request, response, chain, authResult);
    }
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request, 
 HttpServletResponse response)
        throws AuthenticationException {

    System.out.println("Your prints"); <--

    return super.attemptAuthentication(request,response);
  }
}