我们实现了由Redis支持的Spring Session,并具有Tomcat服务器集群。当我们通过不设置jvmRoute来关闭粘性会话时,我们会在jcaptcha服务中不断收到“文本验证失败”的信息。我认为这是因为jcaptcha servlet对Spring Dispatcher servlet不了解,该服务器具有所有Spring Session过滤器,因此无法读取会话变量。我们如何使jcaptcha与Spring Session一起工作?
这是我们的设置:
Web.xml
<servlet>
<servlet-name>my-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jcaptcha</servlet-name>
<servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jcaptcha</servlet-name>
<url-pattern>/jcaptcha/jcaptcha.jpg</url-pattern>
</servlet-mapping>
CustomHttpSessionAppInitializer.java
public class CustomHttpSessionAppInitializer extends AbstractHttpSessionApplicationInitializer {}
RedisSessionConfig.java
@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
@Value("${spring.redis.host}")
private String redisServerName;
@Value("${spring.redis.port}")
private Integer redisServerPort;
@Value("${spring.redis.database}")
private Integer redisServerDatabase;
@Value("${spring.redis.password}")
private String redisServerPassword;
@Value("${spring.server.affinity}")
private Boolean isServerAffinity = Boolean.FALSE;
@Autowired
private SessionIdentifierService sessionIdentifierService;
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisServerName, redisServerPort);
config.setDatabase(redisServerDatabase);
config.setPassword(RedisPassword.of(redisServerPassword));
return new JedisConnectionFactory(config);
}
/*
* We need to register every HttpSessionListener as a bean to translate SessionDestroyedEvent and SessionCreatedEvent into
* HttpSessionEvent. Otherwise we will got a lot of warning messages about being Unable to publish Events for the session.
* See Spring Session Docs at:
* {@link} https://docs.spring.io/spring-session/docs/current/reference/html5/#httpsession-httpsessionlistener
*/
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setUseBase64Encoding(false);
if (isServerAffinity) {
serializer.setJvmRoute(sessionIdentifierService.getJvmRoute());
}
return serializer;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}
答案 0 :(得分:0)
将jcaptcha与Spring Session集成应该没有问题。只要有一种方法可以从Redis中加载会话(在这种情况下,通过SESSION cookie)并且该会话存在,则调用request.getSession()
或request.getSession(false)
将返回Redis支持的会话。
这适用于任何称为 AFTER springSessionRepositoryFilter的过滤器和servlet。如果您查看SessionRepositoryFilter
的源代码,就会看到HttpServletRequest
被SessionRepositoryRequestWrapper
交换了。
因此,您的SimpleImageCaptchaServlet
以及用于验证用户响应的servlet都将获得SessionRepositoryRequestWrapper,这似乎使您能够访问Redis支持的会话。
那么问题可能出在您的配置上。 springSessionRepositoryFilter可能未在容器中注册,尤其是因为您同时使用了web.xml和Servlet 3.0+ WebApplicationInitializer
。如果您的应用正常运行,则您的web.xml最有可能运行良好。您是否正在使用WebApplicationInitializer
来加载web.xml?如果不是,则可能是Java Config未加载。确保您的web.xml以某种方式加载配置,可能是通过在contextLoaderListener xml配置文件中启用组件扫描(<context:component-scan/>
)来加载Java Config以及:
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
要加载将创建过滤器的配置,然后必须将其添加到web.xml:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>