Spring Session with MongoDB – 与MongoDB的Spring Session

最后修改: 2019年 6月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll be exploring how to use the Spring Session backed with MongoDB, both with and without Spring Boot.

在这个快速教程中,我们将探讨如何在MongoDB中使用Spring Session backed,无论是否有Spring Boot。

Spring Session can also be backed with other stores such as Redis and JDBC.

Spring Session还可以与其他存储设备进行备份,如RedisJDBC

2. Spring Boot Configuration

2.Spring Boot配置

First, let’s look at the dependencies and the configuration required for Spring Boot. To start with, let’s add the latest versions of spring-session-data-mongodb and spring-boot-starter-data-mongodb to our project:

首先,让我们看一下Spring Boot所需的依赖性和配置。首先,让我们把最新版本的spring-session-data-mongodbspring-boot-starter-data-mongodb添加到我们的项目。

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-mongodb</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

After that, to enable Spring Boot auto-configuration, we’ll need to add the Spring Session store-type as mongodb in the application.properties:

之后,为了启用Spring Boot自动配置,我们需要在application.properties中添加Spring Session存储类型为mongodb

spring.session.store-type=mongodb

3. Spring Configuration Without Spring Boot

3.没有Spring Boot的Spring配置

Now, let’s take a look at the dependencies and the configuration required to store the Spring session in MongoDB without Spring Boot.

现在,让我们来看看在没有Spring Boot的情况下将Spring会话存储在MongoDB中所需要的依赖性和配置。

Similar to the Spring Boot configuration, we’ll need the spring-session-data-mongodb dependency. However, here we’ll use the spring-data-mongodb dependency to access our MongoDB database:

与Spring Boot的配置类似,我们将需要spring-session-data-mongodb依赖。然而,在这里我们将使用spring-data-mongodb依赖项来访问我们的MongoDB数据库。

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-mongodb</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

Finally, let’s see how to configure the application:

最后,让我们看看如何配置该应用程序。

@EnableMongoHttpSession
public class HttpSessionConfig {

    @Bean
    public JdkMongoSessionConverter jdkMongoSessionConverter() {
        return new JdkMongoSessionConverter(Duration.ofMinutes(30));
    }
}

The @EnableMongoHttpSession annotation enables the configuration required to store the session data in MongoDB.

@EnableMongoHttpSessionannotation可启用将会话数据存储在MongoDB中所需的配置

Also, note that the JdkMongoSessionConverter is responsible for serializing and deserializing the session data.

另外,请注意,JdkMongoSessionConverter负责序列化和反序列化会话数据。

4. Example Application

4.应用实例

Let’s create an application to test the configurations. We’ll be using Spring Boot, as it’s faster and requires less configuration.

让我们创建一个应用程序来测试这些配置。我们将使用Spring Boot,因为它更快,需要的配置更少。

We’ll begin by creating the controller to handle requests:

我们将首先创建控制器来处理请求。

@RestController
public class SpringSessionMongoDBController {

    @GetMapping("/")
    public ResponseEntity<Integer> count(HttpSession session) {

        Integer counter = (Integer) session.getAttribute("count");

        if (counter == null) {
            counter = 1;
        } else {
            counter++;
        }

        session.setAttribute("count", counter);

        return ResponseEntity.ok(counter);
    }
}

As we can see in this example, we’re incrementing counter on every hit to the endpoint and storing its value in a session attribute named count.

正如我们在这个例子中看到的,我们在每次点击端点时都会增加counter,并将其值存储在一个名为count的会话属性中。

5. Testing the Application

5.测试应用程序

Let’s test the application to see if we’re actually able to store the session data in MongoDB.

让我们测试一下这个应用程序,看看我们是否真的能够在MongoDB中存储会话数据。

To do so, we’ll access the endpoint and inspect the cookie that we’ll receive. This will contain a session id.

要做到这一点,我们将访问端点并检查我们将收到的cookie。这将包含一个会话ID。

After that, we’ll query the MongoDB collection to fetch the session data using the session id:

之后,我们将查询MongoDB集合,使用会话ID来获取会话数据。

@Test
public void 
  givenEndpointIsCalledTwiceAndResponseIsReturned_whenMongoDBIsQueriedForCount_thenCountMustBeSame() {
    
    HttpEntity<String> response = restTemplate
      .exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class);
    HttpHeaders headers = response.getHeaders();
    String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE);

    Assert.assertEquals(response.getBody(),
      repository.findById(getSessionId(set_cookie)).getAttribute("count").toString());
}

private String getSessionId(String cookie) {
    return new String(Base64.getDecoder().decode(cookie.split(";")[0].split("=")[1]));
}

6. How Does It Work?

6.它是如何工作的?

Let’s take a look at what goes on in the Spring session behind the scenes.

让我们来看看Spring会议的幕后情况。

The SessionRepositoryFilter is responsible for most of the work:

SessionRepositoryFilter负责大部分的工作。

  • converts the HttpSession into a MongoSession
  • checks if there’s a Cookie present, and if so, loads the session data from the store
  • saves the updated session data in the store
  • checks the validity of the session

Also, the SessionRepositoryFilter creates a cookie with the name SESSION that is HttpOnly and secure. This cookie contains the session id, which is a Base64-encoded value.

另外,SessionRepositoryFilter创建了一个名为SESSION的cookie,它是HttpOnly和安全的。这个cookie包含会话ID,它是一个Base64编码的值。

To customize the cookie name or properties, we’ll have to create a Spring bean of type DefaultCookieSerializer.

为了自定义cookie的名称或属性,我们必须创建一个DefaultCookieSerializer.类型的Spring Bean。

For instance, here we’re disabling the httponly property of the cookie:

例如,在这里我们要禁用cookie的httponly属性。

@Bean
public DefaultCookieSerializer customCookieSerializer(){
    DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        
    cookieSerializer.setUseHttpOnlyCookie(false);
        
    return cookieSerializer;
}

7. Session Details Stored in MongoDB

7.存储在MongoDB中的会话细节

Let’s query our session collection using the following command in our MongoDB console:

让我们在MongoDB控制台使用以下命令查询我们的会话集合。

db.sessions.findOne()

As a result, we’ll get a BSON document similar to:

结果,我们将得到一个类似于BSON的文件。

{
    "_id" : "5d985be4-217c-472c-ae02-d6fca454662b",
    "created" : ISODate("2019-05-14T16:45:41.021Z"),
    "accessed" : ISODate("2019-05-14T17:18:59.118Z"),
    "interval" : "PT30M",
    "principal" : null,
    "expireAt" : ISODate("2019-05-14T17:48:59.118Z"),
    "attr" : BinData(0,"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAAFY291bnRzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAC3g=")
}

The _id is a UUID that will be Base64-encoded by the DefaultCookieSerializer and set as a value in the SESSION cookie. Also, note that the attr attribute contains the actual value of our counter.

_id是一个UID,它将被DefaultCookieSerializer进行Base64编码,并设置为SESSION cookie中的一个值。另外,请注意,attr属性包含我们的计数器的实际值。

8. Conclusion

8.结论

In this tutorial, we’ve explored Spring Session backed with MongoDB — a powerful tool for managing HTTP sessions in a distributed system. With this purpose in mind, it can be very useful in solving the problem of replicating sessions across multiple instances of the application.

在本教程中,我们已经探讨了Spring Session backed与MongoDB的关系–这是一个在分布式系统中管理HTTP会话的强大工具。考虑到这一目的,它在解决跨应用程序的多个实例复制会话的问题方面非常有用

As usual, the source code is available over on GitHub.

像往常一样,源代码可在GitHub上获得。