Spring security SpringBoot用户名PasswordAuthenticationFilter问题

Spring security SpringBoot用户名PasswordAuthenticationFilter问题,spring-security,spring-boot,Spring Security,Spring Boot,我正在扩展UsernamePasswordAuthenticationFilter,以便添加自定义字段以将它们保存到会话中 public class AuthFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse respon

我正在扩展
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);
    }
}
还有我的网站安全配置

@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(新的AntPathRequestMatcher(“/login”,“POST”);

addFilterAfter
更改为
addFilterBefore
,并添加了一点代码,成功了

假设您使用的是最新的Spring Boot(1.2.3),那么您使用的是Spring Security 3.2.7。此版本将映射到
/j\u Spring\u Security\u check
。但是,当使用基于java的配置时,会将其更改为
/login


您的仍映射到旧URL。要修复此问题,请添加一个默认的无参数构造函数,该构造函数调用超级构造函数,该构造函数接受一个请求匹配器。这样做的缺点是,如果您仍然需要(或想要扩展)UsernamePasswordAuthenticationFilter的功能,则必须复制它

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

另一个解决方案是仍然扩展
usernamespasswordauthenticationfilter
并从那里调用
setrequireauthenticationrequestmatcher

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);
    ...
}

为了使自定义UsernamePasswordAuthenticationFilter实现正常工作,请将.loginProcessingUrl(“/dologin”)添加到 WebSecurity配置,此处“/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)
 }
@覆盖
//@顺序(有序。最高优先级)
public void configure(HttpSecurity http)引发异常{/@formatter:off
http
...
...
.formLogin().login页面(“/login”)

-->.loginProcessingUrl(“/dologin”).addFilterBefore(新建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);
  }
}

公共类AuthFilter扩展了UsernamePasswordAuthenticationFilter{
AuthenticationManager AuthenticationManager;
private boolean ContinueChaineBefore SuccessfulAuthentication=false;
公共AuthFilter(AuthenticationManager AuthenticationManager){
this.authenticationManager=authenticationManager;
//idk为什么我必须这样做,否则它是空的
super.setAuthenticationManager(authenticationManager);
}
公共AuthFilter(){}
private SessionAuthenticationStrategy sessionStrategy=新的NullAuthenticatedSessionStrategy();
//此筛选器将截取的路径

RequestMatcher customFilterUrl=新的AntPathRequestMatcher(“/dologin”);没有,因为身份验证已经发生,所以无需再做任何事情。将其添加到
用户名密码身份验证筛选器
之前,而不是之后。尝试了它,同样的问题。您可能还希望避免将其注册为
@Bean
,因为它现在也被添加到普通筛选器链而不是spring安全链。Sp默认情况下,ring Boot将所有定义的
@Bean
过滤器注册为过滤器,您只想将它们添加到Spring安全过滤器链中。我去掉了Bean注释,它已注册,但在身份验证期间仍然没有调用,因为我看不到我的打印。实际上没有,它没有,它获得了管理的版本这取决于Spring Boot版本。假设您使用的是最新的Spring Boot(1.2.3)您可能正在使用Spring Security 3.2.7。此版本将
用户名密码身份验证筛选器
映射到
/j\u Spring\u Security\u check
,但是,当使用java配置时,默认配置将更改为
/login
。但是,您的用户名密码身份验证筛选器仍映射到旧URL。创建一个调用
super的默认构造函数(新的AntPathRequestMatcher(“/login”,“POST”))
。UsernamePasswordAuthenticationFilter没有带参数的super,这就是我后来扩展另一个类的原因。问题是您的筛选器现在没有登录功能,因为这是特定于
UsernamePasswordAuthenticationFilter
的。我修改了答案,以包含两个其他可能的解决方案。。。