Shiro + Redis自定义session会话管理

原文博客地址

此图非常重要!!!镇楼

0x001 重写SessionManager

shiro提供了三种默认实现:

  • DefaultSessionManager: 用于java se 环境
  • ServletContainerSessionManager:默认使用的实现,Servlet容器管理
  • DefaultWebSessionManager:自己维护

重写SessionManager需要继承DefaultWebSessionManager

目的:自定义从header中的Authorization获取token

public class CustomSessionManager extends DefaultWebSessionManager {

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader("Authorization");
        if (StringUtils.isEmpty(id)) {
            // 获取sessionId,id可以自定义
            return super.getSessionId(request, response);
        } else {
            //返回sessionId;固定套路
            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 重写SessionDao

重写SessionDao 需要实现SessionDAO接口

继承以下子类也可以:

SessionDAO实现关系

继承AbstractSessionDAO,其实现了基础的实现

ps:

​ 注意!!!!!!!

扫描二维码关注公众号,回复: 9303871 查看本文章

一定要自己把session转换成二进制在用redistemplate存到redis 中,直接用redistemplate的对象序列化器,会出错误!!!!!

@Component
public class SelfSessionDao extends AbstractSessionDAO {

    @Resource(name = "SessionRedisTemplate")
    private RedisTemplate<Object, byte[]> redisTemplate;


    // 创建session 存到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);
    }

    /**
     * 更新
     * @param session
     * @throws UnknownSessionException
     */
    @Override
    public void update(Session session) throws UnknownSessionException {
        if (session == null || session.getId() == null) {
            throw new UnknownSessionException("session 或者 sessionId为空");
        }

        redisTemplate.boundValueOps(AppConstants.SHIRO_SESSION_REDIS_PREFIX + session.getId())
                .set(sessionToByte(session), AppConstants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
    }

    /**
     * 删除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;
        }
    }

    // 把session对象转化为byte保存到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;
    }

    // 把byte还原为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自定义id生成器

public class CustomSessionIdGenerator implements SessionIdGenerator {

    @Override
    public Serializable generateId(Session session) {
        //... 生成id逻辑
        return id;
    }
}

0x004 配置类

@Bean
    public SecurityManager getSecurityManager(CustomRealm realm,DefaultWebSessionManager defaultWebSessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);

        //将自定义的会话管理器注册到安全管理器中
        securityManager.setSessionManager(defaultWebSessionManager);
        //将自定义的redis缓存管理器注册到安全管理器中
        securityManager.setCacheManager(selfCacheManager());

        return securityManager;
    }
//会话管理器
@Bean
    public DefaultWebSessionManager sessionManager(SelfSessionDao selfSessionDao) {
        CustomSessionManager sessionManager = new CustomSessionManager();
        // 自定义sessionDAO
        sessionManager.setSessionDAO(selfSessionDao);
        // 自定义id生成器
		selfSessionDao.setSessionIdGenerator(new CustomSessionIdGenerator());
        return sessionManager;
    }
发布了7 篇原创文章 · 获赞 1 · 访问量 267

猜你喜欢

转载自blog.csdn.net/weixin_46235241/article/details/104108584