【问题标题】:Spring Boot - Hazelcast Session Replication with Spring SecuritySpring Boot - 带有 Spring Security 的 Hazelcast 会话复制
【发布时间】:2019-04-15 10:17:51
【问题描述】:

我正在尝试使用 Hazelcast 分布式缓存来复制带有 Spring Boot 和 Spring Security 的 HTTP 会话,但无法设置它(但是,简单的缓存复制工作正常,我已经通过在 map 上设置一些值来验证这一点应用程序节点并试图在其他集群节点上获取它)。

我已经浏览了网络上可用的东西,但不幸的是我无法设置它。应用程序在集群中运行时,登录一个节点后,我没有在另一个节点上获取会话对象(我正在从会话注册表对象中获取会话)。

我已包含依赖项:hazelcast 版本:'3.12' 和 hazelcast-all 版本:'3.12' 在 gradle 构建文件中。

以下是我目前尝试过的代码配置。

我在 AppConfig.java 中添加了下面的 bean

@Bean
    public Config hazelCastConfig(){
        Config config = new Config();
        config.setInstanceName("hazelcast-instance")
                .addMapConfig(
                        new MapConfig()
                                .setName("hazelcastConfiguration")
                                .setMaxSizeConfig(new MaxSizeConfig(200, MaxSizeConfig.MaxSizePolicy.FREE_HEAP_SIZE))
                                .setEvictionPolicy(EvictionPolicy.LRU)
                                .setTimeToLiveSeconds(-1));
        NetworkConfig networkConfig = config.getNetworkConfig();
        networkConfig.setPort(6701).setPortCount(20);
        networkConfig.setPortAutoIncrement(true);
        JoinConfig join = networkConfig.getJoin();
        join.getMulticastConfig().setEnabled(false);
        join.getTcpIpConfig()
                .addMember("localhost")
                .setEnabled(true);
        return config;
    }

@Bean
    public FilterRegistrationBean hazelcastFilter(HazelcastInstance hazelcastInstance) {
        FilterRegistrationBean registration = new FilterRegistrationBean(new SpringAwareWebFilter());
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
        registration.addUrlPatterns("/*");
        registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE);
        registration.addInitParameter("sticky-session", "false");
        registration.addInitParameter("instance-name", hazelcastInstance.getName());
        return registration;
    }

@Bean
    public ServletListenerRegistrationBean<SessionListener> hazelcastSessionListener() {
        return new ServletListenerRegistrationBean<SessionListener>(new SessionListener());
    }

从主类中,我排除了 SessionAutoConfiguration.class

@SpringBootApplication
        (exclude =
        {
                DataSourceAutoConfiguration.class,
                HibernateJpaAutoConfiguration.class,
                SessionAutoConfiguration.class
        }
        )

下面是我的 SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * Reference of UserDetailsService service class instance.
     * @see UserDetailsService
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * Reference of CustomAuthenticationSuccessHandler instance.
     * @see CustomAuthenticationSuccessHandler
     */
    @Autowired
    private CustomAuthenticationSuccessHandler authenticationSuccessHandler;

    /**
     * Reference of CustomAuthenticationEntryPoint instance.
     * @see CustomAuthenticationEntryPoint
     */
    @Autowired
    private CustomAuthenticationEntryPoint authenticationEntryPoint;

    /**
     * Reference of CustomAuthenticationFailureHandler instance.
     * @see CustomAuthenticationFailureHandler
     */
    @Autowired
    private CustomAuthenticationFailureHandler authenticationFailureHandler;

    /**
     * Reference of CustomLogoutSuccessHandler instance.
     * @see CustomLogoutSuccessHandler
     */
    @Autowired
    CustomLogoutSuccessHandler customLogoutSuccessHandler;

    /**
     * Reference of PasswordEncoder utility instance.
     * @see PasswordEncoder
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private SessionRegistry sessionRegistry;

    /**
     * Method representing security configuration details, provides AuthenticationManager.
     *
     * @param auth Allows for easily building in memory authentication, LDAP authentication, JDBC based
     * authentication, adding {@link UserDetailsService}, and adding
     * AuthenticationProviders.
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    /**
     * Method returning a bean of AuthenticationManager which is available during application lifecycle.
     *
     * @return an instance of default AuthenticationManager.
     * @throws Exception
     */
    @Bean
    public AuthenticationManager customAuthenticationManager() throws Exception {
        return authenticationManager();
    }

    /**
     * Method returning a bean of {@link ServletContextInitializer} to register {@link EventListener}s in a Servlet
     * 3.0+ container.
     *
     * This bean can be used to register the following types of listener:
     * <ul>
     * <li>{@link ServletContextAttributeListener}</li>
     * <li>{@link ServletRequestListener}</li>
     * <li>{@link ServletRequestAttributeListener}</li>
     * <li>{@link HttpSessionAttributeListener}</li>
     * <li>{@link HttpSessionListener}</li>
     * <li>{@link ServletContextListener}</li>
     * </ul>
     *
     * @return ServletListenerRegistrationBean
     */
    @Bean
    public static ServletListenerRegistrationBean httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
    }

    /**
     * Method returning a bean of custom authentication filter containing custom success and failure handlers.
     * Also sets SessionAuthenticationStrategy in filter.
     *
     * @return CustomUsernamePasswordAuthenticationFilter
     * @see CustomUsernamePasswordAuthenticationFilter
     * @throws Exception
     */
    @Bean
    public CustomUsernamePasswordAuthenticationFilter authenticationFilter() throws Exception {
        CustomUsernamePasswordAuthenticationFilter authenticationFilter
                = new CustomUsernamePasswordAuthenticationFilter(sessionRegistry);
        authenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        authenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
        authenticationFilter.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/api/login", "POST"));
        authenticationFilter.setAuthenticationManager(customAuthenticationManager());
        authenticationFilter.setSessionAuthenticationStrategy(concurrentSession());
        return authenticationFilter;
    }

    /**
     * Method representing configuration/strategy for concurrent sessions.
     *
     * @return CompositeSessionAuthenticationStrategy A SessionAuthenticationStrategy that accepts multiple
     * SessionAuthenticationStrategy implementations to delegate to. Each
     * SessionAuthenticationStrategy is invoked in turn.
     */
    @Bean
    public CompositeSessionAuthenticationStrategy concurrentSession() {

        ConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy =
                new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
        concurrentAuthenticationStrategy.setMaximumSessions(1);
        concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(false);
        List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<>();
        delegateStrategies.add(concurrentAuthenticationStrategy);
        delegateStrategies.add(new SessionFixationProtectionStrategy());
        delegateStrategies.add(new RegisterSessionAuthenticationStrategy(sessionRegistry));

        CompositeSessionAuthenticationStrategy authenticationStrategy =
                new CompositeSessionAuthenticationStrategy(delegateStrategies);
        return authenticationStrategy;
    }

    /**
     * Method returning a bean of ConcurrentSessionFilter which is available during application life-cycle.
     *
     * @return ConcurrentSessionFilter
     */
    @Bean
    ConcurrentSessionFilter concurrentSessionFilter() {
        CustomConcurrentSessionFilter concurrentSessionFilter = new CustomConcurrentSessionFilter(sessionRegistry);
        return concurrentSessionFilter;
    }

    /**
     * Method representing different types of security rules/configuration for the application.
     *
     * @param http HttpSecurity object to configure HTTP security parameters.
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
        http.sessionManagement().sessionAuthenticationStrategy(concurrentSession());
        http.addFilterBefore(concurrentSessionFilter(), ConcurrentSessionFilter.class);
        http.authorizeRequests()
                .antMatchers("/api/secure/org/**",
                                        "/v2/api-docs",
                                        "/configuration/ui",
                                        "/swagger-resources",
                                        "/configuration/security",
                                        "/swagger-ui.html",
                                        "/webjars*//**//**",
                                        "/swagger-resources/configuration/ui").
                hasAnyAuthority("ADMIN").anyRequest().fullyAuthenticated()

                .antMatchers("/api/secure/dms/**").
                hasAnyAuthority("ADMIN","INTERNAL").anyRequest().fullyAuthenticated()

                    .antMatchers("/api/secure/ext/**","/api/secure/tests/**").
                hasAnyAuthority("ADMIN","INTERNAL","EXT").anyRequest().fullyAuthenticated()         
                .and()
                .addFilterBefore(
                        authenticationFilter(),
                        UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new RequestFilter(), BasicAuthenticationFilter.class)
                /*.addFilterBefore(new RequestFilter(), BasicAuthenticationFilter.class)
                .formLogin().loginPage("/api/login")
                .permitAll()
                .successHandler(authenticationSuccessHandler)
                .failureHandler(authenticationFailureHandler)
                .usernameParameter("email")
                .passwordParameter("password")
                .and()
                .httpBasic().and()*/
                .csrf().ignoringAntMatchers("/api/login","/api/auth/**","/api/secure/**")
                .csrfTokenRepository(csrfTokenRepository())
                .and()
                .logout().logoutUrl("/api/logout")
                .invalidateHttpSession(false).logoutSuccessHandler(customLogoutSuccessHandler)
                .permitAll();

//        http.logout().
//                logoutUrl("/api/auth/logout").
//                logoutSuccessHandler(customLogoutSuccessHandler);
        //http.csrf().disable();
    }


    /**
     * Method overriding/representing security configuration/rules to bypasses configured URLs.
     *
     * @param web WebSecurity object to apply rules.
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/api/auth/**","/api/application/**","/api/unsecure/**");
    }

    /**
     * This method configure global security.
     *
     * @param auth AuthenticationManagerBuilder object
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    /**
     * This method sets CSRF header name in CSRF token repository.
     *
     * @return CsrfTokenRepository repository object
     */
    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }
}

有人可以建议我缺少哪些配置,或者是否有人可以分享示例代码或任何我可以正确配置的资源。

要求只是复制会话,以便其他集群节点知道现有会话。

提前致谢!!!

【问题讨论】:

    标签: spring-boot spring-security hazelcast spring-session


    【解决方案1】:

    请在此处查看我的示例项目:https://github.com/gokhanoner/seajug-demo

    它使用 Hazelcast 作为会话缓存以及使用 Spring Session,我相信这是您所需要的,而且设置更简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      • 2019-08-08
      • 2018-03-18
      • 2018-01-29
      • 2017-07-22
      相关资源
      最近更新 更多