spring security重写UsernamePasswordAuthenticationFilter后记住我失效

因为security不支持JSON数据登录,就重写了UsernamePasswordAuthenticationFilter里面的attemptAuthentication方法,代码如下

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationBean authenticationBean = null;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        //use jackson to deserialize json
        ObjectMapper mapper = new ObjectMapper();
        UsernamePasswordAuthenticationToken authRequest = null;
        try (InputStream is = request.getInputStream()){
            AuthenticationBean authenticationBean = mapper.readValue(is,AuthenticationBean.class);
            authRequest = new UsernamePasswordAuthenticationToken(authenticationBean.getUsername(), authenticationBean.getPassword());
        }catch (IOException e) {
            e.printStackTrace();
            authRequest = new UsernamePasswordAuthenticationToken("", "");
        }finally {
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }
}

然后在WebSecurityConfig中加入了这个过滤器。

http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

@Bean
    CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        filter.setAuthenticationFailureHandler(authenticationFailureHandler);
        filter.setFilterProcessesUrl("/login");

        //这句很关键,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

此时可以用JSON传账号密码登录了,然后我又增加了记住我的相关配置。

.and().rememberMe()
                .rememberMeParameter("remember_me")
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60).userDetailsService(userDetailsService())

@Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        System.out.println("启动了记住我。。。");
        //在第一次运行时会创建一个记住我token数据库,只能运行一次
//        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

发现登录成功后没有返回cookie,数据库中也没存有相应的cookie。
但是我把

http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

注释掉,用原始表单的方式登录,记住我又能正常用,前端能接收到cookie,数据库也存了cookie

自定义的过滤器应该放在之前

img


所以你把代码改成下面的就可以了,在UsernamePasswordAuthenticationFilter之前过滤

http.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);