Java Spring使用额外的登录参数记住我
在SpringMVC应用程序中,我在登录屏幕上捕获了一个额外的“location”参数,并将其用于用户名之外的身份验证。所以在“loadUserByUsername”中,我的sql查询类似于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中检索
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。