SpringBoot与Shiro权限管理系统实战:认证授权与避坑指南

发布时间:2026/10/29 17:38:09

SpringBoot与Shiro权限管理系统实战:认证授权与避坑指南 简介这份资源是基于SpringBoot与Shiro的权限管理系统完整项目源码面向具备一定Java Web基础、希望深入理解认证授权机制的开发者与学习者。项目将SpringBoot的自动配置能力与Shiro的安全框架相结合覆盖用户登录验证、角色权限分配、会话管理以及敏感数据加密等核心场景适合用于课程设计、毕业设计或企业级权限模块的参考实现。压缩包共306个文件约1.82MB其中108个java文件承载后端认证授权与业务逻辑56个js、34个html与22个css构成前端交互界面另有xml、yml、sql等配置与建表脚本以及png、jpeg等界面素材和字体文件结构完整、层次清晰。目前已有28人学习下载。通过阅读源码读者可以掌握Realm自定义、Authorizer授权策略、SessionManager会话控制等关键实现理解角色与权限的灵活分配方式并借鉴其可扩展的模块化设计快速搭建或改造自己的权限管理模块。1. 从一份「权限管理系统.zip」说起SpringBoot 与 Shiro 到底怎么搭拿到一个名为「基于SpringBoot与Shiro的权限管理系统.zip」的压缩包多数人的第一反应是解压、找pom.xml、看启动类然后mvn spring-boot:run一把梭。但真正跑起来之后问题才刚开始登录能过菜单却出不来菜单出来了按钮权限又拦不住换个角色登录接口直接 403 或者干脆 500。这些现象背后几乎都指向同一件事——SpringBoot 的自动装配和 Shiro 的过滤器链没有对齐。这个标题讲的是用 SpringBoot 做工程底座、用 Shiro 做认证与授权的一套权限管理系统。它解决的核心问题是谁能登录、登录后能看到哪些菜单、能点哪些按钮、能调哪些接口。适合正在做后台管理系统、毕设项目、或者公司内部中台权限模块的开发者。如果你手里正好有这么一个压缩包或者准备自己搭一套下面这些内容能帮你少走弯路。2. 环境准备与工程结构别急着写 Realm2.1 依赖版本怎么选才不打架SpringBoot 和 Shiro 的整合第一个坑往往出在版本上。Shiro 官方并没有提供一个「SpringBoot Starter」式的开箱依赖常见做法是引入shiro-spring或shiro-spring-boot-web-starter。前者需要自己写配置类后者能省掉一部分样板代码但对 SpringBoot 版本有隐性要求。我一般会先锁定 SpringBoot 的版本再反推 Shiro 的版本。比如 SpringBoot 2.7.x 搭配 Shiro 1.11.0 是比较稳的组合如果 SpringBoot 3.xShiro 需要 1.13.0 以上才支持 Jakarta EE 命名空间。下面是一个典型的pom.xml依赖片段!-- SpringBoot 父工程锁定版本 -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version /parent dependencies !-- Web 场景提供内嵌 Tomcat 和 MVC -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Shiro 与 Spring 整合的核心包 -- dependency groupIdorg.apache.shiro/groupId artifactIdshiro-spring/artifactId version1.11.0/version /dependency !-- 如果要用 Shiro 的缓存比如 Redis再加对应依赖 -- dependency groupIdorg.apache.shiro/groupId artifactIdshiro-ehcache/artifactId version1.11.0/version /dependency /dependencies这里shiro-spring负责把 Shiro 的SecurityManager、Realm等组件交给 Spring 容器管理。shiro-ehcache是可选的用来缓存授权信息避免每次请求都查库。参数上version尽量和 Shiro 主版本保持一致不要混用 1.10 和 1.13 的包否则容易出现NoSuchMethodError。2.2 目录结构把 Shiro 配置单独放一个能跑起来的权限管理系统目录结构通常长这样src/main/java/com/example/permission/ ├── config/ │ ├── ShiroConfig.java // Shiro 核心配置 │ └── MyBatisConfig.java // 如果用了 MyBatis ├── controller/ │ ├── LoginController.java │ └── UserController.java ├── realm/ │ └── CustomRealm.java // 自定义 Realm ├── entity/ │ └── SysUser.java ├── service/ │ └── SysUserService.java └── PermissionApplication.java // 启动类把ShiroConfig和CustomRealm分开放在不同包下是为了后续排查问题时能快速定位过滤器链的问题看config认证授权逻辑的问题看realm。很多压缩包里的代码把两者混在一个类里改起来非常痛苦。2.3 最小可运行配置先让登录页出来在写 Realm 之前先把 Shiro 的过滤器链配好让/login能匿名访问其他路径需要认证。下面是一个最小化的ShiroConfigConfiguration public class ShiroConfig { Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean factoryBean new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); // 设置登录页未认证时跳转到这里 factoryBean.setLoginUrl(/login); // 登录成功后跳转 factoryBean.setSuccessUrl(/index); // 未授权页面 factoryBean.setUnauthorizedUrl(/403); // 过滤器链定义注意 LinkedHashMap 是有序的 MapString, String filterChainMap new LinkedHashMap(); filterChainMap.put(/login, anon); // 匿名访问 filterChainMap.put(/static/**, anon); // 静态资源放行 filterChainMap.put(/logout, logout); // 登出 filterChainMap.put(/**, authc); // 其余全部认证 factoryBean.setFilterChainDefinitionMap(filterChainMap); return factoryBean; } Bean public SecurityManager securityManager(CustomRealm customRealm) { DefaultWebSecurityManager securityManager new DefaultWebSecurityManager(); securityManager.setRealm(customRealm); return securityManager; } }这段代码的关键在filterChainMap的顺序。LinkedHashMap保证按插入顺序匹配所以/**必须放在最后。如果把/**放在/login前面登录页也会被拦截直接死循环。参数anon表示匿名访问authc表示需要认证logout会触发 Shiro 的登出逻辑并重定向到loginUrl。提示如果启动后访问任何路径都跳登录页先检查filterChainMap里有没有把静态资源放行以及loginUrl是否被authc拦截。3. 认证与授权Realm 写对了权限就通了一半3.1 自定义 Realm 的认证逻辑Realm 是 Shiro 和你的用户数据之间的桥梁。认证阶段Shiro 会把用户输入的账号密码封装成AuthenticationToken交给 Realm 去比对。下面是一个基于数据库查询的CustomRealmpublic class CustomRealm extends AuthorizingRealm { Autowired private SysUserService sysUserService; // 认证登录时调用 Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken (UsernamePasswordToken) token; String username upToken.getUsername(); // 从数据库查用户 SysUser user sysUserService.findByUsername(username); if (user null) { throw new UnknownAccountException(用户不存在); } if (user.getStatus() 0) { throw new LockedAccountException(账号已被锁定); } // 参数principal身份credentials密码realmName return new SimpleAuthenticationInfo( user, // principal 放用户对象 user.getPassword(), // 数据库里的密码 ByteSource.Util.bytes(user.getSalt()), // 盐值 getName() ); } // 授权访问受控资源时调用 Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SysUser user (SysUser) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info new SimpleAuthorizationInfo(); // 查角色 SetString roles sysUserService.findRolesByUserId(user.getId()); info.setRoles(roles); // 查权限 SetString permissions sysUserService.findPermissionsByUserId(user.getId()); info.setStringPermissions(permissions); return info; } }认证部分有三个关键点第一principal放的是整个用户对象这样授权阶段可以直接从PrincipalCollection里取出来不用再查一次库第二密码比对由 Shiro 完成但前提是你在ShiroConfig里配置了HashedCredentialsMatcher否则它会拿明文比对第三盐值必须和注册时使用的一致否则哈希对不上。授权部分返回的roles和permissions是字符串集合。角色通常对应role:admin这种格式权限对应user:add、user:delete这种细粒度标识。这些字符串最终会用在控制器或页面的RequiresPermissions注解上。3.2 密码加密与盐值处理如果数据库里存的是明文密码上面那段代码能跑通但没有任何安全性可言。常见做法是用HashedCredentialsMatcher配合 MD5 或 SHA-256 加盐。配置如下Bean public CustomRealm customRealm(HashedCredentialsMatcher matcher) { CustomRealm realm new CustomRealm(); realm.setCredentialsMatcher(matcher); return realm; } Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher matcher new HashedCredentialsMatcher(); matcher.setHashAlgorithmName(MD5); // 哈希算法 matcher.setHashIterations(1024); // 迭代次数 matcher.setStoredCredentialsHexEncoded(true); // 十六进制存储 return matcher; }参数hashIterations越大暴力破解成本越高但登录时的计算开销也越大。1024 是一个折中值生产环境可以调到 10000 以上。storedCredentialsHexEncoded要和数据库里密码的存储格式一致如果存的是 Base64这里要改成false。注册用户时需要用同样的算法生成密码public String encryptPassword(String password, String salt) { return new SimpleHash(MD5, password, ByteSource.Util.bytes(salt), 1024).toHex(); }盐值一般用随机字符串存在用户表里。每个用户的盐值不同这样即使两个用户密码相同数据库里的哈希值也不一样。3.3 角色与权限的拦截方式Shiro 提供了注解和标签两种拦截方式。后端接口用注解RestController RequestMapping(/user) public class UserController { RequiresPermissions(user:list) GetMapping(/list) public ListSysUser list() { return userService.findAll(); } RequiresRoles(admin) PostMapping(/delete/{id}) public String delete(PathVariable Long id) { userService.deleteById(id); return ok; } }前端页面用 Shiro 标签控制按钮显示shiro:hasPermission nameuser:add button idaddBtn新增用户/button /shiro:hasPermission注解生效的前提是在ShiroConfig里开启了 AOP 支持也就是注册AuthorizationAttributeSourceAdvisor这个 Bean。如果注解不生效先检查这个 Bean 有没有被 Spring 扫描到。注意RequiresPermissions在 Controller 方法上生效需要 Shiro 的 AOP 代理。如果 Controller 没有被代理注解会被静默忽略接口就变成了裸奔。4. 避坑与排查那些让权限系统「看起来正常」的陷阱4.1 登录成功但一直跳登录页现象输入正确账号密码后台日志显示认证通过但浏览器又回到了/login。原因Shiro 的SecurityManager和 Spring 的SecurityManager不是同一个实例或者ShiroFilterFactoryBean里的securityManager没有正确注入。另一个常见原因是filterChainMap里/login的anon被后面的规则覆盖了。解决在ShiroConfig里确认securityManagerBean 被shiroFilter方法参数注入而不是在方法内部new一个。同时打印filterChainMap的顺序确保anon规则在authc之前。4.2 授权信息不更新改了角色要重启现象给用户新增了一个角色数据库已经改了但用户重新登录后权限还是旧的。原因Shiro 默认会缓存授权信息如果配置了CacheManager但没有清理策略doGetAuthorizationInfo不会每次都查库。解决在角色或权限变更的 Service 方法里手动调用shiroRealm.clearCachedAuthorizationInfo(principals)。或者干脆在开发阶段先关掉缓存确认逻辑正确后再开启。4.3 静态资源被拦截页面样式全丢现象登录页能打开但 CSS 和 JS 全部 404 或者被重定向到登录页。原因filterChainMap里没有放行/static/**、/css/**、/js/**等路径或者 SpringBoot 的静态资源路径和 Shiro 的拦截路径不一致。解决在filterChainMap里显式放行静态资源目录并确认application.yml里的spring.resources.static-locations配置。如果用了前端框架打包后的dist目录还要放行/index.html和/favicon.ico。4.4 密码加盐后登录失败现象注册时用了盐值加密登录时却提示密码错误。原因注册和登录使用的哈希算法、迭代次数、盐值编码方式不一致。比如注册时用了toHex()登录时HashedCredentialsMatcher却按 Base64 解析。解决把注册和登录的加密逻辑抽到同一个工具类里确保SimpleHash的四个参数完全一致。盐值在数据库里存字符串使用时统一转成ByteSource。4.5 前后端分离时 Session 丢失现象Vue 前端调用后端接口登录成功后返回了 Cookie但后续请求带上 Cookie 仍然提示未认证。原因跨域请求默认不携带 Cookie或者后端没有配置withCredentials。Shiro 默认基于 Session 管理认证状态跨域时 Session ID 传不过去。解决前端在 axios 里设置withCredentials: true后端配置 CORS 时allowCredentials(true)且allowedOrigins不能是*。如果完全不想用 Session可以换成 JWT把认证信息放在 Token 里Shiro 的 Realm 从 Token 中解析用户。5. 进阶技巧把权限系统做得再稳一点5.1 用 Redis 接管 Shiro 缓存默认的 Ehcache 是单机缓存多实例部署时会出现权限不一致。把CacheManager换成 Redis 实现可以让多个节点共享授权缓存。核心是自定义一个RedisCacheManager实现 Shiro 的CacheManager接口然后在SecurityManager里注入。Bean public SecurityManager securityManager(CustomRealm realm, RedisCacheManager redisCacheManager) { DefaultWebSecurityManager securityManager new DefaultWebSecurityManager(); securityManager.setRealm(realm); securityManager.setCacheManager(redisCacheManager); return securityManager; }Redis 里存的 key 通常是shiro:authorization:userIdvalue 是序列化后的授权信息。设置合理的过期时间比如 30 分钟避免权限变更后长时间不生效。5.2 动态权限从数据库加载过滤器链硬编码在ShiroConfig里的filterChainMap只适合路径固定的场景。如果权限需要动态配置比如后台可以新增一个/report/**需要report:view权限就需要从数据库加载过滤器链。常见做法是定义一个FilterChainDefinition类从数据库查权限规则按顺序拼成LinkedHashMap再交给ShiroFilterFactoryBean。Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, FilterChainDefinition filterChainDefinition) { ShiroFilterFactoryBean factoryBean new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); factoryBean.setFilterChainDefinitionMap(filterChainDefinition.loadFilterChains()); return factoryBean; }loadFilterChains方法里按sort字段排序确保anon规则排在authc前面。数据库表设计上至少要有url、filterName、sort三个字段。5.3 验证权限配置是否生效的三种方法第一种直接在 Controller 里注入Subject调用subject.isPermitted(user:add)看返回值是否符合预期。第二种在doGetAuthorizationInfo里打日志确认每次请求都触发了授权查询。第三种用 Postman 或 curl 直接访问受控接口不带 Cookie 应该返回 401 或跳转带 Cookie 且权限不足应该返回 403。我自己的习惯是每加一个权限标识先在数据库里给测试账号配上然后用subject.isPermitted在单元测试里断言一次。这样比在页面上点来点去快得多也不容易漏。5.4 一个容易忽略的细节Shiro 的 Session 超时Shiro 的 Session 默认超时时间是 30 分钟和 Servlet 容器的 Session 超时是两套机制。如果只改了server.servlet.session.timeoutShiro 的 Session 不会跟着变。需要在ShiroConfig里单独设置Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(1800000); // 30 分钟单位毫秒 sessionManager.setSessionValidationSchedulerEnabled(true); return sessionManager; }setSessionValidationSchedulerEnabled(true)会启动一个定时任务清理过期 Session生产环境建议开启。如果用了 Redis 共享 Session还要把SessionDAO换成 Redis 实现。权限系统这东西搭起来不难难的是边界情况。我踩过最深的坑是前后端分离时 Cookie 的SameSite属性浏览器默认Lax跨站请求不带 Cookie排查了一整天才发现是浏览器策略问题。后来养成的习惯是任何权限相关的改动先在无痕窗口里用两个不同角色的账号交叉验证一遍再提交代码。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/29 17:38:09

51单片机定时器中断实战:Proteus交通灯仿真与避坑指南

简介:这是一份面向51单片机初学者与电子工程专业学生的C语言Proteus仿真实例资源,聚焦定时器控制交通指示灯这一典型项目,帮助读者理解定时器中断、I/O口电平控制与红绿灯周期切换的编程逻辑。压缩包共15个文件,约29KB&#xff0c…

2026/10/29 17:33:08

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

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

2026/10/29 17:33:08

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

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

2026/10/29 18:38:15

context-mode:SQLite+FTS5+BM25构建本地AI上下文检索模式

1. “context-mode”到底是什么?别被术语唬住,它本质是让AI真正“听懂上下文”的工程实践最近在多个技术社区和开发群聊里,“context-mode”这个词突然高频出现,尤其和MCP、SQLite、FTS5、BM25这些词绑在一起。很多人第一反应是&a…

2026/10/29 18:38:15

hyperframes:用HTML+CSS实现视频帧级交互的轻量范式

1. “hyperframes”不是新框架,而是对HTML媒体渲染范式的重新命名与实践重构最近在多个前端技术社区和CLI工具讨论区里,“hyperframes”这个词突然高频出现。它既不是某个新发布的JavaScript框架,也不是W3C正在推进的标准草案,更不…

2026/10/29 18:38:15

从技能分层到能力模型:打造可落地的技能管理框架

一个只写着“skills”的项目标题,乍看像一个未完成的占位符,但接触过人才盘点、个人知识管理或技术团队搭建的朋友应该都有同感——这个词背后藏着的潜台词其实是:在一个信息过载、工具爆炸的时代,我们到底该如何识别、沉淀、复用…

2026/10/29 18:38:15

拆解二维码扫码登录:临时票据、状态机、轮询与安全并发

二维码扫码登录这东西,几乎每个做过 Web 端的人都用过,但真被面试官追着问细节的时候,能从头到尾讲圆的人并不多。我见过不少候选人在这个问题上翻车,不是不知道流程,而是把"扫码登录"当成了一个黑盒&#x…

2026/10/29 18:38:15

Superpowers安装与协作开发完全指南:浏览器实时共写游戏

前两天整理开源项目收藏夹,翻出一个躺了大半年的链接:superpowers。这名字挺大气,实际是个基于浏览器的实时协作游戏开发环境。顺手搜了下相关热搜词,“想要安装superpowers”排在很前面,看来最近想入坑的朋友不少。这…

2026/10/29 18:33:14

Blender马尾辫制作指南:Ponytail插件从生发到绑定布料模拟全流程

做角色资产的老哥应该都懂:头发永远是进度表上最不可控的那一项,尤其是马尾辫。上个月我接了个角色绑定活,美术要求来一条自然垂坠、甩头时有质感的高马尾。我一开始纯手动:搭低模发片、撒粒子梳理发丝、给整束头发刷权重&#xf…

2026/10/29 17:05:52

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/29 17:06:02

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/29 17:06:13

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/29 0:03:42

学生选课系统DFD图绘制指南:边界划分与分层校验实战

简介:文档以顶层与第一层DFD图为核心,完整刻画学生选课系统的逻辑模型,面向软件工程课程设计、系统分析学习及毕设前期建模人群。顶层图界定系统边界,外部实体包括管理员、教师和学生三类角色;第一层图进一步细化用户登…

2026/10/29 0:03:42

JIRA敏捷落地:Scrum角色权限、Sprint与燃尽图避坑指南

简介:围绕“基于JIRA的敏捷开发项目管理”这一主题,面向产品负责人、Scrum Master及研发测试成员,梳理Scrum角色分工、迭代流程与JIRA工具配置的对应关系,适合初、中级团队导入敏捷管理时参考。压缩包共1个docx文件,大…

2026/10/29 0:03:42

SEMI S8人机工程验收实战:从条款拆解到现场实测的完整指南

简介:面向半导体设备设计、制造与运维工程师及安全合规人员,这份资料聚焦SEMI标准体系下的设备安全规范,重点收录SEMI S8-0308《半导体制造设备人体工程学工程安全指南》。内容围绕设备设计原则、错误与事故预防、人体工程学适配三大主线展开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑