咨询:如何在Spring Boot+MySQL的Petclinic项目中集成Apache Shiro
Spring Boot PetClinic + Apache Shiro 集成入门指南
Hey there! I’ve worked through integrating Shiro with Spring Boot projects before, so let me walk you through a practical, no-nonsense starting plan tailored for the PetClinic app. Let’s break this down step by step:
1. 先添加Shiro依赖
首先给项目引入Shiro的Spring Boot启动器(如果用PetClinic默认的Thymeleaf视图层,记得加上Shiro-Thymeleaf集成依赖)。这里是Maven的配置示例:
<!-- Shiro Spring Boot Web 启动器 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.12.0</version> <!-- 使用最新稳定版本 --> </dependency> <!-- Shiro Thymeleaf 集成,用于页面级权限控制 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-thymeleaf</artifactId> <version>1.12.0</version> </dependency>
2. 配置Shiro核心组件
创建一个ShiroConfig.java配置类,用来设置Shiro的核心模块:Realm(处理认证和授权逻辑)、SecurityManager(Shiro的核心控制组件)和拦截规则。
下面是适配PetClinic的入门配置示例:
@Configuration public class ShiroConfig { // 自定义Realm:这里是对接PetClinic用户数据的核心 @Bean public Realm petClinicRealm() { AuthorizingRealm realm = new AuthorizingRealm() { // 授权逻辑:获取当前登录用户的角色/权限 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String userIdentifier = (String) principals.getPrimaryPrincipal(); // 替换为实际数据库查询:比如从PetClinic的仓库中获取用户角色 SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(); // 示例:根据用户类型分配角色(OWNER、VET、ADMIN) if (userIdentifier.contains("vet@")) { authInfo.addRole("VET"); } else { authInfo.addRole("OWNER"); } return authInfo; } // 认证逻辑:验证用户名密码是否匹配PetClinic的用户数据 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken loginToken = (UsernamePasswordToken) token; String username = loginToken.getUsername(); // 替换为实际仓库调用:比如ownerRepository.findByEmail(username) // 测试阶段可以用PetClinic的示例用户数据 if ("george.francis@example.com".equals(username)) { // 注意:数据库中要存储BCrypt加密后的密码,不要存明文! return new SimpleAuthenticationInfo(username, "$2a$10$Z8OvQxQ8y8a9X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P", getName()); } throw new UnknownAccountException("PetClinic系统中未找到该用户"); } }; // 配置BCrypt密码匹配器,确保密码验证安全 realm.setCredentialsMatcher(new HashedCredentialsMatcher("BCrypt")); return realm; } // 安全管理器:Shiro的核心控制组件 @Bean public DefaultWebSecurityManager securityManager(Realm petClinicRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(petClinicRealm); return securityManager; } // Shiro过滤器:定义哪些路径需要认证/角色权限 @Bean public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean(); filterFactory.setSecurityManager(securityManager); filterFactory.setLoginUrl("/login"); // 未认证用户跳转的登录页 filterFactory.setSuccessUrl("/"); // 登录成功后跳转的首页 filterFactory.setUnauthorizedUrl("/unauthorized"); // 权限不足时的跳转页 // 配置拦截规则(顺序很重要!) Map<String, String> filterRules = new LinkedHashMap<>(); // 静态资源和登录页允许匿名访问 filterRules.put("/css/**", "anon"); filterRules.put("/js/**", "anon"); filterRules.put("/images/**", "anon"); filterRules.put("/login", "anon"); // 其他所有路径需要认证才能访问 filterRules.put("/**", "authc"); // 兽医专属页面仅允许VET角色访问 filterRules.put("/vet/**", "roles[VET]"); filterFactory.setFilterChainDefinitionMap(filterRules); return filterFactory; } // 启用Shiro Thymeleaf标签,支持页面级权限判断 @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }
3. 适配PetClinic的用户实体
PetClinic默认没有专门的用户实体,你可以选择:
- 给现有实体(比如
Owner或Vet)添加password(加密后存储)和role字段 - 创建独立的
User实体,关联到Owner/Vet等,专门存储认证信息
4. 实现登录/登出流程
创建一个简单的LoginController,用Shiro的SubjectAPI处理用户登录登出:
@Controller public class LoginController { @GetMapping("/login") public String showLoginPage() { return "login"; // 指向自定义的登录页Thymeleaf模板 } @PostMapping("/login") public String processLogin(@RequestParam String username, @RequestParam String password, Model model) { Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { currentUser.login(token); return "redirect:/"; } catch (AuthenticationException e) { model.addAttribute("error", "用户名或密码错误"); return "login"; } } @GetMapping("/logout") public String processLogout() { SecurityUtils.getSubject().logout(); return "redirect:/login"; } }
5. 页面级权限控制
用Shiro的Thymeleaf标签根据用户角色或认证状态显示/隐藏内容,比如在PetClinic的头部导航中:
<!-- 仅向已认证用户显示登出链接 --> <div shiro:authenticated> <a href="/logout">退出登录</a> </div> <!-- 仅向VET角色用户显示兽医控制台链接 --> <div shiro:hasRole="VET"> <a href="/vet/dashboard">兽医控制台</a> </div>
避坑小提示
- 永远存储加密后的密码(禁止明文),示例中用的BCrypt是推荐方案
- 从小功能入手:先实现基础登录,再逐步添加角色权限控制
- 用PetClinic的示例用户(比如george.francis@example.com)测试流程
内容的提问来源于stack exchange,提问作者Rodwan Bakkar
相关产品推荐
相关产品推荐

