Java Spring使用额外的登录参数记住我

Java Spring使用额外的登录参数记住我,java,spring,spring-mvc,spring-security,Java,Spring,Spring Mvc,Spring Security,在SpringMVC应用程序中,我在登录屏幕上捕获了一个额外的“location”参数,并将其用于用户名之外的身份验证。所以在“loadUserByUsername”中,我的sql查询类似于 select from user where username = ? and location = ? 现在,如果用户是“记住我”用户,则无法捕获“位置”参数,因为不会出现登录提示。在“记住我”功能的情况下,spring只在cookie中存储用户名。对于RememberMe登录,它从cookie中检索

在SpringMVC应用程序中,我在登录屏幕上捕获了一个额外的“location”参数,并将其用于用户名之外的身份验证。所以在“loadUserByUsername”中,我的sql查询类似于

select from user where username = ? and location = ? 
现在,如果用户是“记住我”用户,则无法捕获“位置”参数,因为不会出现登录提示。在“记住我”功能的情况下,spring只在cookie中存储用户名。对于RememberMe登录,它从cookie中检索用户名,并将其传递给'loadUserByUsername'调用,以从DB加载用户。所以,在我的例子中,对于MemberMe用户,由于“location”为空,因此加载用户的查询失败。
我想知道是否有方法覆盖默认的spring行为,将“location”与用户名一起存储在cookie中,然后将location和用户名传递给PersistentTokenBasedMemberMeservices.ProcessAutologyCookie()中的“loadUserByUsername”。
请参阅下面我的代码以供参考

CustomAuthenticationFilter.java:-

public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        final Long locationId = Long.parseLong(request.getParameter("locations"));
        request.getSession().setAttribute("LOCATION_ID", locationId);

        return super.attemptAuthentication(request, response); 
    } 
}
SecurityConfig.java:-

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    @Autowired
    private AuthenticationManagerBuilder auth;

    @Autowired
    public void configureGlobal(UserDetailsService userDetailsService, AuthenticationManagerBuilder auth) throws Exception {
        auth
        .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    AccessDeniedExceptionHandler accessDeniedExceptionHandler;

    @Bean
    public CustomInvalidSessionStrategy invalidSessionStrategy() {
        return new CustomInvalidSessionStrategy();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
        .antMatchers("/resources/**").permitAll()
        .antMatchers("/error/**").permitAll()
        .antMatchers("/secured/**").hasRole("ADMIN")
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage("/login")
//      .defaultSuccessUrl("/")
        .permitAll()
        .and().rememberMe().rememberMeServices(persistentTokenBasedRememberMeServices())
        .and()
        .logout()
        .permitAll()
        .and()
        .exceptionHandling()
        .accessDeniedHandler(accessDeniedExceptionHandler);

        http.addFilterBefore(customAuthenticationFilter(),
                UsernamePasswordAuthenticationFilter.class);
        http.addFilterAfter(rememberMeAuthenticationFilter(),
                UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() {
        AuthenticationManager manager = null;
        try {
            manager = super.authenticationManagerBean();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return manager;
    }


    @Bean
    public SimpleUrlAuthenticationSuccessHandler simpleUrlAuthenticationSuccessHandler() {
        SimpleUrlAuthenticationSuccessHandler handler = new SimpleUrlAuthenticationSuccessHandler();
        handler.setDefaultTargetUrl("/");
        return handler;
    }

    @Bean
    public SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
        SimpleUrlAuthenticationFailureHandler handler = new SimpleUrlAuthenticationFailureHandler();
        handler.setDefaultFailureUrl("/login?error");
        return handler;
    }

    @Bean
    public CustomAuthenticationFilter customAuthenticationFilter () {
        CustomAuthenticationFilter filter= new  CustomAuthenticationFilter();
        filter.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/login","POST"));
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setUsernameParameter("username");
        filter.setPasswordParameter("password");
        filter.setAuthenticationSuccessHandler(simpleUrlAuthenticationSuccessHandler());
        filter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
        filter.setRememberMeServices(persistentTokenBasedRememberMeServices());
        return filter;
    }

    @Bean
    public RememberMeAuthenticationFilter rememberMeAuthenticationFilter() {
        RememberMeAuthenticationFilter filter = new RememberMeAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setRememberMeServices(persistentTokenBasedRememberMeServices());
        return filter;
    }

    @Bean
    public PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices() {
        PersistentTokenBasedRememberMeServices service = new PersistentTokenBasedRememberMeServices("remember_me_key", userDetailsService, persistentTokenRepository());
        service.setCookieName("remember_me");
        service.setTokenValiditySeconds(864000);
        return service;
    }

    @Autowired
    public UserDetailsService userDetailsService;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
        tokenRepositoryImpl.setDataSource(dataSource);
        return tokenRepositoryImpl;
    }
}

扩展类PersistentTokenBasedMemberMeservices并重写其方法,如下所示

  @Override    
    processAutoLoginCookie(String[] cookieTokens,HttpServletRequest request, HttpServletResponse response){
   super.processAutoLoginCookie(cookieTokens,request,response); // do not provide any implementation to loadUserByUsername() in your CustomUserDetail and add one more method loadUserbyUsenameAndLocation(username, location);
   String location = request.getSession().getAttribute("LOCATION_ID");
   return ((customeUserDetailsService)userDetailsService).loadUserbyUsenameAndLocation(username, location)
}

Hi Bhushan,“位置”仅在用户使用登录页面登录时可用。因为我们在登录页面上捕获位置,然后将其放入CustomAuthenticationFilter的会话中。与此相反,当会话过期并且用户试图访问应用程序时,记住我的登录将出现在图片中。因此,在processAutoLoginCookie()方法中使用的会话中没有可用的位置。不知何故,我必须找到一种方法将位置存储在persistent_logins表中,并在processAutoLoginCookie方法中获取该位置。persistent_logins是spring用于存储remember me令牌并根据cookie中接收的令牌获取用户名的表。您也可以将其添加到cookie中。当用户首次登录时,在Cookie中发送位置id。您可以从请求中检索cookie。