Shiro整合SpringBoot,实战下的应用场景

文章目录

  • 前言
  • 一、springBoot+shiro环境准备
    • 1.数据库
    • 2.ssmp环境搭建
    • 3.实体类
    • 4.三层搭建
    • 5.初始化测试数据
  • 二、Shiro过滤器
    • 1.Shiro认证过滤器
    • 2.Shiro授权过滤器
  • 三、springBoot+shiro身份认证
    • 1.创建Realm,重写认证方法doGetAuthenticationInfo
    • 2.创建shiro配置类
    • 3.Postman测试
  • 四、springBoot+shiro授权,鉴权
    • 1.重写授权方法doGetAuthenticationInfo
    • 2.访问程序资源(鉴权)
    • 3.全局异常处理器
    • 4.Postman测试


前言

整合springBoot+shiro流程:

  1. 环境准备
  2. 身份认证
    2.1 密码加密
    2.2 非法请求控制
  3. 授权,鉴权

一、springBoot+shiro环境准备

项目目录:
在这里插入图片描述

1.数据库

认证框架五表设计:
准备user用户表、user_role用户角色关系表、role角色表、 role_permission角色权限关系表、permission权限表
user用户表:
在这里插入图片描述
user_role用户角色关系表:
在这里插入图片描述
role角色表:
在这里插入图片描述
role_permission角色权限关系表:
在这里插入图片描述
permission权限表:
在这里插入图片描述

2.ssmp环境搭建

2.1准备依赖

		<!--web启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--test启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version><scope>runtime</scope></dependency><!--Mybatisplus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><!--lombok作用于实体类--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--shiro相关坐标--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency>

2.2 配置Yaml文件

#数据源配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rooturl: jdbc:mysql://localhost:3306/shiro?serverTimezone=GMTpassword: 12345678
#Mybatisplus配置
mybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.实体类

User用户类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("pe_user")
public class User implements Serializable {@TableId(value = "id",type = IdType.NONE)private String id;@TableField(value = "username")private String username;@TableField(value = "password")private String password;@TableField(value = "salt")private String salt;@TableField(exist = false)private Set<Role> roles;
}

role角色类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("pe_role")
public class Role implements Serializable {private  String id;private  String name;private  String code;private  String description;private Set<Permission> permissions;
}

Permission 权限类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("pe_permission")
public class Permission implements Serializable {private  String id;private  String name;private  String code;private  String escription;
}

4.三层搭建

DAO层: 因为是五表构造,需要处理关联关系,所以在这里使用级联查询的方式实现:
UserMapper :

@Mapper
public interface UserMapper extends BaseMapper<User> {@Select("select * from pe_user where username =#{username}")User findByName(String name);@Select("select * from pe_user where id =#{id}")@Results({@Result(id = true,property = "id",column = "id"),@Result(property = "username",column = "username"),@Result(property = "password",column = "password"),@Result(property = "salt",column = "salt"),@Result(property = "roles",column = "id",many = @Many(select = "com.apesource.springboot_shiro_01.dao.RoleMapper.findRoleById"))})User findUserDetailById(int id);
}

RoleMapper :

@Mapper
public interface RoleMapper {@Results({@Result(column = "id", property = "id"),@Result(column = "name", property = "name"),@Result(column = "code", property = "code"),@Result(column = "description", property = "description"),@Result(column = "id",property = "permissions",many = @Many(select = "com.apesource.springboot_shiro_01.dao.PermissionMapper.findPermissionById"))})
//    @Select("select  *  from 角色表 where 角色id in (select 角色ID from 关系表 where 用户id = ?)")@Select("select  *  from pe_role where id in (select role_id from pe_user_role where user_id = #{id})")public Set<Role> findRoleById(String id);
}

PermissionMapper :

@Mapper
public interface PermissionMapper {@Select("select  *  from pe_permission where id in (select permission_id from pe_role_permission where role_id = #{id})")@Results({@Result(column = "id", property = "id"),@Result(column = "name", property = "name"),@Result(column = "code",property = "code"),@Result(column = "description", property = "description")})public Set<Permission> findPermissionById(long id);
}

Service层: 因为项目只实现Shrio的用户认证和授权,所以只构造User的业务层就足够了。
UserService :

@Service
public class UserService {@Autowired(required = false)UserMapper mapper;public User findByName(String name){return mapper.findByName(name);}public User findUserDetailById(int id){return mapper.findUserDetailById(id);}
}

Controller层:

@RestController
public class ShiroController {@AutowiredUserService service;/*** @RequiresPermissions()  -- 访问此方法必须具备的权限*  @RequiresRoles()        -- 访问此方法必须具备的角色**/@RequiresPermissions("user-home")@RequestMapping(value = "/user/home")public String home() {return "访问个人主页成功";}//添加@RequiresPermissions("user-add")@RequestMapping(value = "/user",method = RequestMethod.POST)public String add() {return "添加用户成功";}//查询@RequiresPermissions("user-find")@RequestMapping(value = "/user/find",method = RequestMethod.GET )public String find(){return "查询成功";}//更新@RequiresPermissions("user-update")@RequestMapping(value = "/user/{id}",method = RequestMethod.PUT)public String update(@PathVariable String id) {return "更新用户成功";}//删除@RequiresPermissions("user-delete")@RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)public String delete(@PathVariable String id) {return "删除用户成功";}//未登陆与未授权页面@RequestMapping(value="/autherror")public String autherror() {return "未登录";}//用户登录@RequestMapping(value="/login")public String login(User user) {try {//1.构造登录令牌UsernamePasswordToken upToken = new UsernamePasswordToken(user.getUsername(),user.getPassword());//2.获取subjectSubject subject = SecurityUtils.getSubject();//3.调用subject进行登录subject.login(upToken);return "登录成功";}catch (Exception e) {e.printStackTrace();return "用户名或密码错误";}}
}

5.初始化测试数据

因为在实战场景下,数据库的密码是不可以明文保存的,这样对于数据的安全性是巨大的隐患,而shiro也支持数据加密的功能。
加密工具类:

public class DigestUtil {//算法方式public static final String SHA1 = "SHA-1";public static final String SHA256 = "SHA-256";//加密次数public static final Integer Counts =369;/*** @Description show* @param input 需要散列字符串* @param salt 盐字符串* @return*/public static String show(String input,String salt){return new SimpleHash(SHA1,input,salt,Counts).toString();}/*** @Description 随机获得salt字符串* @return*/public static String generateSalt(){SecureRandomNumberGenerator randomNumberGenerator =new SecureRandomNumberGenerator();return randomNumberGenerator.nextBytes().toHex();}/*** @Description 生成密码字符密文和salt密文* @param* @return*/public static Map<String,String> entryptPassword(String passwordPlain){Map<String,String> map = new HashMap<>();String salt =generateSalt();String password = show(passwordPlain,salt);map.put("salt",salt);map.put("明文password",passwordPlain);map.put("密文密码",password);return map;}

由于没有实现注册功能,所以对于数据库的密文密码通过自己操作工具类输入进去:

    public static void main(String[] args) {String name ="张三丰";String password = "123123";Map<String, String> map = entryptPassword(password);System.out.println(map.toString());}

二、Shiro过滤器

Shiro内置了很多默认的过滤器,比如身份验证、授权等相关的,shiro也是通过过滤器的原理来实现认证和授权的扩展功能的。

1.Shiro认证过滤器

在这里插入图片描述

2.Shiro授权过滤器

在这里插入图片描述

三、springBoot+shiro身份认证

1.创建Realm,重写认证方法doGetAuthenticationInfo

使用@PostConstruct注解修饰的init方法就会在Spring容器的启动时自动的执行

public class MyRealm extends AuthorizingRealm {@AutowiredUserService service;/*** @Description 自定义密码比较器* bean标签 init-method属性*/@PostConstructpublic void initCredentialsMatcher() {//指定密码算法HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestUtil.SHA1);//指定迭代次数hashedCredentialsMatcher.setHashIterations(DigestUtil.Counts);//生效密码比较器setCredentialsMatcher(hashedCredentialsMatcher);}
}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.获取登录的用户名密码(token)UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;String username = token.getUsername();//2.根据用户名查询数据库User user  = service.findByName(username);//3.判断用户是否存在或者密码是否一致if(user==null){throw new UnknownAccountException("账户不存在");}//4.如果一致返回安全数据//通过SimpleAuthenticationInfo校验数据//构造方法:安全数据,密码(匿名),混淆字符串(salt),realm域名return new SimpleAuthenticationInfo(user.getId(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),"MyRealm");}

2.创建shiro配置类

shiro配置类需要配置八个步骤,比较繁琐,最重要的是shiroFilter过滤器,用于实现非法请求的处理

@Configuration
public class ShiroConfiguration {/*** 1.创建shiro自带cookie对象*/@Beanpublic SimpleCookie sessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("ShiroSession");return simpleCookie;}//2.创建realm@Beanpublic MyRealm getRealm() {return new MyRealm();}/*** 3.创建会话管理器*/@Beanpublic DefaultWebSessionManager sessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionValidationSchedulerEnabled(false);sessionManager.setSessionIdCookieEnabled(true);sessionManager.setSessionIdCookie(sessionIdCookie());sessionManager.setGlobalSessionTimeout(3600000);return sessionManager;}//4.创建安全管理器@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(getRealm());securityManager.setSessionManager(sessionManager());return securityManager;}/*** 5.保证实现了Shiro内部lifecycle函数的bean执行*/@Bean(name = "lifecycleBeanPostProcessor")public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 6.开启对shiro注解的支持*   AOP式方法级权限检查*/@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验*/@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());return authorizationAttributeSourceAdvisor;}//8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制@Beanpublic ShiroFilterFactoryBean shiroFilter() {//1.创建过滤器工厂ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();//2.设置安全管理器filterFactory.setSecurityManager(defaultWebSecurityManager());//3.通用配置(跳转登录页面,为授权跳转的页面)filterFactory.setLoginUrl("/autherror");//跳转url地址//4.设置过滤器集合//key = 拦截的url地址//value = 过滤器类型Map<String,String> filterMap = new LinkedHashMap<>();//key:请求规则   value:过滤器名称filterMap.put("/login","anon");//当前请求地址可以匿名访问filterMap.put("/user/**","authc");//当前请求地址必须认证之后可以访问//在过滤器工程内设置系统过滤器filterFactory.setFilterChainDefinitionMap(filterMap);return filterFactory;}
}

3.Postman测试

成功:
在这里插入图片描述
合法请求资源:
在这里插入图片描述

失败:
在这里插入图片描述
非法请求资源:
在这里插入图片描述


四、springBoot+shiro授权,鉴权

1.重写授权方法doGetAuthenticationInfo

授权方法:
操作的时候,判断用户是否具有响应的权限
一定先认证再授权
先认证 – 安全数据
再授权 – 根据安全数据获取用户具有的所有操作权限

//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//1.获取已认证的用户数据String id1 = (String) principalCollection.getPrimaryPrincipal();int i = Integer.parseInt(id1);User user = service.findUserDetailById(i);//2.根据用户数据获取用户的权限信息(所有角色,所有权限)Set<String> roles = new HashSet<>();//所有角色Set<String> perms = new HashSet<>();//所有权限for (Role role : user.getRoles()) {roles.add(role.getName());for (Permission perm : role.getPermissions()) {perms.add(perm.getCode());}}//将角色和权限信息返回SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.setStringPermissions(perms);info.setRoles(roles);return info;}

2.访问程序资源(鉴权)

注解实现:直接在控制器接口上加注解即可;
注解实现权限:如果权限信息不匹配,抛出异常(则使用异常处理器解决);
常用注解:
@RequiresPermissions – 访问此方法必须具备的权限
@RequiresRoles – 访问此方法必须具备的角色
@RequiresAuthentication – 表明当前用户需是经过认证的用户
@ RequiresGuest --表明该用户需为”guest”用户
@ RequiresUser – 当前用户需为已认证用户或已记住用户

具体实现在controller层的每个业务接口,这里只举例一个:

	//个人主页@RequiresPermissions("user-home")@RequestMapping(value = "/user/home")public String home() {return "访问个人主页成功";}@RequiresPermissions("user-add")//参数:对应权限的code值@RequestMapping(value = "/user",method = RequestMethod.POST)public String add() {return "添加用户成功";}

3.全局异常处理器

专门用于处理权限不足的异常信息:

@ControllerAdvice
public class BaseExceptionHandler {@ExceptionHandler(value = AuthorizationException.class)@ResponseBodypublic String error(HttpServletRequest request, HttpServletResponse response, AuthorizationException e) {return "未授权-异常处理器实现";}
}

4.Postman测试

张三丰用户只有user-home权限,没有add权限;

1.直接访问权限方法会被拦截做登录:
在这里插入图片描述
2.访问有权限的资源
成功
在这里插入图片描述
3.访问没有权限的资源
失败,被全局异常处理器处理。
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/66621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

财报解读:迈向高端化,珍酒李渡如何持续讲好品牌故事?

2023年上半年&#xff0c;尤其是第二季度&#xff0c;白酒行业淡季属性较为明显。对于市场情况&#xff0c;中国酒业协会《2023中国白酒市场中期研究报告》也有所披露&#xff1a;约40.91%的受访者反馈春节后平日的白酒消费量有所减少&#xff0c;约31.82%的受访者反馈五一期间…

python调用git出错:ImportError: Failed to initialize: Bad git executable.

报错信息 #报错信息 Traceback (most recent call last): File “”, line 1, in File “C:\Python27\lib\site-packages\git_init_.py”, line 85, in raise ImportError(‘Failed to initialize: {0}’.format(exc)) ImportError: Failed to initialize: Bad git executab…

锂电池充电电路方案

锂电池充电电路一 原理图如下 都是比较小的&#xff0c;SOT-23-6 封装 此方案的优势是器件可以扩容&#xff0c;也就是可以替换成容量更大的mos管。 锂电池充电电路二 锂电池充电电路三 注意线的粗细。 引脚说明 锂电池电量检测电路 键盘上的电量检测电路原理图 电量检…

Flutter状态管理 — 探索Flutter中的状态

前言 随着响应式编程的理念&Flutter被大众所了解以来&#xff0c;状态管理一直是一个引人深思的话题。如果想要学习好Flutter这样的响应式的编程框架就一定是离不开状态管理的。我遇到过很多没有了解过响应式编程框架的&#xff0c;或者从事后端开发&#xff0c;自己想用F…

国标GB28181视频平台EasyGBS国标视频云平台级联到EasyCVR,上级平台无法播放通道视频的问题解决方案

EasyGBS国标视频云平台是基于国标GB28181协议的视频能力兼服务平台&#xff0c;可实现的视频能力包括将设备通过国标GB28181协议接入、流媒体转码、处理及分发、直播录像、语音对讲、云存储、告警、平台级联等功能。其中&#xff0c;平台级联功能是指平台与平台之间可以通过国标…

计算机竞赛 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

文章目录 0 简介1 二维码检测2 算法实现流程3 特征提取4 特征分类5 后处理6 代码实现5 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖&#xff0c;适合作为竞赛课…

解决npm install报错: No module named gyp

今天运行一个以前vue项目&#xff0c;启动时报错如下&#xff1a; ERROR Failed to compile with 1 error上午10:19:33 error in ./src/App.vue?vue&typestyle&index0&langscss& Syntax Error: Error: Missing binding D:\javacode\Springboot-MiMall-RSA\V…

#include <graphics.h> #include <conio.h> #include<stdlib.h>无法打开源文件解决方案

一、问题描述 学习数据结构链表的过程中&#xff0c;在编写漫天星星闪烁的代码时&#xff0c;遇到了如下图所示的报错&#xff0c;#include <graphics.h> 、 #include <conio.h> 等无法打开源文件。 并且主程序中initgraph(初始化画布)、setfillcolor&#xff08;…

pdf转换成图片免费软件用哪个?pdf转换成图片就用它

随着技术的发展&#xff0c;现在企业办公运用到的电子文档各种各样&#xff0c;我们日常需要掌握的技能越来越高要求&#xff0c;其中pdf和图片是我们经常接触的文件格式之一&#xff0c;而且这两个文件格式我们会经常将它们进行转换&#xff0c;那么pdf转换成图片怎么操作呢?…

Qt +VTK+Cmake 编译和环境配置(第一篇 采坑)

VTK下载地址&#xff1a;https://vtk.org/download/ cmake下载地址&#xff1a;https://cmake.org/download/ 版本对应方面&#xff0c;如果你的项目对版本没有要求&#xff0c;就不用在意。我就是自己随机搭建的&#xff0c;VTK选择最新版本吧&#xff0c;如果后面其他的库不…

iPhone 隔空投送使用指南:详细教程

本文介绍了如何在iPhone上使用隔空投送,包括如何在iOS 11到iOS 14的iPhone上启用它、发送文件以及接受或拒绝AirDrop发送给你的文件。对于iOS 7以上的旧款iPhone,提供了另一种方法。 如何打开隔空投送 你可以通过以下两种方式之一启动隔空投送功能:在“设置”应用程序或控…

1、[春秋云镜]CVE-2022-32991

文章目录 一、相关信息二、解题思路&#xff08;手注&#xff09;三、通关思路&#xff08;sqlmap&#xff09; 一、相关信息 靶场提示&#xff1a;该CMS的welcome.php中存在SQL注入攻击。 NVD关于漏洞的描述&#xff1a; 注入点不仅在eid处&#xff01;&#xff01;&#xff…

uni-app+uView实现点击查看大图片的效果

<u-button text"月落" click"imgPreview()"></u-button> //注意&#xff1a;参数urls 是预览图片的链接地址&#xff0c;是个数组 imgPreview() {uni.previewImage({indicator: "none",loop: false,urls: []&#xff0c;}) },参数说…

Python爬虫抓取经过JS加密的API数据的实现步骤

随着互联网的快速发展&#xff0c;越来越多的网站和应用程序提供了API接口&#xff0c;方便开发者获取数据。然而&#xff0c;为了保护数据的安全性和防止漏洞&#xff0c;一些API接口采用了JS加密技术这种加密技术使得数据在传输过程中更加安全&#xff0c;但也给爬虫开发带来…

【前端demo】倒计时器 可选择时间 原生实现

文章目录 效果过程日历与获取时间居中背景与字计时器清空计时器 代码HTMLCSSJS 其他demo 效果 效果预览&#xff1a;倒计时器 可选择时间 (codepen.io) 参考&#xff1a; Simple Clock/Countdown timer (codepen.io) 前端页面实现倒计时效果的几种方法_前端倒计时__Boboy的…

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 目录 Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 一、简单介绍 二、注意事项 三、环境搭建 git 下载和安装 python 下载和安装 stable-diffusion-webui 下载和安装 测试 stable diffuse w…

智慧水产养殖方案,守护养殖水产品安全!

水产品在人们的饮食文化中占据着举足轻重的地位&#xff0c;更是人们摄入蛋白质的重要来源。因此&#xff0c;保障食品安全&#xff0c;提升养殖水产品的品质至关重要然。而传统的人工观察水产养殖方式较为单一&#xff0c;难以及时发现水质问题和投喂情况&#xff0c;容易导致…

Flink+Paimon多流拼接性能优化实战

目录 &#xff08;零&#xff09;本文简介 意外收获&#xff1a; &#xff08;一&#xff09;背景 &#xff08;二&#xff09;探索梳理过程 &#xff08;三&#xff09;源码改造 &#xff08;四&#xff09;修改效果 1、JOB状态 2、Level5的dataFile总大小 3、数据延…

STM32定时器定时及其应用

STM32定时器定时及其应用 定时器概述☆定时器相关配置CubeMX工程配置及程序实现固件库程序设计及实现 定时器概述 1. 工作原理 使用精准的时基&#xff0c;通过硬件的方式&#xff0c;实现定时功能。定时器核心就是计数器 2. 定时器分类   基本定时器&#xff08;TIM6~TIM7…