SpringBoot怎么整合Shiro实现权限控制
从现在开始,努力学习吧!本文《SpringBoot怎么整合Shiro实现权限控制》主要讲解了等等相关知识点,我会在golang学习网中持续更新相关的系列文章,欢迎大家关注并积极留言建议。下面就先一起来看一下本篇正文内容吧,希望能帮到你!
1、SpringBoot整合Shiro
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。
1.1、shiro简介
shiro有个核心组件,分别为Subject、SecurityManager和Realms
Subject:相当于当前操作的”用户“,这个用户不一定是一个具体的人,是一个抽象的概念,表明的是和当前程序进行交互的任何东西,例如爬虫、脚本、等等。所有的Subject都绑定到SecurityManager上,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者。
SecurityManager:这个是shiro框架的核心,所有与安全相关的操作都会与它进行交互,它管理者所有的Subject。
Realms:充当了Shiro与应用安全数据间的”桥梁“,当对用户执行认证(登录)和授权(访问控制)验证时,SecurityManager 需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作。
1.2、代码的具体实现
1.2.1、Maven的配置
<!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> <!--shiro整合thymeleaf--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> <!--shiro缓存--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.7.1</version> </dependency>
shiro默认是与jsp进行使用的,而这里是shiro整合thymeleaf所有要导入shiro整合thymeleaf的jar包
1.2.2、整合需要实现的类
一般来说整合只需要完成两个类的实现即可
一个是 ShiroConfig 一个是 CustomerRealm
如果需要添加shiro缓存并且不是自带的缓存而是redis缓存还需要进行另外两个类的编写
一个是 RedisCache 一个是 RedisCacheManager
1.2.3、项目结构
1.2.4、ShiroConfig的实现
未加shiro的缓存
package com.yuwen.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import com.yuwen.shiro.cache.RedisCacheManager; import com.yuwen.shiro.realm.CustomerRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; @Configuration public class ShiroConfig { //让页面shiro标签生效 @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } //1、创建shiroFilter 负责拦截所有请求 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); //给filter设置安全管理 factoryBean.setSecurityManager(defaultWebSecurityManager); //配置系统的受限资源 //配置系统公共资源 全部都能访问的设置anon Map<String,String> map = new HashMap<>(); map.put("/main","authc");//请求这个资源需要认证和授权 authc表示需要认证后才能访问 map.put("/admin","roles[admin]"); //表示admin角色才能访问 roles[]表示需要什么角色才能访问 map.put("/manage","perms[user:*:*]"); //表示需要user:*:*权限才能访问 perms[]表示需要什么权限才能访问 //访问需要认证的页面如果未登录会跳转到/login路由进行登陆 factoryBean.setLoginUrl("/login"); //访问未授权页面会自动跳转到/unAuth路由 factoryBean.setUnauthorizedUrl("/unAuth"); factoryBean.setFilterChainDefinitionMap(map); return factoryBean; } //2、创建安全管理器 @Bean public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("getRealm") Realm realm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //给安全管理器设置 securityManager.setRealm(realm); return securityManager; } //3、创建自定义的realm @Bean public Realm getRealm(){ CustomerRealm customerRealm = new CustomerRealm(); //修改凭证校验匹配器 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //设置加密算法为md5 credentialsMatcher.setHashAlgorithmName("MD5"); //设置散列次数 credentialsMatcher.setHashIterations(1024); customerRealm.setCredentialsMatcher(credentialsMatcher); return customerRealm; } }
因为一般在数据库中设置明文密码不安全,所有我这里对密码进行了md5加密,我的加密方式为:密码 = 密码+盐+散列次数 而后进行MD5加密 所以这里创建自定义的realm时需要进行设置匹配器这样登录时密码才能匹配成功
1.2.5、CustomerRealm的实现
package com.yuwen.shiro.realm; import com.yuwen.pojo.User; import com.yuwen.pojo.vo.ViewPerms; import com.yuwen.pojo.vo.ViewRole; import com.yuwen.service.UserService; import com.yuwen.shiro.salt.MyByteSource; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.CollectionUtils; import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.util.List; //自定义realm public class CustomerRealm extends AuthorizingRealm { @Resource private UserService userService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //获取身份信息 String primaryPrincipal = (String)principalCollection.getPrimaryPrincipal(); //根据主身份信息获取角色 和 权限信息 List<ViewRole> roles = userService.findRolesByUsername(primaryPrincipal); if (!CollectionUtils.isEmpty(roles)){ SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); roles.forEach(viewRole -> { simpleAuthorizationInfo.addRole(viewRole.getName()); //权限信息 List<ViewPerms> perms = userService.findPermsByRoleId(viewRole.getName()); if (!CollectionUtils.isEmpty(perms)){ perms.forEach(viewPerms -> { simpleAuthorizationInfo.addStringPermission(viewPerms.getPName()); }); } }); return simpleAuthorizationInfo; } return null; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //获取登入的身份信息 String principal = (String) authenticationToken.getPrincipal(); User user = userService.findByUsername(principal); if (!ObjectUtils.isEmpty(user)){ //ByteSource.Util.bytes(user.getSalt()) 通过这个工具将盐传入 //如果身份认证验证成功,返回一个AuthenticationInfo实现; return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),new MyByteSource(user.getSalt()),this.getName()); } return null; } }
在登录时会自动调用这个身份验证 在验证时如果出错,会报异常,我在controller层接收了异常并处理
controller层中登录时的异常处理
@PostMapping("/login") public String login(String username,String password){ //获取主体对象 Subject subject = SecurityUtils.getSubject(); try { //自动调用CustomerRealm 类中的身份验证方法 subject.login(new UsernamePasswordToken(username,password)); return "index"; }catch (UnknownAccountException e){ //接收异常并处理 e.printStackTrace(); model.addAttribute("msg","用户名有误,请重新登录"); }catch (IncorrectCredentialsException e){//接收异常并处理 e.printStackTrace(); model.addAttribute("msg","密码有误,请重新登录"); } return "login"; }
1.2.6、shiro缓存配置
定义了shiro缓存,用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率
默认缓存的配置
在 ShiroConfig中 的 getRealm() 方法中开启缓存管理
@Bean public Realm getRealm(){ CustomerRealm customerRealm = new CustomerRealm(); //开启缓存管理 customerRealm.setCacheManager(new EhCacheManager()); //开启全局缓存 customerRealm.setCachingEnabled(true); //开启认证缓存 customerRealm.setAuthenticationCachingEnabled(true); customerRealm.setAuthenticationCacheName("authenticationCache"); //开启权限缓存 customerRealm.setAuthorizationCachingEnabled(true); customerRealm.setAuthorizationCacheName("authorizationCache"); return customerRealm; }
与reids整合的缓存这里就不说明了,放在源码里自己查看,源码在下方
1.2.7、主页index.html的设置
在这里用标签来判断某些区域需要认证或什么角色或者什么权限才能访问
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8"> <title>首页</title> <link rel="shortcut icon" href="#"> </head> <body> <h1>index</h1> <a href="/logout">退出</a> <div> <a href="/main">main</a> | <a href="/manage">manage</a> | <a href="/admin">admin</a> </div> <!--获取认证信息--> 用户:<span shiro:principal=""></span><hr> <!--认证处理--> <span shiro:authenticated=""><hr> 显示认证通过内容 </span> <span shiro:notAuthenticated=""><hr> 没有认证时 显示 </span> <!--授权角色--> <span shiro:hasRole="admin"><hr> admin角色 显示 </span> <span shiro:hasPermission="user:*:*"><hr> 具有用户模块的"user:*:*"权限 显示 </span> </body> </html>
1.3、简单测试
1.3.1、admin角色所有权限测试
1.3.2、无角色有权限测试
1.3.3、无角色无权限测试
今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

- 上一篇
- win7无法打开nvidia控制面板怎么办?win7打不开nvidia控制面板解决方法

- 下一篇
- linux arp有什么作用
-
- 文章 · java教程 | 2小时前 |
- Lombok注解处理器工作原理解析
- 295浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java线程池类型及使用场景解析
- 220浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java实现Zookeeper服务注册与发现方法
- 336浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java集成FFmpeg处理视频流教程
- 275浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java反射与动态代理实用技巧解析
- 389浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java类是什么?面向对象核心概念详解
- 291浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- MAT工具使用:Java堆内存分析全攻略
- 105浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java连接InfluxDB教程详解
- 430浏览 收藏
-
- 文章 · java教程 | 3小时前 | 异步处理 松耦合 Spring事件监听 ApplicationEvent ApplicationListener
- Spring事件监听的实战应用解析
- 353浏览 收藏
-
- 文章 · java教程 | 3小时前 | 性能 jdbc 批量操作 PreparedStatement addBatch
- JavaJDBC批量操作怎么用,优势有哪些?
- 416浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java数组与算法常见应用解析
- 155浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java循环变量累积问题与重置方法
- 490浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 509次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 边界AI平台
- 探索AI边界平台,领先的智能AI对话、写作与画图生成工具。高效便捷,满足多样化需求。立即体验!
- 39次使用
-
- 免费AI认证证书
- 科大讯飞AI大学堂推出免费大模型工程师认证,助力您掌握AI技能,提升职场竞争力。体系化学习,实战项目,权威认证,助您成为企业级大模型应用人才。
- 67次使用
-
- 茅茅虫AIGC检测
- 茅茅虫AIGC检测,湖南茅茅虫科技有限公司倾力打造,运用NLP技术精准识别AI生成文本,提供论文、专著等学术文本的AIGC检测服务。支持多种格式,生成可视化报告,保障您的学术诚信和内容质量。
- 185次使用
-
- 赛林匹克平台(Challympics)
- 探索赛林匹克平台Challympics,一个聚焦人工智能、算力算法、量子计算等前沿技术的赛事聚合平台。连接产学研用,助力科技创新与产业升级。
- 267次使用
-
- 笔格AIPPT
- SEO 笔格AIPPT是135编辑器推出的AI智能PPT制作平台,依托DeepSeek大模型,实现智能大纲生成、一键PPT生成、AI文字优化、图像生成等功能。免费试用,提升PPT制作效率,适用于商务演示、教育培训等多种场景。
- 206次使用
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览