servlets - 如何使 jcaptcha 与 Spring Session 一起使用?

标签 servlets captcha spring-session jcaptcha

我们实现了由 Redis 支持的 Spring Session,并拥有一个 Tomcat 服务器集群。当我们通过不设置 jvmRoute 来关闭粘性 session 时,我们在 jcaptcha 服务中不断收到“文本验证失败”消息。我认为这是因为 jcaptcha servlet 对 Spring Dispatcher servlet 一无所知,Spring Dispatcher servlet 具有所有 Spring Session 过滤器,因此无法读取 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;
    }
}

最佳答案

将 jcaptcha 与 Spring Session 集成应该不会有问题。只要有办法从 Redis 加载 session (在本例中是通过 SESSION cookie)并且 session 存在,调用 request.getSession()request.getSession(false)将返回 Redis 支持的 session 。

这适用于任何在 springSessionRepositoryFilter 之后调用的过滤器和 servlet。如果你看SessionRepositoryFilter的源代码,您会看到HttpServletRequestSessionRepositoryRequestWrapper 交换.

所以你的SimpleImageCaptchaServlet无论您使用哪个 servlet 来验证用户响应,都将获得一个 SessionRepositoryRequestWrapper,它将让您顺利访问 Redis 支持的 session 。

问题可能出在您的配置上; springSessionRepositoryFilter 可能未在容器中注册,特别是因为您同时使用 web.xml 和 Servlet 3.0+ WebApplicationInitializer 。如果您的应用程序工作正常,那么您的 web.xml 很可能工作正常。您使用的是 WebApplicationInitializer加载你的web.xml?如果没有,则可能是您的 Java 配置未加载。确保您的 web.xml 以某种方式加载您的配置,也许可以通过在 contextLoaderListener xml 配置文件中启用组件扫描 ( <context:component-scan/> ) 来加载您的 Java 配置:

<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>

查看 Spring Session reference on XML config

关于servlets - 如何使 jcaptcha 与 Spring Session 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54046802/

相关文章:

java - 无法从表单操作调用 servlet

java - 有没有办法从 Jcaptcha 中过滤掉攻击性的词?

captcha - 那么,如果验证码即将被淘汰,接下来会发生什么?

spring boot 启用 redis http session

security - tomcat 7 基于表单的身份验证

java - 使用 JSTL 读取动态数组

http - 处理用户的多个同时 HttpSession

javascript - ReCaptcha API v2 样式

java - Spring Security 如何通过各种 session 创建和 session 固定组合来处理 JSESSIONID?