1. 会话管理
(1) 会话相关API
Shiro 提供了丰富的会话管理接口以支持与 Web 环境无关的会话操作。Session 和 Subject 是 Shiro 会话管理的核心接口
-
Session:代表用户的一次会话。
Session接口提供了基础会话操作,如获取或设置会话属性、会话ID、超时时间等。其中的核心方法包括:getId(): 获取会话的唯一标识符getAttribute(Object key): 获取会话属性,用于存储用户或会话相关数据setAttribute(Object key, Object value): 设置会话属性removeAttribute(Object key): 删除指定的会话属性getTimeout() / setTimeout(long): 获取或设置会话超时时间,通常以毫秒为单位stop(): 终止会话,通常在用户注销或会话超时时调用
-
Subject:表示当前操作的用户或系统实体。
Subject的getSession()方法可以获取当前用户的会话,支持自动创建或获取已有会话。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 提供了多种加密方式,如 Md5Hash、Sha256Hash 等,常用于用户密码的加密存储。为了提高安全性,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("账户已锁定,请稍后重试");
}
620

被折叠的 条评论
为什么被折叠?



