This picture is very important!!! Town building
0x001 override SessionManager
shiro provides three default implementations:
- DefaultSessionManager: for java se environment
- ServletContainerSessionManager: implementation used by default, Servlet container management
- DefaultWebSessionManager: self maintenance
Overriding SessionManager requires inheriting the DefaultWebSessionManager class
Purpose: get token from Authorization in header
public class CustomSessionManager extends DefaultWebSessionManager { @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response) { String id = WebUtils.toHttp(request).getHeader("Authorization"); if (StringUtils.isEmpty(id)) { // Get sessionId, id can be customized return super.getSessionId(request, response); } else { //Return sessionId; fixed routine request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "header"); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return id; } } }
0x002 rewrite SessionDao
Overriding SessionDAO requires implementing the SessionDAO interface
You can also inherit the following subclasses:
Inherits AbstractSessionDAO and implements the basic implementation
ps:
Attention!!!!!!!
Be sure to convert the session to binary and save it in redis with redistemplate. If you directly use the object serializer of redistemplate, there will be an error!!!!!
@Component public class SelfSessionDao extends AbstractSessionDAO { @Resource(name = "SessionRedisTemplate") private RedisTemplate<Object, byte[]> redisTemplate; // Create session and save to redis @Override protected Serializable doCreate(Session session) { Serializable sessionId = generateSessionId(session); assignSessionId(session, sessionId); redisTemplate.boundValueOps(AppConstants.SHIRO_SESSION_REDIS_PREFIX + sessionId) .set(sessionToByte(session), AppConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { byte[] bytes = redisTemplate.boundValueOps(AppConstants.SHIRO_SESSION_REDIS_PREFIX + sessionId).get(); return byteToSession(bytes); } /** * To update * @param session * @throws UnknownSessionException */ @Override public void update(Session session) throws UnknownSessionException { if (session == null || session.getId() == null) { throw new UnknownSessionException("session perhaps sessionId Empty"); } redisTemplate.boundValueOps(AppConstants.SHIRO_SESSION_REDIS_PREFIX + session.getId()) .set(sessionToByte(session), AppConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS); } /** * Delete session * @param session */ @Override public void delete(Session session) { redisTemplate.delete(AppConstants.SHIRO_SESSION_REDIS_PREFIX + session.getId()); } @Override public Collection<Session> getActiveSessions() { Set<Object> keys = redisTemplate.keys(AppConstants.SHIRO_SESSION_REDIS_PREFIX + "*"); if (keys != null) { return keys.stream().map(key -> { byte[] bytes = redisTemplate.boundValueOps(key).get(); return byteToSession(bytes); }).collect(Collectors.toList()); } else { return null; } } // Convert session object to byte and save it in redis public byte[] sessionToByte(Session session){ ByteArrayOutputStream bo = new ByteArrayOutputStream(); byte[] bytes = null; try { ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(session); bytes = bo.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return bytes; } // Restore byte to session public Session byteToSession(byte[] bytes){ ByteArrayInputStream bi = new ByteArrayInputStream(bytes); ObjectInputStream in; SimpleSession session = null; try { in = new ObjectInputStream(bi); session = (SimpleSession) in.readObject(); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return session; } }
0x003 custom id generator
public class CustomSessionIdGenerator implements SessionIdGenerator { @Override public Serializable generateId(Session session) { //... generate id logic return id; } }
0x004 configuration class
@Bean public SecurityManager getSecurityManager(CustomRealm realm,DefaultWebSessionManager defaultWebSessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(realm); //Register a custom session manager with the Security Manager securityManager.setSessionManager(defaultWebSessionManager); //Register the customized redis cache manager to the Security Manager securityManager.setCacheManager(selfCacheManager()); return securityManager; } //Session manager @Bean public DefaultWebSessionManager sessionManager(SelfSessionDao selfSessionDao) { CustomSessionManager sessionManager = new CustomSessionManager(); // Custom sessionDAO sessionManager.setSessionDAO(selfSessionDao); // Custom id generator selfSessionDao.setSessionIdGenerator(new CustomSessionIdGenerator()); return sessionManager; }