2015-04-10 1 views
7

Я встречая проблема с моей запомнить меня конфигурации:Проблема с Spring Security запомнить лексема не установлен на SecurityContextHolder

[nio-8080-exec-8] s.s.w.a.r.RememberMeAuthenticationFilter : SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframew[email protected]73939efa: Principal: Member ... 

Вот моя конфигурация Spring безопасности:

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private MemberUserDetailsService memberUserDetailsService; 

    @Autowired 
    private BCryptPasswordEncoder passwordEncoder; 

    @Autowired 
    private AccessDecisionManager accessDecisionManager; 

    @Autowired 
    private ApplicationEventPublisher eventPublisher; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     //@formatter:off 
     http 
     .headers() 
     .cacheControl() 
      .and() 
     .and() 
     .csrf() 
     .csrfTokenRepository(csrfTokenRepository()) 
     .and() 
     .rememberMe() 
     .tokenValiditySeconds(60*60*24*7) 
     .and() 
      .exceptionHandling() 
      .accessDeniedHandler(accessDeniedHandler()) 
     .and() 
      .formLogin() 
      .loginProcessingUrl("/api/signin") 
      .failureHandler(authenticationFailureHandler()) 
      .successHandler(authenticationSuccessHandler()) 
     .and() 
      .logout() 
      .logoutRequestMatcher(new AntPathRequestMatcher("/api/signout")) 
      .logoutSuccessHandler(logoutSuccessHandler()) 
     .and() 
      .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class) 
      .authorizeRequests() 
       .accessDecisionManager(accessDecisionManager) 
       .antMatchers("/resources/**", "/**").permitAll() 
       .anyRequest().authenticated(); 
     //@formatter:on 
    } 

    private LogoutSuccessHandler logoutSuccessHandler() { 
     return new LogoutSuccessHandler() { 
      @Override 
      public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
       response.setStatus(HttpStatus.OK.value()); 
      } 
     }; 
    } 

    private AccessDeniedHandler accessDeniedHandler() { 
     return new AccessDeniedHandler() { 
      @Override 
      public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 
       // TODO: deal with InvalidCsrfTokenException 
       response.setStatus(HttpStatus.FORBIDDEN.value()); 
      } 
     }; 
    } 

    private AuthenticationFailureHandler authenticationFailureHandler() { 
     return new AuthenticationFailureHandler() { 
      @Override 
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 
       response.setStatus(HttpStatus.UNAUTHORIZED.value()); 
      } 
     }; 
    } 

    private AuthenticationSuccessHandler authenticationSuccessHandler() { 
     return new AuthenticationSuccessHandler() { 
      @Override 
      public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
       Member member = (Member) authentication.getPrincipal(); 
       eventPublisher.publishEvent(new SigninApplicationEvent(member)); 
       // TODO: overhaul below 
       response.addHeader("MEMBER_ROLE", member.getRole().name()); 
       response.setStatus(HttpStatus.OK.value()); 
      } 
     }; 
    } 

    @Bean 
    @Override 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(memberUserDetailsService).passwordEncoder(passwordEncoder); 
    } 

    private CsrfTokenRepository csrfTokenRepository() { 
     HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 
     repository.setHeaderName("X-XSRF-TOKEN"); 
     return repository; 
    } 
} 

, а также:

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class CoreSecurityConfiguration { 

    @Bean 
    public MemberUserDetailsService memberUserDetailsService() { 
     return new MemberUserDetailsService(); 
    } 

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

    @Bean 
    public SessionRegistryImpl sessionRegistry() { 
     SessionRegistryImpl sessionRegistry = new SessionRegistryImpl(); 
     return sessionRegistry; 
    } 

    @Bean 
    public AffirmativeBased accessDecisionManager() { 
     AffirmativeBased accessDecisionManager = new AffirmativeBased(accessDecisionVoters()); 
     return accessDecisionManager; 
    } 

    private List<AccessDecisionVoter<? extends Object>> accessDecisionVoters() { 
     List<AccessDecisionVoter<? extends Object>> accessDecisionVoters = new ArrayList<>(); 
     accessDecisionVoters.add(roleHierarchyVoter()); 
     accessDecisionVoters.add(webExpressionVoter()); 
     return accessDecisionVoters; 
    } 

    @Bean 
    public WebExpressionVoter webExpressionVoter() { 
     WebExpressionVoter webExpressionVoter = new WebExpressionVoter(); 
     webExpressionVoter.setExpressionHandler(defaultWebSecurityExpressionHandler()); 
     return webExpressionVoter; 
    } 

    @Bean 
    public DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler() { 
     DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); 
     defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy()); 
     return defaultWebSecurityExpressionHandler; 
    } 

    @Bean 
    public RoleHierarchyVoter roleHierarchyVoter() { 
     RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy()); 
     return roleHierarchyVoter; 
    } 

    @Bean 
    public RoleHierarchyImpl roleHierarchy() { 
     RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); 
     //@formatter:off 
     roleHierarchy.setHierarchy(
       "ROLE_ADMINISTRATOR > ROLE_MODERATOR\n" + 
       "ROLE_MODERATOR > ROLE_SUBSCRIBED_PARENTS\n" + 
       "ROLE_MODERATOR > ROLE_SUBSCRIBED_CHILDCARE_WORKER\n" + 
       "ROLE_SUBSCRIBED_PARENTS > ROLE_BASIC_PARENTS\n" + 
       "ROLE_SUBSCRIBED_CHILDCARE_WORKER > ROLE_BASIC_CHILDCARE_WORKER"); 
     //@formatter:on 
     return roleHierarchy; 
    } 

} 

Может ли это помочь?

редактировать 1:

MemberUserDetailsService:

@Component 
public class MemberUserDetailsService implements UserDetailsService { 

    @Autowired 
    private MemberRepository memberRepository; 

    @Override 
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { 
     Member member = memberRepository.findByEmail(email); 
     if (member == null) { 
      throw new UsernameNotFoundException("Username: " + email + " not found!"); 
     } 
     return member; 
    } 

} 

редактировать 2: Вот новый конфигурационный:

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private MemberUserDetailsService memberUserDetailsService; 

    @Autowired 
    private BCryptPasswordEncoder passwordEncoder; 

    @Autowired 
    private AccessDecisionManager accessDecisionManager; 

    @Autowired 
    private ApplicationEventPublisher eventPublisher; 

    @Autowired 
    private CsrfTokenRepository csrfTokenRepository; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     //@formatter:off 
     http 
     .headers() 
     .cacheControl() 
      .and() 
     .and() 
     .csrf() 
     .csrfTokenRepository(csrfTokenRepository()) 
     .and() 
     .rememberMe() 
     .key("myKey") 
     .tokenValiditySeconds(60*60*24*7) 
     .userDetailsService(memberUserDetailsService) 
     .and() 
      .exceptionHandling() 
      .accessDeniedHandler(accessDeniedHandler()) 
     .and() 
      .formLogin() 
      .loginProcessingUrl("/api/signin") 
      .failureHandler(authenticationFailureHandler()) 
      .successHandler(authenticationSuccessHandler()) 
     .and() 
      .logout() 
      .logoutRequestMatcher(new AntPathRequestMatcher("/api/signout")) 
      .logoutSuccessHandler(logoutSuccessHandler()) 
     .and() 
      .addFilter(usernamePasswordAuthenticationFilter()) 
      .addFilter(rememberMeAuthenticationFilter()) 
      .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class) 
      .authorizeRequests() 
       .accessDecisionManager(accessDecisionManager) 
       .antMatchers("/resources/**", "/**").permitAll() 
       .anyRequest().authenticated(); 
     //@formatter:on 
    } 

    private LogoutSuccessHandler logoutSuccessHandler() { 
     return new LogoutSuccessHandler() { 
      @Override 
      public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
       response.setStatus(HttpStatus.OK.value()); 
      } 
     }; 
    } 

    private AccessDeniedHandler accessDeniedHandler() { 
     return new AccessDeniedHandler() { 
      @Override 
      public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { 
       // TODO: deal with InvalidCsrfTokenException & MissingCsrfTokenException 
       response.setStatus(HttpStatus.FORBIDDEN.value()); 
      } 
     }; 
    } 

    private AuthenticationFailureHandler authenticationFailureHandler() { 
     return new AuthenticationFailureHandler() { 
      @Override 
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { 
       response.setStatus(HttpStatus.UNAUTHORIZED.value()); 
      } 
     }; 
    } 

    private AuthenticationSuccessHandler authenticationSuccessHandler() { 
     return new AuthenticationSuccessHandler() { 
      @Override 
      public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
       response.setStatus(HttpStatus.OK.value()); 
       Member member = (Member) authentication.getPrincipal(); 
       eventPublisher.publishEvent(new SigninApplicationEvent(member)); 
       response.setStatus(HttpStatus.OK.value()); 
       // TODO: overhaul below 
       response.addHeader("MEMBER_ROLE", member.getRole().name()); 
      } 
     }; 
    } 

    @Bean 
    @Override 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(rememberMeAuthenticationProvider()).userDetailsService(memberUserDetailsService).passwordEncoder(passwordEncoder); 
    } 

    @Bean 
    protected CsrfTokenRepository csrfTokenRepository() { 
     HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 
     repository.setHeaderName("X-XSRF-TOKEN"); 
     return repository; 
    } 

    @Bean 
    public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() { 
     return new RememberMeAuthenticationProvider("myKey"); 
    } 

    @Bean 
    public RememberMeServices rememberMeServices() { 
     return new TokenBasedRememberMeServices("myKey", memberUserDetailsService); 
    } 

    @Bean 
    public RememberMeAuthenticationFilter rememberMeAuthenticationFilter() throws Exception { 
     return new RememberMeAuthenticationFilter(authenticationManager(), rememberMeServices()); 
    } 

    @Bean 
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception { 
     UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(); 
     filter.setRememberMeServices(rememberMeServices()); 
     filter.setAuthenticationManager(authenticationManager()); 
     return filter; 
    } 

} 
+0

Просьба шаги, которые привели к этому вопросу. – Mithun

+0

Шаги, которые приводят к проблеме, - это просто вход в систему безопасности весны. – balteo

+0

Пожалуйста, поделитесь также кодом для 'MemberUserDetailsService'. – Mithun

ответ

3

Поскольку вы не указали службы Запомни меня тип реализации, TokenBasedRememberMeServices используется по умолчанию.

Пожалуйста, найдите ниже записку от документации при использовании TokenBasedRememberMeServices:

Не забудьте добавить RememberMeServices реализацию в вашей UsernamePasswordAuthenticationFilter.setRememberMeServices() собственности, включают RememberMeAuthenticationProvider в вашем AuthenticationManager.setProviders() списке, и добавить RememberMeAuthenticationFilter в ваш FilterChainProxy (обычно сразу после вашего UsernamePasswordAuthenticationFilter)

Вам необходимо сделать следующие изменения:

  1. In configure() метод вам нужно добавить ключ и фильтры

    http.rememberMe().key("yourKey")

    .addFilter(usernamePasswordAuthenticationFilter()) .addFilter(rememberMeAuthenticationFilter())

  2. Создать UsernamePasswordAuthenticationFilter и RememberMeAuthenticationFilter

    @Bean 
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() 
           throws Exception { 
        UsernamePasswordAuthenticationFilter filter = 
           new UsernamePasswordAuthenticationFilter(); 
        filter.setRememberMeServices(memberUserDetailsService);  
        filter.setAuthenticationManager(authenticationManager()); 
        return filter; 
    } 
    
    @Bean 
    public RememberMeAuthenticationFilter rememberMeAuthenticationFilter() 
            throws Exception { 
        RememberMeAuthenticationFilter filter = 
          new RememberMeAuthenticationFilter(authenticationManager(), memberUserDetailsService); 
        return filter; 
    } 
    
  3. Добавить RememberMeAuthenticationProvider в список поставщиков:

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) 
        throws Exception {    
        auth.userDetailsService(memberUserDetailsService) 
         .passwordEncoder(passwordEncoder) 
         .and() 
         .authenticationProvider(new RememberMeAuthenticationProvider("yourKey")); 
    } 
    
+0

Спасибо за ваш вклад. Я попробовал предоставленный код. Он имеет две ошибки: в 'filter.setRememberMeServices (memberUserDetailsService); '&' new RememberMeAuthenticationFilter (authenticationManager(), memberUserDetailsService); ** memberUserDetailsService ** должен быть ** помнитьMeServices **? – balteo

+0

Это, похоже, не работает. Я редактирую свой пост, чтобы отразить точные изменения. Как насчет порядка фильтров? Это имеет значение? – balteo

+0

Благодарим вас за возможные повреждения. Что касается упорядочения фильтров, 'UsernamePasswordAuthenticationFilter' должен поступать до' RememberMeAuthenticationFilter' в цепочке фильтров, которая уже позаботилась в вашей конфигурации. Еще одно изменение, не уверенный, что это сработает, вы могли бы удалить 'CsrfHeaderFilter' и попробовать. – Mithun