深入解析:Spring Boot与Apache Shiro的无缝集成实践
1. 添加依赖
在Spring Boot项目中,依赖管理是通过pom.xml
文件完成的。为了将Apache Shiro集成到项目中,我们需要引入Shiro的核心依赖以及Spring Boot的整合依赖。同时,为了支持Web功能,我们还需要引入Spring Boot Web模块的依赖。以下是完整的依赖配置:
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Apache Shiro Spring Boot Starter -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.10.0</version> <!-- 请根据项目需求选择合适的版本 -->
</dependency>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
这段配置为项目引入了Spring Boot的核心功能、Shiro的安全管理能力以及Web开发所需的支持。通过这种方式,我们可以确保项目在启动时自动加载Shiro的相关组件,并与Spring Boot的生命周期无缝集成。这不仅简化了配置过程,还提高了系统的整体性能和可维护性。
2. 配置Shiro
在Spring Boot中,配置类是通过@Configuration
注解定义的。我们需要创建一个ShiroConfig
类,用于配置Shiro的核心组件,包括ShiroFilterFactoryBean
和DefaultWebSecurityManager
。这些组件将负责管理Shiro的过滤器链、安全策略以及与自定义Realm的交互。
以下是ShiroConfig
类的完整代码:
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean,用于定义Shiro的过滤器链。
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
// 定义拦截规则
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon"); // 登录页面无需认证
filterChainDefinitionMap.put("/register", "anon"); // 注册页面无需认证
filterChainDefinitionMap.put("/logout", "logout"); // 退出登录
filterChainDefinitionMap.put("/**", "authc"); // 其他页面需要认证
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
bean.setLoginUrl("/login"); // 设置登录页面
bean.setSuccessUrl("/home"); // 设置登录成功后的跳转页面
bean.setUnauthorizedUrl("/403"); // 设置未授权页面
return bean;
}
/**
* 创建DefaultWebSecurityManager,用于管理Shiro的安全策略。
*/
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm()); // 设置自定义Realm
return securityManager;
}
/**
* 创建自定义Realm,用于连接用户数据源。
*/
@Bean
public MyRealm myRealm() {
return new MyRealm();
}
}
在上述配置中,ShiroFilterFactoryBean
定义了Shiro的过滤器链,通过filterChainDefinitionMap
配置了哪些路径需要认证,哪些路径可以匿名访问。DefaultWebSecurityManager
则负责管理Shiro的安全策略,并通过setRealm
方法与自定义的MyRealm
类进行关联。这种分层的配置方式不仅清晰明了,还便于后续的扩展和维护。
3. 创建自定义Realm
Realm是Shiro的核心接口,用于连接用户数据源(如数据库)。在Shiro中,Realm的作用是提供用户信息、角色和权限数据。为了实现自定义的认证和授权逻辑,我们需要创建一个MyRealm
类,继承自AuthorizingRealm
。
以下是MyRealm
类的完整代码:
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class MyRealm extends AuthorizingRealm {
/**
* 授权逻辑,用于获取用户的角色和权限。
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = principals.getPrimaryPrincipal().toString();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 模拟从数据库中获取用户角色和权限
if ("admin".equals(username)) {
info.addRole("admin");
info.addStringPermission("user:create");
info.addStringPermission("user:delete");
} else if ("user".equals(username)) {
info.addRole("user");
info.addStringPermission("user:view");
}
return info;
}
/**
* 认证逻辑,用于验证用户身份。
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = token.getPrincipal().toString();
String password = new String((char[]) token.getCredentials()); // 获取用户输入的密码
// 模拟从数据库中获取用户信息
if (!"admin".equals(username) && !"user".equals(username)) {
throw new UnknownAccountException("用户名不存在");
}
if (!"123".equals(password)) {
throw new IncorrectCredentialsException("密码错误");
}
return new SimpleAuthenticationInfo(username, password, getName());
}
}
在MyRealm
类中,doGetAuthorizationInfo
方法用于实现授权逻辑,通过PrincipalCollection
获取当前用户的用户名,并根据用户名模拟从数据库中获取用户的角色和权限。doGetAuthenticationInfo
方法则用于实现认证逻辑,通过AuthenticationToken
获取用户输入的用户名和密码,并进行验证。这种分层的实现方式不仅符合面向对象的设计原则,还便于后续的扩展和维护。
4. 创建Controller
为了测试Shiro的认证和授权功能,我们需要创建一个简单的ShiroController
类。通过这个Controller,我们可以模拟用户登录、访问受保护的资源以及退出登录的场景。
以下是ShiroController
类的完整代码:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.*;
@RestController
public class ShiroController {
/**
* 模拟用户登录接口。
*/
@GetMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
return "登录成功!欢迎 " + username;
} catch (Exception e) {
return "登录失败:" + e.getMessage();
}
}
/**
* 模拟用户访问主页接口。
*/
@GetMapping("/home")
public String home() {
return "欢迎来到主页!";
}
/**
* 模拟用户退出登录接口。
*/
@GetMapping("/logout")
public String logout() {
SecurityUtils.getSubject().logout();
return "退出成功!";
}
/**
* 模拟用户访问未授权资源时的接口。
*/
@GetMapping("/403")
public String unauthorized() {
return "您没有权限访问该页面!";
}
}
在ShiroController
类中,/login
接口用于模拟用户登录操作,通过SecurityUtils.getSubject()
获取当前用户主体,并调用login
方法进行登录。/home
接口用于模拟用户访问受保护的资源,/logout
接口用于模拟用户退出登录,/403
接口则用于模拟用户访问未授权资源时的场景。这种设计不仅清晰明了,还便于后续的扩展和维护。
5. 启动项目并测试
完成上述配置后,启动Spring Boot项目。通过访问/login
接口,可以模拟用户登录操作。登录成功后,用户可以访问/home
页面,而未登录的用户将被重定向到登录页面。此外,通过访问/logout
接口,用户可以退出登录。
注意事项
- 版本兼容性:在选择Shiro版本时,务必确保其与Spring Boot版本兼容,以避免潜在的兼容性问题。建议在项目启动前进行版本兼容性测试,确保系统的稳定性和可靠性。
- 数据库集成:在实际项目中,用户信息和权限数据通常存储在数据库中。可以通过Spring Data JPA或MyBatis等框架实现与数据库的交互,并在自定义Realm中加载用户数据。这种设计不仅提高了系统的灵活性,还便于后续的扩展和维护。
- 自定义过滤器:根据项目需求,可以自定义Shiro的过滤器,例如实现验证码登录、记住我功能或自定义登录逻辑。通过自定义过滤器,可以进一步提升系统的安全性和用户体验。
- 安全性:在生产环境中,密码应通过加密方式存储和验证,避免明文存储密码。可以使用Shiro提供的
HashedCredentialsMatcher
来实现密码的加密验证。此外,建议定期对系统进行安全审计,确保系统的安全性。 - 日志记录:建议在认证和授权逻辑中添加日志记录,以便在出现问题时能够快速定位和排查。通过日志记录,可以更好地监控系统的运行状态,及时发现潜在的安全问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具