Spring Boot-具有Spring Security的Hazelcast会话复制

时间:2019-04-15 10:17:52

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

我正在尝试使用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;
    }
}

有人可以建议我缺少什么配置,或者有人可以共享示例代码或可以正确配置的任何资源。

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

提前谢谢!

1 个答案:

答案 0 :(得分:1)

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

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