You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring+Shiro+Redis项目运行报[B cannot be cast to org.apache.shiro.session.Session错误

异常触发原因

[B 在Java中是byte[]类型的标识,该异常是Shiro会话定时校验线程从Redis获取会话数据时,拿到了未反序列化的字节数组,直接尝试强转为org.apache.shiro.session.Session对象导致的,常见触发场景如下:

  • 自定义实现的RedisSessionDAO逻辑缺失:getActiveSessions、doGetSession等读取会话的方法,没有对Redis返回的字节数据做反序列化处理,直接返回原始字节数组
  • Redis键扫描范围错误:getActiveSessions方法扫描Redis键时没有过滤Shiro会话专属前缀,拿到了其他业务存储的字节类型数据
  • 序列化/反序列化配置不兼容:存储会话时用的序列化器和读取时用的序列化器不一致,导致反序列化失败直接返回了原始字节数组
修复方案

1. 完善RedisSessionDAO的序列化逻辑

统一使用Shiro配套的序列化器(比如DefaultSerializer)处理会话的读写,所有从Redis读取的字节数据必须先反序列化为Session对象再返回给Shiro框架,示例逻辑如下:

// 序列化器初始化
private DefaultSerializer<Session> serializer = new DefaultSerializer<>();
private static final String SESSION_KEY_PREFIX = "shiro:session:";

@Override
protected Session doReadSession(Serializable sessionId) {
    byte[] bytes = redisTemplate.opsForValue().get(SESSION_KEY_PREFIX + sessionId);
    if (bytes == null) {
        return null;
    }
    // 必须做反序列化后再返回
    return serializer.deserialize(bytes);
}

@Override
public Collection<Session> getActiveSessions() {
    Set<String> keys = redisTemplate.keys(SESSION_KEY_PREFIX + "*");
    List<Session> sessions = new ArrayList<>();
    if (keys == null || keys.isEmpty()) {
        return sessions;
    }
    for (String key : keys) {
        byte[] bytes = redisTemplate.opsForValue().get(key);
        // 反序列化后再加入集合
        sessions.add(serializer.deserialize(bytes));
    }
    return sessions;
}

2. 增加Redis键前缀过滤

给Shiro会话存储的键增加统一专属前缀,比如上文示例的shiro:session:,扫描活跃会话时仅匹配带该前缀的键,避免获取到其他业务的非会话数据。

3. 可选:关闭会话定时校验

如果业务不需要Shiro自动清理过期会话,可以直接在SessionManager配置中关闭定时校验任务,从触发路径上规避该问题:

DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
// 关闭会话验证调度器
sessionManager.setSessionValidationSchedulerEnabled(false);

内容的提问来源于stack exchange,提问作者Enoch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 03:12:03