当前位置: 首页 > 知识库问答 >
问题:

Spring Boot-Hazelcast会话复制与Spring Security

顾磊
2023-03-14

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

我已经通过网页上的东西,但不幸的是,我无法设置这一点。应用程序在集群中运行时,在一个节点上登录后,我没有在其他节点上获取会话对象(我正在从会话注册表对象中获取会话)。

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

下面是我到目前为止尝试过的代码配置。

@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());
    }
@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个答案

国俊艾
2023-03-14

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

它使用Hazelcast作为会话缓存,也使用Spring session,我相信这正是您所需要的&它是一个更简单的设置。

 类似资料:
  • 我有一些hazelcast http会话复制特性的问题。 我有些问题: 在同一个tomcat集群中有没有可能有hazelcast封装的应用程序和非hazelcast封装的应用程序? 带有hazelcast的应用程序应该是可分发的?(通过像其他方法一样添加它的web.xml) 部署应用程序的Tomcat不应该在集群中?是否可以在同一tomcat中使用标准tomcat会话复制将其他应用程序群集化? 编

  • 我在Spring Boot应用程序中遵循基于Hazelcast的会话复制文档。 谢谢Aravind

  • 当我介绍hazelcast时,第一次验证是成功的。之后,第一个请求也是成功的。但在那之后 org.springframework.security.web.context.httpsessionSecurityContextRepository找不到会话... 正如我所说,在配置com.hazelcast.web.webfilter进行sesion复制之后,就开始出现这种情况,如下所示: 2017

  • 背景:我在tomcat上部署了一个javaee webapp,它使用基于表单的身份验证。当web服务器接收到登录请求时,它将该请求发送到一个专用的身份验证服务,该服务验证用户登录(用户id和密码)。验证成功后,用户的会话将在web服务器中维护。 问题:我在这里编写了一个简单的webpp源代码,以模拟该场景。成功登录后,当前实例无效,并创建新实例。对于post登录页面的每个请求,都会验证会话。设置一

  • 我试图使用Spring Cloud的Zuul、Eureka和我自己的服务实现微服务架构。我有多个具有UI和服务的服务,每个服务都可以使用x509安全性对用户进行身份验证。现在我想把祖尔放在那些服务机构的前面。由于Zuul无法将客户端证书转发到后端,我认为下一个最好的方法是在Zuul的前门对用户进行身份验证,然后使用Spring会话在后端服务中复制他们的身份验证状态。我遵循了Dave Syer的教程

  • 我使用redisson在运行tomcat V8.5的3个tomcat吊舱中复制spring应用程序的tomcat会话。我还在同一个Kubernetes集群中部署了Redis。下面是我的tomcat context.xml配置 我的redisson配置如下: 当我在所有pod上运行我的应用程序和负载平衡请求时,它会为发送到不同pod的每个请求创建一个新的JSESSIONID cookie 这应该验证