【问题标题】:Does spring-session saves bean with HttpSession?spring-session 是否使用 HttpSession 保存 bean?
【发布时间】:2019-02-16 12:04:48
【问题描述】:

我正在使用 Redis 在我的 JEE 项目中实现 spring-session。 HttpSession 正在我的 Redis 服务器上保存和更新,我可以在节点故障转移的情况下使用它。

问题是,我的会话范围 bean 没有与 Redis 中的会话一起保存,因此我不能在集群上使用,因为用户需要存储在 bean 上的信息才能使用很多功能(坚定的)。

我错过了什么吗?我找不到很多关于此的信息,而且由于我是 Spring 新手,所以它会让人感到困惑。 bean(或可以)是否与会话一起存储在 Redis 中?这是我的实现:

web.xml:

<context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>bootstrap</param-value>
</context-param>

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Production</param-value>
</context-param>

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.faces</url-pattern>
</servlet-mapping>

<session-config>
    <session-timeout>30</session-timeout>
</session-config>
<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

<context-param>
    <param-name>
        javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE
    </param-name>
    <param-value>true</param-value>
</context-param>

<context-param>
    <param-name>com.sun.faces.expressionFactory</param-name>
    <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>

<welcome-file-list>
    <welcome-file>login.faces</welcome-file>
</welcome-file-list>

<error-page>
    <exception-type>com.exception.InvalidPasswordException</exception-type>
    <location>/ErroServlet</location>
</error-page>
<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/login.faces</location>
</error-page>
<error-page>
    <!-- Missing login -->
    <error-code>401</error-code>
    <location>/error.jsp</location>
</error-page>
<error-page>
    <!-- Forbidden directory listing -->
    <error-code>403</error-code>
    <location>/error.jsp</location>
</error-page>
<error-page>  
    <error-code>404</error-code>  
    <location>/error404.jsp</location>  
</error-page> 
<error-page>
    <!-- Uncaught exception -->
    <error-code>500</error-code>
    <location>/error.jsp</location>
</error-page>
<error-page>
    <!-- Unsupported servlet method -->
    <error-code>503</error-code>
    <location>/error.jsp</location>
</error-page>
<error-page>  
    <exception-type>java.lang.Exception</exception-type>  
    <location>/error.jsp</location>  
</error-page>

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

<listener>
    <listener-class>
        org.springframework.web.context.request.RequestContextListener
    </listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring/*.xml
    </param-value>
</context-param>
<listener>

    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

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

<filter>
    <filter-name>UserCheckFilter</filter-name>
    <filter-class>com.servlet.UserCheckFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>UserCheckFilter</filter-name>
    <url-pattern>/admin/*</url-pattern>
    <url-pattern>/dashboard/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>UserLogCheckFilter</filter-name>
    <filter-class>com.servlet.UserLogCheckFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>UserLogCheckFilter</filter-name>
    <url-pattern>/login.faces</url-pattern>
</filter-mapping>


<filter>
    <filter-name>AWSXRayServletFilter</filter-name>
    <filter-class>com.amazonaws.xray.javax.servlet.AWSXRayServletFilter</filter-class>
    <init-param>
        <param-name>fixedName</param-name>
        <param-value>app</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>AWSXRayServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

session.xml:

<context:annotation-config/>

<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />

<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" 
      p:host-name="127.0.0.1" p:port="6379" />

pom.xml:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.18.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session</artifactId>
        <version>1.3.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
        <version>1.3.3.RELEASE</version>
        <type>pom</type>
    </dependency>

控制器:(抽象控制器实现Serializable)

...

@Named
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Controller extends AbstractController {

    // EJB to access database using JPA
    @EJB(mappedName = "java:global/app/app-ejb/ControllerService!com.service.ControllerService")
    ControllerService controllerService;

    // A class with my JPA Entity used in the form and some other properties
    private FormFields formFields;

...

【问题讨论】:

  • 您是否认真地在 java-ee 项目中引入 spring 只是为了能够在 redis 中存储 序列化不可读 对象?我刚刚阅读了您关于此问题的其他 Q/A,建议您不要有充分和正当的理由...您的 java-ee 服务器是什么,我确信它具有内置功能。
  • 哦,通过添加@Component,您不仅引入了 spring-session,而且引入了完整的 spring 注入/上下文框架。在一个类上同时使用组件和命名注释是错误的......我强烈建议不要这样做
  • 您好 Kukeltje,感谢您的反馈!我正试图在 web 项目上远离 JEE,所以引入 spring 没有问题。当然,正如您所指出的,我忽略了一些重要的实现。我正在使用 Payara。我会看一下幻灯片并给你一个反馈。谢谢!

标签: java spring jsf redis spring-session


【解决方案1】:

如果你想从请求中获取会话,你应该在springSessionRepositoryFilter之后添加这个过滤器

<filter>
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>requestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

我也没有在您的 web.xml 中看到此配置,这对于在集群中使用很重要

<context-param>
    <param-name>org.apache.myfaces.USE_ENCRYPTION</param-name>
    <param-value>false</param-value>
</context-param>

因此,当您将 USE_ENCRYPTION 设为 false 时,集群中的节点可以检索会话中的数据。

附:当您使用客户端状态保存而不是禁用加密时,使用https://stackoverflow.com/a/35626681/4431053 很重要。感谢@Kukeltje。

对于 Myfaces,您可以使用以下配置进行加密:

 <context-param>
        <param-name>org.apache.myfaces.ALGORITHM</param-name>
        <param-value>AES</param-value>
    </context-param>
    <!-- Defines the secret (Base64 encoded) used to initialize the secret key
         for encryption algorithm. The size of it depends on the algorithm used for encryption -->
    <context-param>
        <param-name>org.apache.myfaces.SECRET</param-name>
        <param-value>MoH3NzQ1Njc4OTAxMjM0NTY3ODkwMTIz</param-value>
    </context-param>
    <!-- Define the initialization code (Bas64 encoded) that are used to initialize the secret key used
         on the Message Authentication Code algorithm. The size of it depends on the algorithm used for mac calculation -->
    <context-param>
        <param-name>org.apache.myfaces.MAC_SECRET</param-name>
        <param-value>SaEiDiEyMzQ=</param-value>
    </context-param>

【讨论】:

  • 说真的,禁用加密?这就像说某人应该使用纯 http(不是 https)进行基于互联网的银行操作
  • @Kukeltje 当您使用弹簧安全时,加密是无用的。而且正如你所说,当你使用 https 时它完全没用
  • 你能给我发一个链接吗?因为我很难相信这一点
  • @Kukeltje 当您禁用加密时,javax.faces.ViewState 不会加密,它会以简单文本的形式出现在 html 页面中。如果您使用的是 Spring Security,它是没有用的,因为在这种情况下,客户端请求将带有会话 ID,因此它将被忽略并且请求不会到达 jsf 过滤器。
  • 所以一个经过身份验证的客户端,在使用客户端状态保存和禁用加密的应用程序中,在使用 Spring Security 和 https 时不能操作任何东西? alphabot.com/security/blog/2017/java/…
猜你喜欢
  • 2012-03-04
  • 2017-04-02
  • 2019-06-04
  • 2014-11-20
  • 2012-04-09
  • 2018-01-26
  • 2014-01-04
  • 2017-11-02
  • 1970-01-01
相关资源
最近更新 更多