【问题标题】:Spring remember me not working with custom filter and java configurationSpring 记得我没有使用自定义过滤器和 java 配置
【发布时间】:2016-06-03 18:14:45
【问题描述】:

我正在使用自定义身份验证过滤器来捕获 spring mvc 应用程序中的附加登录参数。我想启用记住我的功能,我正在使用 java 配置。但请记住我的功能不起作用。如果用户选中登录页面上的“记住我”复选框,我可以看到一个新条目已添加到persistent_logins 表中。但是一旦会话超时并且用户单击任何应用程序链接,他/她就会被重定向到登录页面。请在下面找到相关代码,

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:-

@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackageClasses=com.test.web.service.impl.UserServiceImpl.class)
@EnableGlobalMethodSecurity(prePostEnabled=true)
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;

    @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")
        .permitAll()
        .and()
        .logout()
        .permitAll()
        .and()
        .exceptionHandling()
        .accessDeniedHandler(accessDeniedExceptionHandler);

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

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() {
        AuthenticationManager manager = null;
        try {
            manager = super.authenticationManagerBean();
        } catch (Exception e) {
            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 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;
    }
}

如果有人能指出我正确的方向,我将非常感激。

更新:-

单击会话过期上的任何应用程序链接后,我在日志中看到以下输出。从日志看来,RememberMeAuthenticationFilter 似乎没有被解雇。

2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-02-22 19:22:12 DEBUG HttpSessionSecurityContextRepository:136 - No HttpSession currently exists
2016-02-22 19:22:12 DEBUG HttpSessionSecurityContextRepository:90 - No SecurityContext was available from the HttpSession: null. A new one will be created.
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-02-22 19:22:12 DEBUG HstsHeaderWriter:129 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@36fb061c
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:127 - Request 'GET /' doesn't match 'POST /logout
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 6 of 13 in additional filter chain; firing Filter: 'CustomAuthenticationFilter'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:127 - Request 'GET /' doesn't match 'POST /login
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 7 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:127 - Request 'GET /' doesn't match 'POST /login
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-02-22 19:22:12 DEBUG AnonymousAuthenticationFilter:102 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-02-22 19:22:12 DEBUG SessionManagementFilter:92 - Requested session ID 87ABB37D528FC51FFC5C47A717813C79 is invalid.
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-02-22 19:22:12 DEBUG FilterChainProxy:337 - / at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/logout'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/resources/**'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/error/**'
2016-02-22 19:22:12 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/secured/**'
2016-02-22 19:22:12 DEBUG FilterSecurityInterceptor:194 - Secure object: FilterInvocation: URL: /; Attributes: [authenticated]
2016-02-22 19:22:12 DEBUG FilterSecurityInterceptor:310 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2016-02-22 19:22:12 DEBUG AffirmativeBased:65 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@732b4495, returned: -1
2016-02-22 19:22:12 TRACE AnnotationConfigWebApplicationContext:331 - Publishing event in Root WebApplicationContext: org.springframework.security.access.event.AuthorizationFailureEvent[source=FilterInvocation: URL: /]
2016-02-22 19:22:12 DEBUG ExceptionTranslationFilter:165 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied

更新 2:-

在添加 rememberMe() 调用之后,RememberMeAuthenticationFilter 被调用,但仍然记住我的功能与之前的行为不同。最新的日志是,

2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-02-22 20:00:08 DEBUG HttpSessionSecurityContextRepository:136 - No HttpSession currently exists
2016-02-22 20:00:08 DEBUG HttpSessionSecurityContextRepository:90 - No SecurityContext was available from the HttpSession: null. A new one will be created.
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-02-22 20:00:08 DEBUG HstsHeaderWriter:129 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@1c6103c2
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:127 - Request 'GET /' doesn't match 'POST /logout
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 6 of 14 in additional filter chain; firing Filter: 'CustomAuthenticationFilter'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:127 - Request 'GET /' doesn't match 'POST /login
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 7 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:127 - Request 'GET /' doesn't match 'POST /login
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 8 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 9 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 10 of 14 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-02-22 20:00:08 DEBUG AnonymousAuthenticationFilter:102 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-02-22 20:00:08 DEBUG SessionManagementFilter:92 - Requested session ID 0C8F3CE7D018DA453CDD9E23A8125212 is invalid.
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-02-22 20:00:08 DEBUG FilterChainProxy:337 - / at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/logout'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/resources/**'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/error/**'
2016-02-22 20:00:08 DEBUG AntPathRequestMatcher:145 - Checking match of request : '/'; against '/secured/**'
2016-02-22 20:00:08 DEBUG FilterSecurityInterceptor:194 - Secure object: FilterInvocation: URL: /; Attributes: [authenticated]
2016-02-22 20:00:08 DEBUG FilterSecurityInterceptor:310 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2016-02-22 20:00:08 DEBUG AffirmativeBased:65 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@3c682cd2, returned: -1
2016-02-22 20:00:08 TRACE AnnotationConfigWebApplicationContext:331 - Publishing event in Root WebApplicationContext: org.springframework.security.access.event.AuthorizationFailureEvent[source=FilterInvocation: URL: /]
2016-02-22 20:00:08 DEBUG ExceptionTranslationFilter:165 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied  

【问题讨论】:

  • 日志记录是什么意思 - 你应该得到所有过滤器的列表,看看是否包含了 rememberme,或者日志记录
  • 您好 Farrellmr,是的,RememberMeAuthenticationFilter 似乎没有被解雇。我不确定为什么。我在上面添加了更新以包含日志摘录。谢谢
  • RememberMeAuthenticationFilter 没有被触发可能是因为我使用了自定义身份验证过滤器?我需要在自定义身份验证过滤器上明确设置 RememberMeAuthenticationFilter 吗?但我不确定如何。我已经检查了 UsernamePasswordAuthenticationFilter api,但找不到方法

标签: java spring spring-mvc spring-security


【解决方案1】:

似乎在 configure() 中没有启用记住; 请参阅

处的示例

http://docs.spring.io/spring-security/site/docs/3.2.x/apidocs/org/springframework/security/config/annotation/web/builders/HttpSecurity.html#rememberMe()

你需要做的

.formLogin()
        .loginPage("/login")
        .permitAll()
        .and()
        .rememberMe()
        .rememberMeServices(persistentTokenBasedRememberMeServices());

【讨论】:

  • 您好 Bhushan,我根据您的建议添加了 rememberMe() 调用,但记住我功能仍然无法正常工作。但是随着这一变化,从日志中可以明显看出,RememberMeAuthenticationFilter 被调用了。请参阅我的更新 2。谢谢
  • 请检查 rememberMeServices.autoLogin(request, response);可能返回空对象。您还需要设置记住我服务来记住我过滤器。
  • 布山,是的。在添加 '.rememberMeServices(rememberMeServices())' 部分之后,spring 现在认识到它是一个记住我的用户,并试图通过数据库中的用户名获取用户。这就是我的问题。如 OP 中所述,我正在使用附加的“位置”参数来验证用户身份。在正常登录期间,我正在捕获位置以及用户名和密码,并在“loadUserByUsername”函数中使用它。现在,如果它是一个记住我的用户,spring 通过只传递一个用户名来调用“loadUserByUsername”。在这种情况下,“位置”将不可用并且查询失败。
  • 从逻辑上讲,用户名是唯一的,并且可以独立于位置进行获取。方法'loadUserByUsername'将返回'UserDetails'对象,该对象将由spring security使用,它是spring定义的对象。我没有找到任何很好的使用位置来创建“UserDetails”对象。如果您仍然需要,您可以将应用程序级别映射(缓存类型)用户名映射到位置。
  • 在我的例子中,可以在创建用户时将用户分配到一个或多个位置。他/她将能够在登录时选择位置,并且只有特定于该位置的数据才会显示给用户。所以我有必要将位置存储在数据库中,在登录期间捕获它,并在身份验证中使用它。应用程序级别的地图可能不是一个选项,因为可以动态添加位置。
猜你喜欢
  • 2015-07-10
  • 2014-07-30
  • 1970-01-01
  • 2015-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
相关资源
最近更新 更多