GitHub_Trending/sp/spring-reading安全框架:Shiro与Spring集成
1. 安全框架选型痛点与解决方案
你是否正面临Spring应用权限管理的以下困境:
- 手写拦截器实现认证逻辑导致代码冗余
- 权限控制散落在业务代码中难以维护
- 缺乏统一的会话管理和加密策略
Apache Shiro(四郎)作为轻量级安全框架,提供认证(Authentication)、授权(Authorization)、会话管理(Session Management) 和加密(Cryptography) 四大核心功能,与Spring框架的无缝集成可完美解决上述问题。本文将从环境配置、核心组件、实战案例到性能优化,系统化讲解Shiro与Spring的集成方案。
2. 环境准备与依赖配置
2.1 必要依赖坐标
<!-- Shiro核心依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.12.0</version>
</dependency>
<!-- Spring集成模块 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.12.0</version>
</dependency>
<!-- 缓存支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.12.0</version>
</dependency>
2.2 项目结构规范
src/main/java
├── com/example/security
│ ├── config/ # Shiro配置类
│ │ ├── ShiroConfig.java
│ │ └── CustomRealm.java
│ ├── controller/ # 受保护资源
│ └── service/ # 业务逻辑层
src/main/resources
├── shiro.ini # 传统配置方式(可选)
└── spring-shiro.xml # Spring整合配置
3. 核心组件与工作原理
3.1 Shiro架构流程图
3.2 核心组件说明
组件名称 | 作用 | 常见实现类 |
---|---|---|
Subject | 代表当前用户 | org.apache.shiro.subject.Subject |
SecurityManager | 安全核心管理器 | org.apache.shiro.web.mgt.DefaultWebSecurityManager |
Realm | 数据源连接器 | org.apache.shiro.realm.AuthorizingRealm |
FilterChain | URL拦截过滤器 | org.apache.shiro.web.filter.mgt.DefaultFilterChainManager |
SessionDAO | 会话持久化 | org.apache.shiro.session.mgt.eis.MemorySessionDAO |
4. 详细集成步骤
4.1 自定义Realm实现
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 查询用户角色
Set<String> roles = userService.queryRolesByUsername(username);
info.setRoles(roles);
// 查询用户权限
Set<String> permissions = userService.queryPermissionsByUsername(username);
info.setStringPermissions(permissions);
return info;
}
// 认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.queryByUsername(username);
if (user == null) {
throw new UnknownAccountException("用户不存在");
}
return new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName()
);
}
}
4.2 Spring配置类
@Configuration
public class ShiroConfig {
// 1. 创建Realm
@Bean
public CustomRealm customRealm() {
CustomRealm realm = new CustomRealm();
// 配置加密算法
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1024);
realm.setCredentialsMatcher(matcher);
return realm;
}
// 2. 创建SecurityManager
@Bean
public SecurityManager securityManager(CustomRealm realm) {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(realm);
// 配置会话管理器
manager.setSessionManager(sessionManager());
// 配置缓存管理器
manager.setCacheManager(cacheManager());
return manager;
}
// 3. 配置Shiro过滤器
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
factory.setSecurityManager(securityManager);
// 配置URL拦截规则
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/login", "anon"); // 登录页匿名访问
filterMap.put("/css/**", "anon"); // 静态资源匿名访问
filterMap.put("/admin/**", "roles[ADMIN]");// 管理员角色访问
filterMap.put("/user/**", "perms[user:view]");// 用户权限访问
filterMap.put("/**", "authc"); // 其他路径需认证
factory.setFilterChainDefinitionMap(filterMap);
factory.setLoginUrl("/login"); // 未认证跳转页
factory.setUnauthorizedUrl("/unauth"); // 未授权跳转页
return factory;
}
// 4. 配置会话管理器
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(3600000); // 1小时超时
sessionManager.setSessionDAO(new MemorySessionDAO());
return sessionManager;
}
// 5. 配置缓存管理器
@Bean
public CacheManager cacheManager() {
return new MemoryConstrainedCacheManager();
}
}
4.3 登录控制器实现
@Controller
public class LoginController {
@PostMapping("/login")
public String login(String username, String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
return "redirect:/index";
} catch (UnknownAccountException e) {
model.addAttribute("error", "用户名不存在");
return "login";
} catch (IncorrectCredentialsException e) {
model.addAttribute("error", "密码错误");
return "login";
}
}
@GetMapping("/unauth")
@ResponseBody
public ResultVO unauth() {
return ResultVO.fail(403, "没有访问权限");
}
}
5. 高级特性配置
5.1 会话共享(分布式场景)
<!-- 配置Redis会话DAO -->
<bean id="redisSessionDAO" class="org.crazycake.shiro.RedisSessionDAO">
<property name="redisManager" ref="redisManager"/>
</bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionDAO" ref="redisSessionDAO"/>
</bean>
5.2 记住我功能
// 在ShiroFilterFactoryBean中添加
factory.setRememberMeParam("rememberMe");
factory.setSuccessUrl("/index");
// 登录时设置记住我
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
subject.login(token);
6. 常见问题解决方案
问题场景 | 解决方案 | 代码示例 |
---|---|---|
密码加密存储 | 使用HashedCredentialsMatcher | matcher.setHashAlgorithmName("MD5") |
权限动态更新 | 调用realm.clearCache() | SecurityUtils.getSubject().getSession().stop() |
单点登录集成 | 集成CAS客户端 | casFilter.setServerUrlPrefix("https://cas.example.com/cas") |
跨域请求处理 | 自定义CORS过滤器 | 实现javax.servlet.Filter接口处理OPTIONS请求 |
7. 性能优化策略
-
缓存优化:使用Ehcache替代内存缓存
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> </bean>
-
会话优化:设置合理的超时时间和清理策略
sessionManager.setSessionValidationInterval(1800000); // 30分钟验证一次 sessionManager.setSessionValidationSchedulerEnabled(true);
-
SQL优化:权限查询使用批量操作
-- 批量查询用户角色 SELECT r.role_code FROM sys_user_role ur LEFT JOIN sys_role r ON ur.role_id = r.id WHERE ur.user_id = #{userId}
8. 与Spring Security对比分析
特性 | Shiro | Spring Security |
---|---|---|
上手难度 | 简单 | 复杂 |
配置方式 | XML/JavaConfig | JavaConfig为主 |
OAuth集成 | 需扩展 | 原生支持 |
密码加密 | 内置多种算法 | 需自定义 |
社区支持 | 中等 | 活跃 |
9. 总结与未来展望
通过本文的系统化讲解,你已掌握Shiro与Spring集成的完整流程,包括:
- 环境搭建与依赖配置
- 核心组件的实现原理
- 认证授权的代码实现
- 高级特性与性能优化
建议后续深入学习:
- Shiro的分布式会话解决方案
- 基于JWT的无状态认证改造
- 安全审计日志与异常监控
收藏本文,关注项目更新,获取更多Spring生态实战指南!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考