pring boot integrates redis to realize shiro's distributed session sharing

Keywords: Programming Session Shiro Redis Java

As we know, shiro manages sessions through Session manager, while Session operations are implemented through SessionDao. By default, shiro implements two kinds of SessionDao: cacheingsessiondao and MemorySessionDAO. When we use EhCache caching, we use cacheingsessiondao. When we do not use caching, we choose internal based caching Therefore, if we want to realize Redis based distributed Session sharing, the key is to rewrite the Session Dao in the Session manager. Our rewrite code is as follows:

package com.chhliu.springboot.shiro.cache;
 
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
 
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
 
@Service
@SuppressWarnings({ "rawtypes", "unchecked" })
public class RedisSessionDao extends AbstractSessionDAO {
 
	// Session timeout in milliseconds
	private long expireTime = 120000;
 
	@Autowired
	private RedisTemplate redisTemplate;// Redis operation class. For those unfamiliar with this, please refer to the previous blog
 
	public RedisSessionDao() {
		super();
	}
 
	public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {
		super();
		this.expireTime = expireTime;
		this.redisTemplate = redisTemplate;
	}
 
	@Override // Update session
	public void update(Session session) throws UnknownSessionException {
		System.out.println("===============update================");
		if (session == null || session.getId() == null) {
			return;
		}
		session.setTimeout(expireTime);
		redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);
	}
 
	@Override // Delete session
	public void delete(Session session) {
		System.out.println("===============delete================");
		if (null == session) {
			return;
		}
		redisTemplate.opsForValue().getOperations().delete(session.getId());
	}
 
	@Override// Get the active session, which can be used to count the number of people online. If you want to achieve this function, you can specify a session prefix when adding the session to redis, and use the keys ("session prefix *") method to fuzzy find all session combinations in redis
	public Collection<Session> getActiveSessions() {
		System.out.println("==============getActiveSessions=================");
		return redisTemplate.keys("*");
	}
 
	@Override// Join session
	protected Serializable doCreate(Session session) {
		System.out.println("===============doCreate================");
		Serializable sessionId = this.generateSessionId(session);
		this.assignSessionId(session, sessionId);
 
		redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);
		return sessionId;
	}
 
	@Override// Read session
	protected Session doReadSession(Serializable sessionId) {
		System.out.println("==============doReadSession=================");
		if (sessionId == null) {
			return null;
		}
		return (Session) redisTemplate.opsForValue().get(sessionId);
	}
 
	public long getExpireTime() {
		return expireTime;
	}
 
	public void setExpireTime(long expireTime) {
		this.expireTime = expireTime;
	}
 
	public RedisTemplate getRedisTemplate() {
		return redisTemplate;
	}
 
	public void setRedisTemplate(RedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}
}

After the implementation of SessionDao, we need to add SessionDao to the SessionManager. The code is as follows:

@Bean
	public DefaultWebSessionManager configWebSessionManager(){
		DefaultWebSessionManager manager = new DefaultWebSessionManager();
		manager.setCacheManager(cacheManager);// Join cache manager
		manager.setSessionDAO(sessionDao);// Set SessionDao
		manager.setDeleteInvalidSessions(true);// Delete expired session s
		manager.setGlobalSessionTimeout(sessionDao.getExpireTime());// Set global session timeout
		manager.setSessionValidationSchedulerEnabled(true);// Check session regularly
		
		return manager;
	}

The last step is to configure the session manager into the security manager


@Bean
	public SecurityManager securityManager(DefaultWebSessionManager webSessionManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// Set realm.
		securityManager.setRealm(myShiroRealm());
 
		// Injection cache manager;
		securityManager.setCacheManager(cacheManager);// If this is executed multiple times, it is the same object;
		
		// session manager
		securityManager.setSessionManager(webSessionManager);
		
		//Inject remember me manager;
	    securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}

The test results are as follows:

==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
===============update================
==============doReadSession=================
==============doReadSession=================
===============update================
==============doReadSession=================
==============doReadSession=================
==============doReadSession=================
Permission configuration -- > myshirorealm. Dogetauthorizationinfo()
==============doReadSession=================

We will find that when there are multiple resources in a page, we will constantly call the doReadSession and update methods to read and update the session. At present, we haven't come up with a better solution to this problem.

Posted by paschim on Fri, 01 Nov 2019 11:21:02 -0700