spring-redis-session custom key and expiration date

For distributed applications, the problem encountered is the beginning of a session of storage, there are several solutions roughly

  • Use spring-session it can be stored in a session where you want to store, such as redis, mysql, etc.
  • Use JWTs, it uses an algorithm to verify the legitimacy of the token, has expired, and the token can not be forged, information also can not be tampered with

This paper mainly said spring-session redis use to store session, implementation principle, modify the expiration time, and other custom key

spring-session for internal systems or can be, easy to use, but if the amount of users will come up, then, will have a great session redis storage overhead, not cost-effective.

use

Simple to use, easy to talk about, the lead pack, configure, add annotations. Such as the following three steps, we configured the use redis-session

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
spring.redis.host=localhost  
# 其它 超时,端口,库,连接池,集群,就自己去找了
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 1800)

Test: Because it is not created when getSession Session, so we have to call in an interface once to see results

@GetMapping("/sessionId")
public String sessionId(){
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    HttpSession session = request.getSession();
    session.setAttribute("user","sanri");
    return session.getId();
}

It stores the following results

hash spring:session:sessions:e3d4d84f-cc9f-44d5-9199-463cd9de8272
string spring:session:sessions:expires:e3d4d84f-cc9f-44d5-9199-463cd9de8272
set spring:session:expirations:1577615340000

A first structure for storing a hash of some attribute information of the session and some basic information set by the user

creationTime Created

lastAccessedTime last access time

Expires long maxInactiveInterval, default is 30 minutes, where the stored second value

sessionAttr: user this is my set to go through session.setAttribute property

The second string structure, it has no value, only a ttl information, identify this group of key still long to live, can be viewed using ttl

The third set structure, so it is necessary to save the expired key

The principle

Description: This is not much more difficult to achieve, I did as the source read it, is a filter application only.

First learned from the Internet, it uses filters to achieve the session is stored in redis, and each request is to get the session from redis, so the goal is to see it filter which is how to store, but also how it is acquired.

We can see from its only entrance @EnableRedisHttpSessioninto the view, it introduces a RedisHttpSessionConfigurationturn on a timer, inherited from SpringHttpSessionConfiguration, you can note RedisHttpSessionConfigurationcreate a Bean RedisOperationsSessionRepositoryRepository is a repository of meaning, so it is a core class for storing session; that filter where is it to see SpringHttpSessionConfigurationthat it belongs to the spring-session-core package, which is used to manage a spring session of the pack, is an abstract concept, concrete implementation done by the spring-session-data-redis, it certainly filter created here, and she can see it create a SessionRepositoryFilterfilter, the following were seen filter and stored.

SessionRepositoryFilter

Filters must be some method doFilter view doFilter method, spring using OncePerRequestFilterthe doFilter a layer of packaging, ultimately calling doFilterInternal to achieve, to view doFilterInternal method

Implementation is used to design the packaging request and response response was packed, we generally take the session generally from request.getSession (), so the request package will certainly be rewritten getSession, so you can see how the view from getSession method redis get session;

Judgment in front of all of the relevant existing session, key information here

S session = SessionRepositoryFilter.this.sessionRepository.createSession();

SessionRepository here is what we use to access the session RedisOperationsSessionRepositoryto view method createSession

RedisOperationsSessionRepository

// 这里保存了在 redis 中 hash 结构能看到的数据
RedisSession redisSession = new RedisSession();

this(new MapSession());
this.delta.put(CREATION_TIME_ATTR, getCreationTime().toEpochMilli());
this.delta.put(MAX_INACTIVE_ATTR, (int) getMaxInactiveInterval().getSeconds());
this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime().toEpochMilli());
this.isNew = true;
this.flushImmediateIfNecessary();

In flushImmediateIfNecessary method, if redisFlushMode is a IMMEDIATEpattern, it will immediately save session into redis, but the default configuration is ON_SAVE, where it is stored into the redis it, we return to the filter method doFilterInternal the beginning, when finally in there are a

wrappedRequest.commitSession();

It was here that the session is stored into the redis, we go in and see with the core statement sentence

SessionRepositoryFilter.this.sessionRepository.save(session);
session.saveDelta();
if (session.isNew()) {
    String sessionCreatedKey = getSessionCreatedChannel(session.getId());
    this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
    session.setNew(false);
}

Entering saveDelta, here on a set of hash structure

getSessionBoundHashOperations(sessionId).putAll(this.delta);

The last line was set expiration time and join the current key set, the reader to view

RedisOperationsSessionRepository.this.expirationPolicy
                    .onExpirationUpdated(originalExpiration, this);

Modify some parameters

The actual business, you may need to modify some parameters in order to achieve the needs of our business, the most common requirement is to modify the expiration time of the session, the EnableRedisHttpSessionnotes have been provided some basic configuration such as

maxInactiveIntervalInSeconds 最大过期时间,默认 30 分钟 
redisNamespace 插入到 redis 的 session 命名空间,默认是 spring:session 
cleanupCron 过期 session 清理任务,默认是 1 分钟清理一次
redisFlushMode 刷新方式 ,其实在上面原理的 flushImmediateIfNecessary 方法中有用到,默认是 ON_SAVE

redisNamespace is sure to be modified, the changes will not affect other projects, the general use of the name of our projects do add keywords session key, session information indicates that this is the project.

However, such a configuration was not enough, the maximum expiration time, there may need added to the configuration file, instead of writing code, but there is no function provides placeholders, back to RedisOperationsSessionRepositorycreation, the final configuration of maxInactiveIntervalInSeconds to set or to go into this bean, we can cover the process of creating this bean, rewrite maxInactiveIntervalInSeconds the acquisition process will be solved, as follows

@Autowired
RedisTemplate sessionRedisTemplate;

@Autowired
ApplicationEventPublisher applicationEventPublisher;

@Value("${server.session.timeout}")
private int sessionTimeout = 1800;

@Primary        // 使用 Primary 来覆盖默认的 Bean 
@Bean
public RedisOperationsSessionRepository sessionRepository() {
    RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
    // 这里要把原来的属性引用过来,避免出错 ,可以引用原来的类并复制属性 ;像 redisNamespace,redisFlushMode 都要复制过来
    return sessionRepository;
}

There is a sequence of problems redis, the default is to use the jdk object serialization, it is prone to add a field or a field that appears not to reduce deserialization, so serialization is required to change the cache if the project it has been used for object serialization, then it faces you want to write a single redisTemplate and set to go in building a RedisOperationsSessionRepositoryset time redisTemplate

Another is generated in the key values ​​are redis uuid form, there is no way to know that the current key which is where the user logs in, we can actually modify its key form of userId_ip_time, to indicate what the user the time at which ip have logged in before, so I was playing (not used in practice, although they would change, but there may pit):

After the previous source code analysis, create session and saved to redis is RedisOperationsSessionRepositorythe createSession method, but the writing here is dead construction RedisSession empty, but RedisSession is the final inner classes, access to the default, when the construction of new MapSession also the default and finally the id to use UUID, seems nothing can be done, in fact, here you have created session, the user is not necessarily the state of the login is successful, we should modify key session in order to log in successfully, but fortunately RedisOperationsSessionRepositoryprovides a method findById, we can make a fuss in the above, first RedisSession check out, and then get a reflection MapSession, then noticed MapSessioncan be modified id, which itself also provides a method changeSessionId, we can successfully call setId modify sessionId login, then write back, and RedisSession this code must be in the same package code is as follows:

package org.springframework.session.data.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.MapSession;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;

@Component
public class SessionOperation {
    @Autowired
    private RedisOperationsSessionRepository redisOperationsSessionRepository;

    public void loginSuccess(String userId){
        String sessionId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession().getId();
        RedisOperationsSessionRepository.RedisSession redisSession = redisOperationsSessionRepository.findById(sessionId);
        Field cached = ReflectionUtils.findField(RedisOperationsSessionRepository.RedisSession.class, "cached");
        ReflectionUtils.makeAccessible(cached);
        MapSession mapSession = (MapSession) ReflectionUtils.getField(cached, redisSession);
        mapSession.setId("userId:1");
        redisOperationsSessionRepository.save(redisSession);
    }
}

Source Address: https://gitee.com/sanri/example/tree/master/test-redis-session

Little promotion

Writing is not easy, I hope the support of open source software, and my gadgets, welcome to gitee point star, fork, put bug.

Excel common import and export, support Excel formulas
blog address: https://blog.csdn.net/sanri1993/article/details/100601578
gitee: https://gitee.com/sanri/sanri-excel-poi

Use the template code, the gadget generate code from the database, and some projects can often be used in the
blog address: https://blog.csdn.net/sanri1993/article/details/98664034
gitee: https://gitee.com/ sanri / sanri-tools-maven

Guess you like

Origin www.cnblogs.com/sanri1993/p/12116996.html