首页 > 解决方案 > Spring Working sessionRegistry 不使用 CAS auth

问题描述

我正在使用 Spring Boot 2.1.6.RELEASE。

我需要使角色已更改的用户的会话到期。

我试图使用 sessionRegistry 但它不起作用,我不知道为什么......

这是我的 SecurityConfigurer 类:

/**
 * Configuració de seguretat
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    public static final String WEB = "\\/((?!api).*)";
    public static final String API = "/api/**";

    @Order(1)
    @Configuration
    public static class RestApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Resource(name = "restAuthenticationFilter")
        private Filter restAuthenticationFilter;

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                .antMatcher(API)
                .csrf().disable()
                .antMatcher(API)
                .addFilterBefore(restAuthenticationFilter, CsrfFilter.class)
                .antMatcher(API)
                .authorizeRequests()
                .antMatchers(API).authenticated()
                .and()
                .antMatcher(API)
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            ;
        }
    }



    @Order(2)
    @Configuration
    public static class ApplicacionWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        private final CasProperties casProperties;

        private final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUsuariDetailsService;

        private final UserDetailsService usuariDetailsService;

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

        @Bean
        public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
            return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
        }

        @Autowired
        public ApplicacionWebSecurityConfigurerAdapter(
            CasProperties casProperties,
            AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUsuariDetailsService,
            @Qualifier("casUserDetailsService")
                UserDetailsService usuariDetailsService) {
            this.casProperties = casProperties;
            this.casUsuariDetailsService = casUsuariDetailsService;
            this.usuariDetailsService = usuariDetailsService;
        }


        @Bean
        public ServiceProperties serviceProperties() throws UnknownHostException {

            ServiceProperties serviceProperties = new ServiceProperties();
            serviceProperties.setService(getUrlWithHostName(casProperties.getValidateUrl()));
            serviceProperties.setSendRenew(false);
            return serviceProperties;
        }

        @Bean
        public CasAuthenticationProvider casAuthenticationProvider() throws UnknownHostException {
            CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
            casAuthenticationProvider
                .setAuthenticationUserDetailsService(casUsuariDetailsService);
            casAuthenticationProvider.setServiceProperties(serviceProperties());
            casAuthenticationProvider
                .setTicketValidator(cas20ServiceTicketValidator());
            casAuthenticationProvider.setKey("an_id_for_this_auth_provider_only");
            return casAuthenticationProvider;
        }


        @Bean
        public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
            return new Cas20ServiceTicketValidator(casProperties.getReturnUrl());
        }

        @Bean
        public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
            CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
            casAuthenticationFilter
                .setAuthenticationManager(authenticationManager());
            casAuthenticationFilter.setFilterProcessesUrl("/cas/login");
            casAuthenticationFilter.setSessionAuthenticationStrategy(sessionControlAuthenticationStrategy());
            return casAuthenticationFilter;
        }

        @Bean
        public CasAuthenticationEntryPoint casAuthenticationEntryPoint() throws UnknownHostException {
            CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
            casAuthenticationEntryPoint.setLoginUrl(casProperties.getLoginUrl());
            casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
            return casAuthenticationEntryPoint;
        }

        @Bean
        public ConcurrentSessionControlAuthenticationStrategy sessionControlAuthenticationStrategy() {
            ConcurrentSessionControlAuthenticationStrategy csas = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
            csas.setMaximumSessions(1);
            csas.setExceptionIfMaximumExceeded(true);
            return csas;
        }
        /*
         * User impersonation
         */
        @Bean
        public SwitchUserFilter switchUserFilter() {
            SwitchUserFilter filter = new SwitchUserFilter();
            filter.setUserDetailsService(usuariDetailsService);
            filter.setSwitchUserUrl("/login/impersonate");
            filter.setExitUserUrl("/logout/impersonate");
            filter.setTargetUrl("/");
            filter.setUsernameParameter("username");
            filter.setSwitchFailureUrl("/");
            return filter;
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
            auth.authenticationProvider(casAuthenticationProvider());
        }
        @Bean
        public Filter ajaxTimeOutRedirectFilter() {
            AjaxTimeoutRedirectFilter f = new AjaxTimeoutRedirectFilter();
            f.setCustomSessionExpiredErrorCode(HttpStatus.UNAUTHORIZED.value());
            return f;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // Afegim el filtre del cas a les peticions
            http.addFilter(casAuthenticationFilter());

            http
                .regexMatcher(WEB)
                .exceptionHandling().authenticationEntryPoint(
                casAuthenticationEntryPoint())
                .and()
                .addFilterAfter(ajaxTimeOutRedirectFilter(), ExceptionTranslationFilter.class)
            ;

            http
                .regexMatcher(WEB)
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

                .and()
                .regexMatcher(WEB)
                .authorizeRequests()
                .antMatchers("/images/**", "/css/**", "/fonts/**", "/js/**", "/bower_components/**").permitAll()
                .antMatchers("/logout").permitAll()
                .antMatchers("/cas/login").permitAll()
                .antMatchers("/login/impersonate").hasRole("ADMIN")
                // Actuator
                .antMatchers("/health").permitAll()
                .antMatchers("/info").permitAll()
                .antMatchers("/actuator").permitAll()
                // Swagger
                .antMatchers("/swagger-resources/**",
                    "/v2/api-docs", "/webjars/**", "/swagger-ui.html").permitAll()
                // Resta
                .regexMatchers(WEB).authenticated()
            ;


            http
                .regexMatcher(WEB)
                .logout().logoutUrl("/logout").deleteCookies("JSESSIONID")
                .logoutSuccessUrl(getUrlWithHostName(casProperties.getLogoutUrl()))
                .invalidateHttpSession(true);

            http
                .regexMatcher(WEB)
                .headers().frameOptions().sameOrigin();


        }

        private String getUrlWithHostName(String urlToFormat) throws UnknownHostException {

            return MessageFormat.format(urlToFormat, InetAddress
                .getLocalHost().getCanonicalHostName());
        }

    }

}

我已经尝试了很多,但似乎注册表总是空的,并且主体和会话总是返回一个空映射......

有什么建议吗?谢谢

标签: javaspringspring-bootspring-securitysession-state

解决方案


似乎 ConcurrentSessionAuthenticationStrategy 还需要一个RegisterSessionAuthenticationStrategy,如 Cyril Gabis 在这里的回答中所述:SAML 身份验证的用户不会出现在 Spring Security 的 SessionRegistry 中。以下对我有用:

@Bean
public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    List<SessionAuthenticationStrategy> strategies = new ArrayList<>();
    ConcurrentSessionControlAuthenticationStrategy concurrentStrategy =
            new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
    concurrentStrategy.setMaximumSessions(1);
    concurrentStrategy.setExceptionIfMaximumExceeded(true);
    RegisterSessionAuthenticationStrategy registerStrategy =
            new RegisterSessionAuthenticationStrategy(sessionRegistry());
    strategies.add(concurrentStrategy);
    strategies.add(registerStrategy);
    return new CompositeSessionAuthenticationStrategy(strategies);
}

总之:

  1. 创建 SessionRegistry bean
  2. 创建 SessionAuthenticationStrategy bean
  3. 向 CasAuthenticationFilter 注册 SessionAuthenticationStrategy bean(或者在使用 SAML 时,SAMLProcessingFilter)。

会话注册 bean:

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

使用 CasAuthenticationFilter 注册它:

@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
    casAuthenticationFilter.setAuthenticationManager(authenticationManager());
    casAuthenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
    return casAuthenticationFilter;
}

推荐阅读