尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SpringBoot+Shiro权限管理系统实战:认证授权与动态菜单
简介这份资源是基于SpringBoot与Shiro的权限管理系统完整项目源码面向具备Java与Spring基础的开发者、课程设计或毕业设计人群用于解决用户认证、角色授权与会话管理等安全控制问题。压缩包共306个文件约1.82MB以108个java源码为核心配合56个js、34个html、22个css及22个png等前端与静态资源另有15个xml、1个sql与1个yml等配置脚本覆盖后端逻辑、页面模板、样式脚本与数据库建表等模块。已有28人学习下载。项目将Shiro的Realm认证、Authorizer授权、SessionManager会话管理及密码哈希加密等机制与SpringBoot自动配置结合支持角色权限分配、会话超时与并发控制并集成Thymeleaf或前端框架界面便于读者直接运行调试、理解安全框架集成思路也可作为二次开发与功能扩展的参考模板。1. 一个能直接跑起来的权限管理系统到底省掉了哪些活如果你做过后台管理类项目一定遇到过这种局面用户表、角色表、菜单表、权限表四张表建好了登录接口也写完了但一到「不同角色看到不同菜单、不同按钮」就开始乱。更麻烦的是认证和授权这两件事经常被混在一起写最后代码里到处是if (role.equals(admin))。这份基于 SpringBoot 与 Shiro 的权限管理系统解决的就是这类问题——它把用户、角色、权限、菜单、部门、日志这些后台标配模块做成了一套可运行的工程认证交给 Shiro 的 Realm授权交给过滤链和注解前端菜单由后端权限数据动态生成。它适合三类人正在做课程设计或毕设、需要一套结构完整的后台脚手架的人想系统理解 Shiro 认证授权流程、但不想从零搭环境的人以及手上有个管理系统要快速起步、希望先跑通再改造的人。技术栈是 SpringBoot Shiro MyBatis 前端模板典型的传统后台架构不依赖微服务那一套本地起一个数据库就能跑。下面我按「先跑通、再拆解、最后避坑」的顺序把这份资源拆开讲清楚。2. 环境准备与工程结构先让项目在你机器上活过来2.1 依赖版本与数据库准备拿到一个 SpringBoot 项目第一件事不是急着点运行而是先看pom.xml里的版本组合。SpringBoot 和 Shiro 的整合对版本比较敏感尤其是 Shiro 的 starter 和原生shiro-spring混用时容易出现过滤器不生效的问题。常见做法是统一用shiro-spring-boot-web-starter让自动配置接管大部分 Bean。!-- pom.xml 关键依赖版本按你本地仓库实际可用的来 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring-boot-web-starter/artifactId version1.13.0/version /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId /dependency这段依赖里shiro-spring-boot-web-starter会自动注册SecurityManager、ShiroFilterFactoryBean等核心组件省掉大量 XML 配置。mybatis-spring-boot-starter负责把 Mapper 接口扫描成 Bean。参数上要注意Shiro 1.13 之前有几个安全公告涉及的版本建议不要用太老的 1.2、1.3MySQL 驱动 8.x 要配com.mysql.cj.jdbc.Driver5.x 用com.mysql.jdbc.Driver写错会直接报驱动找不到。数据库方面项目一般会带一个.sql文件导入后至少有用户、角色、权限、菜单、角色权限关联、用户角色关联这几张表。导入前先确认字符集是utf8mb4否则菜单里的中文会变问号。# 建库并导入注意库名和配置文件保持一致 mysql -uroot -p -e CREATE DATABASE shiro_demo DEFAULT CHARACTER SET utf8mb4; mysql -uroot -p shiro_demo sql/shiro_demo.sql导入完成后去application.yml里核对数据库连接。这一步翻车最多因为很多人只改了库名没改密码或者端口不是默认的 3306。spring: datasource: url: jdbc:mysql://localhost:3306/shiro_demo?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.DriverserverTimezone这个参数在 MySQL 8 里必须给否则启动时报时区错误。useUnicode和characterEncoding一起用保证中文不乱码。2.2 目录结构与启动入口SpringBoot 项目的目录结构基本固定但这份资源里值得关注的是 Shiro 相关配置放在哪。常见做法是单独建一个config包放ShiroConfigrealm包放自定义Realmcontroller、service、mapper各司其职。src/main/java/com/example/ ├── config/ # ShiroConfig、MyBatisConfig 等 ├── realm/ # 自定义 AuthorizingRealm ├── controller/ # 登录、用户、角色、菜单接口 ├── service/ # 业务逻辑 ├── mapper/ # MyBatis Mapper 接口 ├── entity/ # 实体类 └── Application.java # 启动类启动类上一般会有MapperScan(com.example.mapper)少了这个注解Mapper 注入会失败。启动时如果报Consider defining a bean of type xxxMapper八成就是扫描路径没对上。SpringBootApplication MapperScan(com.example.mapper) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }启动成功后访问登录页用 SQL 里预置的账号登录。如果登录页能打开但提交后一直跳回登录页先别怀疑代码去看控制台有没有 Shiro 的认证异常堆栈多数是密码比对规则没对上——Shiro 默认用SimpleHash加盐如果数据库里存的是明文或者 MD5而 Realm 里用了加盐校验就会一直认证失败。3. Shiro 认证与授权把登录和权限判断拆开看3.1 自定义 Realm 的认证逻辑Shiro 的核心是Realm它负责从数据库取用户信息和权限信息。认证走doGetAuthenticationInfo授权走doGetAuthorizationInfo这两个方法分开写是理解整个权限系统的关键。public class UserRealm extends AuthorizingRealm { Autowired private UserService userService; // 认证登录时校验用户名密码 Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { UsernamePasswordToken upToken (UsernamePasswordToken) token; User user userService.findByUsername(upToken.getUsername()); if (user null) { throw new UnknownAccountException(用户不存在); } // 参数用户对象、数据库密码、盐值、Realm 名称 return new SimpleAuthenticationInfo( user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName()); } // 授权判断用户有哪些角色和权限 Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { User user (User) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info new SimpleAuthorizationInfo(); info.setRoles(userService.findRolesByUserId(user.getId())); info.setStringPermissions(userService.findPermsByUserId(user.getId())); return info; } }认证方法里SimpleAuthenticationInfo的四个参数分别是主体对象、数据库中的密码、盐值、Realm 名称。盐值这一步是血泪经验——如果数据库密码是加盐哈希存的这里必须传盐否则 Shiro 用同样的算法算出来的结果对不上登录永远失败。授权方法里setRoles和setStringPermissions分别设置角色集合和权限字符串集合后续注解和标签都从这里取数据。3.2 过滤链配置与注解授权Shiro 的过滤链决定了哪些 URL 需要认证、哪些放行。配置在ShiroConfig里用LinkedHashMap保证顺序因为 Shiro 是按顺序匹配的写反了就会出问题。Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean factory new ShiroFilterFactoryBean(); factory.setSecurityManager(securityManager); factory.setLoginUrl(/login); factory.setUnauthorizedUrl(/unauthorized); MapString, String filterMap new LinkedHashMap(); filterMap.put(/login, anon); // 登录页放行 filterMap.put(/static/**, anon); // 静态资源放行 filterMap.put(/logout, logout); // 登出交给 Shiro filterMap.put(/**, authc); // 其余全部需要认证 factory.setFilterChainDefinitionMap(filterMap); return factory; }anon表示匿名访问authc表示必须认证。顺序上放行规则一定要写在/**前面否则登录页也会被拦截形成死循环。这是新手最容易踩的坑之一。授权注解用在 Controller 方法上配合RequiresPermissions或RequiresRoles。要让注解生效必须在ShiroConfig里开启 AOP 支持Bean public AuthorizationAttributeSourceAdvisor advisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }少了这个 Bean注解就是个摆设方法照样能访问。判断注解是否生效可以在方法里打印SecurityUtils.getSubject().isPermitted(user:add)如果返回 false 但方法还能进说明 AOP 没配上。3.3 动态菜单与权限数据联动后台系统里菜单不是写死的而是根据当前用户权限动态生成。常见做法是登录后把用户能访问的菜单树查出来前端渲染。菜单表里一般有perms字段存权限标识和RequiresPermissions里的字符串对应。public ListMenu buildMenuTree(Long userId) { ListMenu menus menuService.findMenusByUserId(userId); // 按 parentId 组装成树根节点 parentId 为 0 MapLong, ListMenu children menus.stream() .filter(m - m.getParentId() ! 0) .collect(Collectors.groupingBy(Menu::getParentId)); menus.forEach(m - m.setChildren(children.getOrDefault(m.getId(), new ArrayList()))); return menus.stream().filter(m - m.getParentId() 0).collect(Collectors.toList()); }这段逻辑先按parentId分组再挂到父节点上最后只返回根节点。参数上要注意parentId的类型如果数据库是bigint而实体是Integer比较时可能因为类型不一致导致分组失败。菜单和权限的联动关系是菜单控制「看不看得见」权限控制「点不点得动」两者数据来源可以是一张表也可以是分开的两张表看项目设计。4. 常见问题排查登录、权限、菜单这三处最容易翻车4.1 登录一直失败但账号密码没错现象输入正确的用户名密码提交后跳回登录页控制台没有明显报错。原因通常是密码比对规则不一致——数据库存的是加盐哈希Realm 里没传盐或者哈希算法MD5/SHA-256和生成时用的不一样。解决先确认数据库密码字段的生成方式找到当初加密的工具类保证 Realm 里用的算法、盐值、迭代次数完全一致。实在不确定就临时把 Realm 改成明文比对跑通后再换回加密。4.2 注解授权不生效无权限也能访问现象方法上加了RequiresPermissions(user:delete)但用没有该权限的账号也能调用。原因有两个一是没配AuthorizationAttributeSourceAdvisorAOP 没织入二是 Controller 没有被 Spring 代理比如方法被private修饰或者类没加Controller。解决先检查 Advisor Bean 是否存在再确认方法所在类是被 Spring 管理的 Bean方法必须是public。4.3 菜单树渲染出来是平铺的现象前端拿到的菜单数据没有层级所有菜单都堆在一起。原因一般是parentId分组时类型不匹配或者根节点的parentId不是 0 而是 null。解决打印一下菜单列表确认parentId的实际值把根节点判断条件改成m.getParentId() null || m.getParentId() 0分组时统一转成Long再比较。4.4 静态资源被拦截导致页面样式丢失现象登录页能打开但 CSS、JS 全部 404页面裸奔。原因是过滤链里没放行静态资源路径或者放行路径和实际访问路径不一致。解决在filterMap里加上/static/**、/css/**、/js/**的anon规则并确认 SpringBoot 的静态资源映射目录和实际存放位置一致。默认是src/main/resources/static如果放在webapp下路径规则要相应调整。4.5 登出后还能访问需要认证的页面现象点了退出跳回登录页但浏览器后退还能看到之前的页面。原因是 Shiro 的logout过滤器清除了服务端会话但浏览器缓存了页面。解决在需要认证的页面响应头里加Cache-Control: no-store或者在登出后强制刷新。更彻底的做法是前端路由守卫配合后端会话校验每次进入页面前请求一次当前用户接口。5. 从跑通到改造把这份资源变成你自己的项目底座跑通之后真正有价值的是知道怎么改。这份资源的权限模型是标准的 RBAC改造空间主要在三个地方权限粒度、数据权限、会话管理。权限粒度上默认是「角色-权限」两级如果要做「用户-权限」直连可以在doGetAuthorizationInfo里把用户直接关联的权限也合并进去info.addStringPermissions()支持多次添加。数据权限是另一个维度比如「只能看本部门的数据」这种不适合用 Shiro 的权限字符串常见做法是在 Service 层拼 SQL 条件或者用 MyBatis 拦截器统一注入dept_id过滤。会话管理方面Shiro 默认用内存会话重启就丢。如果要做分布式部署需要换成 Redis 会话存储引入shiro-redis这类组件把SessionDAO替换掉。这一步要注意序列化问题SimpleAuthenticationInfo里的主体对象必须实现Serializable否则存 Redis 会报错。验证改造是否成功我一般会走一遍这个清单用不同角色账号登录确认菜单差异直接拼 URL 访问无权限接口确认返回 401 或 403退出后重进确认会话状态正确重启服务确认会话策略符合预期。这套流程走下来基本能覆盖认证授权的主要边界。从那以后我每次拿到这类权限系统都强制先跑一遍「登录-菜单-越权-登出」四步验证再动代码。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Linux文件IO操作详解:从基础到高级技巧

Linux文件IO操作详解:从基础到高级技巧

1. Linux文件IO基础概念解析 在Linux系统中,文件IO(输入输出)操作是系统编程中最基础也是最重要的部分之一。不同于Windows系统,Linux将几乎所有设备都抽象为文件来处理,这种"一切皆文件"的设计哲学使得文件…

📅 2026/10/29 17:33:06
电磁场与电磁波四维知识地图:从矢量分析到平面波极化

电磁场与电磁波四维知识地图:从矢量分析到平面波极化

简介:本资源是《电磁场与电磁波》(第二版,陈抗生编著,高等教育出版社)配套的完整课后习题解答,专为通信、电子、电磁场类本科高年级学生及考研备考者设计,有效解决教材习题无标准参考、推导过程…

📅 2026/10/29 17:33:06
动态三维建模技术:从空间表达到空间计算的演进

动态三维建模技术:从空间表达到空间计算的演进

1. 动态三维建模技术体系概述 当我们在手机上滑动查看一个商品的三维模型时,很少有人会意识到这背后是一套正在经历范式转换的技术体系。动态三维建模技术已经从单纯的空间表达(Space Representation)阶段,逐步演进到空间计算&…

📅 2026/10/29 17:33:06
MORE NEWS

更多资讯

📰

AUTOSAR架构下自动驾驶占用网络的实现与优化

1. 项目概述:AUTOSAR与自动驾驶占用网络的关系AUTOSAR(Automotive Open System Architecture)作为汽车电子系统开发的行业标准,正在深刻改变着自动驾驶系统的开发方式。在L3级及以上自动驾驶系统中,占用网络&#xff0…

📰

自动驾驶占用网络技术解析与AUTOSAR实现

1. 自动驾驶占用网络的技术本质占用网络(Occupancy Network)是自动驾驶环境感知领域的革命性技术突破,它彻底改变了传统基于边界框(Bounding Box)的物体检测范式。这个技术最早由Waymo在2022年提出,其核心思…

📰

GitHub趋势榜深度解读:JavaScript轻量化与Python AI工具链的实战选型

1. 从一份日榜速报说起:为什么值得花时间看每天早上刷一眼 GitHub 趋势榜,已经成了我这些年雷打不动的习惯。2026 年 10 月 2 日这一期的日榜,乍看只是普通的一天,但把榜单从头翻到尾之后,我发现里面藏着几条相当清晰的…

📰

从「什么都敢答」到「该拒就拒」:四道闸门

版权与内容来源声明 本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部…

📰

Lombok中@EqualsAndHashCode(callSuper)的正确使用指南

1. 理解EqualsAndHashCode(callSuper true)的本质在Java开发中,对象比较和哈希计算是日常编码绕不开的基础操作。Lombok的EqualsAndHashCode注解通过自动生成equals()和hashCode()方法,显著减少了样板代码。但callSuper参数的使用场景和实现原理&#x…

📰

Kubernetes StatefulSet 设计与实践指南

1. StatefulSet 的本质与设计初衷在 Kubernetes 集群中管理有状态应用一直是个棘手的问题。与无状态服务不同,像数据库、消息队列这类有状态服务对网络标识、存储持久化和部署顺序有着严格要求。StatefulSet 正是为解决这些问题而生的核心控制器。StatefulSet 的设计…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬