Shiro 会话管理和加密

1. 会话管理

(1) 会话相关API

Shiro 提供了丰富的会话管理接口以支持与 Web 环境无关的会话操作。SessionSubject 是 Shiro 会话管理的核心接口

  • Session:代表用户的一次会话。Session 接口提供了基础会话操作,如获取或设置会话属性、会话ID、超时时间等。其中的核心方法包括:

    • getId(): 获取会话的唯一标识符
    • getAttribute(Object key): 获取会话属性,用于存储用户或会话相关数据
    • setAttribute(Object key, Object value): 设置会话属性
    • removeAttribute(Object key): 删除指定的会话属性
    • getTimeout() / setTimeout(long): 获取或设置会话超时时间,通常以毫秒为单位
    • stop(): 终止会话,通常在用户注销或会话超时时调用
  • Subject:表示当前操作的用户或系统实体。SubjectgetSession() 方法可以获取当前用户的会话,支持自动创建或获取已有会话。Subject.getSession(true) 会在没有会话时自动创建新会话,而 Subject.getSession(false) 则只获取已有会话,不会创建新会话

(2) SessionDAO

在 Shiro 中,SessionDAO 负责会话的持久化与读取,它支持将会话信息存储到不同介质中(如内存、数据库、文件或分布式缓存)。Shiro 默认实现了多个 SessionDAO,常用的包括:

  • MemorySessionDAO:将会话存储在内存中,适合小规模应用,但不适合分布式环境
  • EnterpriseCacheSessionDAO:结合缓存管理器,将会话存储在缓存中,支持更高的性能和扩展性
  • 自定义 SessionDAO:可以实现分布式存储支持(如 Redis、MySQL),在分布式环境中使用较多

SessionDAO 的核心方法包括:

  • create(Session session): 创建会话,并将其持久化
  • readSession(Serializable sessionId): 根据会话ID读取会话信息
  • update(Session session): 更新会话信息(如更新超时时间或会话属性)
  • delete(Session session): 删除会话,通常在会话超时或用户注销时调用
(3) 会话使用

在实际应用中,Shiro 会话管理可以灵活使用:

  • 分布式会话:在多节点应用中,通常使用 Redis、Memcached 等分布式缓存来实现会话共享Shiro 的 RedisSessionDAO 通过将会话信息存储到 Redis,以保证会话在多节点之间共享
  • 会话超时:通过 session.setTimeout(long timeout) 设置会话超时时间(单位为毫秒),当会话达到设定时间未活动时会自动失效
  • 会话事件监听:Shiro 支持会话监听器(SessionListener),可以在会话创建、销毁、超时时执行自定义操作,如记录日志或发送通知
RedisSessionDAO sessionDAO = new RedisSessionDAO(); 
sessionDAO.setRedisManager(redisManager); // 设置 Redis 连接信息 
securityManager.setSessionDAO(sessionDAO);

2. 缓存

(1) 问题分析

在高并发系统中,频繁的数据查询会显著增加系统负载。例如,Shiro 在会话验证权限检查等场景下频繁访问用户或权限数据,容易造成数据库压力增大,从而影响系统性能

(2) 解决办法

Shiro 通过 CacheManager 进行缓存管理,可以整合第三方缓存系统(如 EhCache、Redis)。利用缓存可以有效减少对数据库的访问次数,提高系统响应速度。Shiro 的 CacheManager 支持缓存用户会话、认证信息、权限数据等。常见的缓存实现包括:

  • EhCacheManager:基于 EhCache 的内存缓存,适合小型应用,支持本地缓存。
  • RedisCacheManager:基于 Redis 的分布式缓存管理,适合大型分布式应用,支持缓存共享。
  • 自定义 CacheManager:可根据需求自定义缓存实现,支持灵活扩展。
(3) 具体实现

可以通过 XML 或 Java 配置将缓存管理器引入 Shiro,配置方法如下:

EhCache 配置

EhCacheManager cacheManager = new EhCacheManager(); 
cacheManager.setCacheManagerConfigFile("classpath:缓存配置文件名.xml"); 
securityManager.setCacheManager(cacheManager);

Redis 配置示例

RedisCacheManager redisCacheManager = new RedisCacheManager(); 
redisCacheManager.setRedisManager(redisManager); 
securityManager.setCacheManager(redisCacheManager);

3. 加密

(1) 哈希与盐

Shiro 提供了多种加密方式,如 Md5HashSha256Hash 等,常用于用户密码的加密存储。为了提高安全性,Shiro 支持加盐(Salt)机制,即在明文密码基础上加一段随机字符串(盐),再进行哈希运算

使用加盐的好处:

  • 避免相同密码生成相同的加密结果
  • 防止彩虹表攻击(利用预计算的哈希值破解密码)

使用 Shiro 的 Sha256Hash 进行加密:

String salt = "随机生成的盐"; 
String hashedPassword = new Sha256Hash(plainTextPassword, salt, 1024).toHex();

以上代码将 plainTextPassword 加盐并哈希,迭代 1024 次以增加破解难度

(2) 加密与验证

在验证用户登录时,Shiro 可以将用户输入的密码进行相同的加密操作,然后与数据库中的加密结果进行比较

SimpleHash 类使加密验证流程更加简洁

String salt = "数据库中存储的盐值"; String inputHashedPassword = new SimpleHash("SHA-256", plainTextPassword, salt, 1024).toHex(); 
if(inputHashedPassword.equals(storedHashedPassword)) { 
    // 验证成功 
} else { 
    // 验证失败 
}

4. 登录次数限制

Shiro 通过缓存和拦截机制可以实现登录次数限制,防止暴力破解或非法访问。实现方式通常如下:

  • 缓存登录失败次数:通过缓存来记录每个用户的失败次数
  • 拦截登录请求:在用户登录时检查缓存中的失败次数,若达到设定的限制次数,暂时锁定账户或限制登录
// 获取失败次数 
Integer failedAttempts = (Integer) cacheManager.getCache("loginAttempts").get(username);
failedAttempts = (failedAttempts == null) ? 1 : failedAttempts + 1; 
cacheManager.getCache("loginAttempts").put(username, failedAttempts); 
if (failedAttempts >= MAX_ATTEMPTS) { 
    // 锁定账户或发送警告信息 throw new ExcessiveAttemptsException("账户已锁定,请稍后重试");
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值