使用shiroshiro整合其他组件

news2024/11/14 4:10:45

什么是shiro?

一款apache公司出品的Java安全框架,主要用于设计针对应用程序的保护,使用shiro可以完成认证、授权、加密、会话管理等。保证系统稳定性、数据安全性

优势:易于使用、易于理解、兼容性强(可以与其他框架集成)

什么是认证?

认证是指身份认证,即判断该用户身份是否合法是否符合规定的处理过程。比如用户登录:根据用户提供的用户名和密码与系统中存储的是否一致

shiro与SpringSecurity

Spring Security基于spring框架开发,上手难度更大一些,需要的配置文件也较复杂。但是SpringSecurity搭配spring框架更加灵活。而使用shiro则需要与spring框架进行整合

在功能性方面,SpringSecurity要比shiro更加丰富,功能更加强大。但是shiro易于理解,上手速度快,不依赖于任何框架和容器。因为有良好的兼容性,可以与不同的框架整合开发

导入依赖资源

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.9.0</version>
</dependency>
<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.2</version>
</dependency>

shiro功能了解

在这里插入图片描述

如上图所示,shiro支持认证、授权、会话管理、加密操作,以及对web开发的支持

Caching缓存(用户通过验证后,将其信息与权限存入缓存,避免每次都操作数据库
Testing支持对test单元测试的操作
Run As 允许一个用户用另一个用户的身份登录
Remember Me 记住我,一次登录下次可以直接进入
Concurrency支持对并发验证,可以通过线程将权限传播

shiro核心组件

subject主体:subject记录了当前进行操作的用户,外部程序通过subject进行相关校验和认证授权等,而subject是通过SecurityManager安全管理器进行认证授权

SecurityManager安全管理器:对外部subject进行安全管理,SecurityManager针对subject进行认证、授权等擦欧总,但是SecurityManager通过认证器Authenticator进行认证,通过Authorizer授权器控制授权

Authenticator认证器对用户身份进行认证

Authorizer授权器,用户认证通过后所执行的某些操作需要通过授权器授权才会获得执行权

Realm用户域,securityManager对用户进行安全认证时需要获取用户数据,如果数据在数据库那么realm就会去数据库中访问该用户数据从而执行校验。可以把realm理解为一个数据源,但是realm不仅仅是一个数据源,它还包含了一些认证授权的操作

简单实现shrio登录验证

创建普通maven项目,导入上述依赖资源。利用ini存放一些简单数据供测试使用

[users]
zhangsan=z3,role1,role2
lisi=l4
[roles]
role1=user:insert,user:select

编写测试类:

{
  // 1. 获取安全管理实例 
  // 该方法已经被废弃,此处用作演示使用
  IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
  SecurityManager securityManager = factory.getInstance();
  SecurityUtils.setSecurityManager(securityManager);
  // 2. 获取subject
  Subject subject = SecurityUtils.getSubject();
  // 3. 创建token对象
  AuthenticationToken token = new UsernamePasswordToken("zhangsan","z3");
  // 4. 完成登录
  try {
    subject.login(token);
    System.out.println("登陆成功!");
    // 5.  判断角色
    boolean hasRole = subject.hasRole("role1");
    System.out.println("该角色是否存在="+hasRole);
    // 6. 判断权限
    boolean permitted = subject.isPermitted("user:insert");
    System.out.println("是否拥有此权限="+permitted);
  } catch (IncorrectCredentialsException e) {
    e.printStackTrace();
    System.out.println("密码错误");
  } catch (UnknownAccountException e) {
    e.printStackTrace();
    System.out.println("用户不存在");
  } catch (AuthenticationException e) {
    e.printStackTrace();
  }
}

shiro加密

shiro提供了多种不同的加密算法来对用户信息进行加密,同样的加密方式也有多种。比如利用MD5类进行加密,那么通过MD5不同的构造器就可以实现不同的加密方式以及迭代加密次数

String pwd = "z3";
// 使用shrio提供方法加密
Md5Hash md5Hash = new Md5Hash(pwd);
System.out.println("简单加密="+md5Hash.toHex());
// 密码拼接后加密  添加干扰信息
Md5Hash md5Hash1 = new Md5Hash(pwd,"ppt");
System.out.println("干扰加密="+md5Hash1.toHex());
// 也可以继续进行迭代加密
Md5Hash md5Hash2 = new Md5Hash(pwd, "salt", 3);
System.out.println("迭代加密="+md5Hash2.toHex());
// 使用父类加密
SimpleHash simpleHash = new SimpleHash("MD5",pwd,"pilipala",3);
System.out.println("父类加密="+simpleHash.toHex());

shiro自定义登录认证

shiro提供的登录认证默认是不带有加密操作的,如果需要加密则需要开发时自定义认证操作

  1. 继承AuthenticatingRealm类,并且实现doGetAuthenticationInfo方法,有一个参数AuthenticationToken身份验证令牌,该令牌会拥有用户的realm信息,可以通过它获取用户输入的账号和密码
  2. 查询数据库中对应用户输入用户名的信息,存在该用户名则获取其密码,不存在直接返回null表示用户不存在
  3. 获取到数据库中信息之后,将用户名、数据库获取的加密后密码、干扰信息“盐”、用户名string类型封装给AuthenticationInfo身份验证信息对象
  4. 然后在底层做出判断

ini文件

# shiro加密配置器
[main]
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations=3

myrealm=com.yuqu.test.MyRealm
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm

[users]
zhangsan=09d772642c9848153b119fc016580411,role1,role2
lisi=l4
[roles]
role1=user:insert,user:select

自定义MyRealm类

{
  // 1. 获取身份信息
  String principal = token.getPrincipal().toString();
  System.out.println("用户信息="+principal);
  System.out.println("tokrn.getPrincipal="+token.getPrincipal());
  // 2. 获取凭证信息  比如  密码
  String pwd = new String((char[]) token.getCredentials());
  System.out.println("token.getCredentials()="+new String((char[]) token.getCredentials()));
  // 3. 访问数据库获取该用户所存储的信息
  if (principal.equals("zhangsan")){
    // 数据库中存储的加密后的密码
    String pwdSql = "09d772642c9848153b119fc016580411";
    // 4. 信息封装给校验逻辑对象 返回封装数据
    AuthenticationInfo info = new SimpleAuthenticationInfo(
      token.getPrincipal(), // 用户输入的用户名
      pwdSql,   // 数据库拿到的加密后密码
      ByteSource.Util.bytes("pilipala"),// 干扰信息
      token.getPrincipal().toString()
    );
    // 可以发现用户输入的密码z3没有封装过去,
    // 所以我盲猜底层实现是将数据库中加密后的密码进行恢复然后再比较
    System.out.println("干扰信息="+ByteSource.Util.bytes("pilipala"));
    return info;
  }
  return null;
}

自定义realm类需要继承AuthorizingRealm类,然后实现两个doGet方法

  1. doGetAuthenticationInfo读写身份验证信息
  2. doGetAuthorizationInfo读写授权信息

上述示例仅展示读写身份验证信息

测试类

{
  // 1. 获取安全管理实例
  IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
  SecurityManager securityManager = factory.getInstance();
  SecurityUtils.setSecurityManager(securityManager);
  // 2. 获取subject
  Subject subject = SecurityUtils.getSubject();
  // 3. 创建token对象
  AuthenticationToken token = new UsernamePasswordToken("zhangsan","z3");
  // 4. 完成登录
  try {
    subject.login(token);
    System.out.println("登陆成功!");
  } catch (IncorrectCredentialsException e) {
    e.printStackTrace();
    System.out.println("密码错误");
  } catch (UnknownAccountException e) {
    e.printStackTrace();
    System.out.println("用户不存在");
  } catch (AuthenticationException e) {
    e.printStackTrace();
  }
}

通过上述示例,有一点值得注意:在封装身份验证信息时并未将用户输入的密码也就是加密之前的密码封装过去,但是封装了加密之后的信息。所以我盲猜底层是获取了数据库中加密的数据进行解密后对比,得空了看看源码到底是不是

分析一下执行过程:

首先获取到用户的输入,并将用户输入的信息封装为身份验证令牌也就是AuthenticationToken,然后通过subject主体调用login方法,并将该令牌入参。由此开始执行我们的自定义realm登录认证。

首先在ini文件中已经配置好了认证配置信息比如自定义realm类的未知,加密方式以及迭代次数。回到realm类,doGetAuthenticationInfo方法由底层自动调用,其形参就是我们先前传入的令牌,通过令牌获取用户输入的用户名密码等信息,然后通过用户名进入数据库进行查找,找不到就返回null表示该用户不存在。找到之后就获取其密码,最后将数据库中获取的密码以及用户输入的用户名和干扰信息也就是盐共同封装给身份验证信息对象并返回。

shiro授权

自定义realm类实现的doGetAuthorizationInfo读写授权信息方法

// doGetAuthorizationInfo 读写授权信息
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String principal = (String) principals.getPrimaryPrincipal();// 获取用户名
// 查询数据库 该用户都具备什么权限
List<String> permissions  = new ArrayList<String>();
permissions .add("user:insert");
permissions .add("user:select");
// 权限交给校验逻辑对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addStringPermissions(permissions);
return authorizationInfo;
}

测试

// 6. 判断权限
boolean permitted = subject.isPermitted("user:insert");
System.out.println("是否拥有insert权限="+permitted);

shiro整合SpringBoot+MyBatis+Druid数据源

导入shiro支持的springBoot依赖

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.8.0</version>
</dependency>

在application.yaml文件中配置mybatis和Druid

spring:
  thymeleaf:
    cache: false
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/sqltest?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
    # springBoot默认不会配置以下属性值  需要手动绑定
    # druid 数据源专有配置
    initial-size: 5
    min-idle: 5
    max-active: 20
    max-wait: 60000
    time-between-eviction-runs-millis: 60000
    min-evictable-idle-time-millis: 300000
    validation-query: SELECT 1 FROM DUAL
    test-while-idle: true
    test-on-borrow: false
    test-on-return: false
    pool-prepared-statements: true
    #配置监控统计拦截的filters stat:监控统计、log4j日志记录  wall防御sql注入
    filters: stat,wall,log4j
    max-pool-prepared-statement-per-connection-size: 20
    use-global-data-source-stat: true
    connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis:
  type-aliases-package: com.yuqu.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml

编写controller层

@RequestMapping("/login")
public String loginProcess(String username,String password,Model model){
  System.out.println("获取到前端传回的账号密码=="+username+"------"+password);
  // 获取当前用户
  Subject subject = SecurityUtils.getSubject();
  // 加密
  // Md5Hash md5Hash = new Md5Hash(password);
  // System.out.println("加密后的密码="+md5Hash.toHex());
  // 获取用户信息
  UsernamePasswordToken token = new UsernamePasswordToken(username,password);
  token.setRememberMe(true);
  try {
    // 登录
    subject.login(token);
    System.out.println("登陆成功!");
    return "/index";
  } catch (IncorrectCredentialsException e) {
    e.printStackTrace();
    System.out.println("密码错误");
    model.addAttribute("message","密码错误");
    return "login";
  } catch (UnknownAccountException e) {
    e.printStackTrace();
    System.out.println("用户不存在");
    model.addAttribute("message", "用户不存在");
    return "login";
  }
}

controller层获取用户subject后调用登录方法会走我们自定义的realm用户域进行认证和授权,此处只展示认证操作

自定义UserRealm

// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  System.out.println("经过用户认证----------");
  Books books = bookService.selectBookByName(token.getPrincipal().toString());
  if (books.getBookName().equals(token.getPrincipal().toString())){
    // 用户名存在  校验密码
    return new SimpleAuthenticationInfo("",books.getBookCounts().toString(),"");
  }
  return null;
}

我这里使用的是之前的Book表,bookName作为用户名,bookCounts作为密码

shiro整合thymeleaf

导入依赖

<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
  <groupId>com.github.theborakompanioni</groupId>
  <artifactId>thymeleaf-extras-shiro</artifactId>
  <version>2.0.0</version>
</dependency>

在视图上配置命名空间

xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"

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

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

相关文章

SE-SSD论文阅读

摘要 本文提出了一种基于自集成单级目标检测器(SE-SSD)的室外点云三维目标检测方法。我们的重点是利用我们的公式约束开发软目标和硬目标来联合优化模型&#xff0c;而不引入额外的计算在推理中。具体来说&#xff0c;SE-SSD包含一对teacher 和student ssd&#xff0c;在其中我…

Mac 安装 Java 反编译工具 JD-GUI

Mac 安装 Java 反编译工具 JD-GUI JD-GUI 是一款 Java 反编译工具&#xff0c;可以方便的将编译好的 .class 文件反编译为 .java 源码文件&#xff0c;用于开发调试、源码学习等。 官网地址&#xff1a;http://java-decompiler.github.io Git 地址&#xff1a;https://github…

直播美颜sdk是什么?它是怎么让用户”变美“的?

如今&#xff0c;直播美颜sdk、手机摄影、短视频以及社交软件的盛行&#xff0c;让“拍照”成为人们日常生活中不可或缺的一部分。随着直播美颜sdk技术的不断升级&#xff0c;手机摄影的质量也越来越高。有统计数据显示&#xff0c;2018年中国智能手机用户已经达到了7亿人&…

美国最新调查显示 50% 企业已在用 ChatGPT,其中 48% 已让其代替员工,你怎么看?

美国企业开始使用ChatGPT&#xff0c;我认为这不是什么新闻。 如果美国的企业现在还不使用ChatGPT&#xff0c;那才是个大新闻。 据新闻源显示&#xff0c;已经使用chatGPT的企业中&#xff0c;48%已经让其代替员工工作。 ChatGPT的具体职责包括&#xff1a;客服、代码编写、招…

HTB-remote

HTB-remote信息搜集开机提权信息搜集 nmap 较为感兴趣的端口&#xff1a; 2180nfs 首先尝试21端口&#xff0c;可以看到并没有文件在ftp服务器里面&#xff0c;而且也无法上传文件。 80端口。 在contact里面找到了能够登录的网站。 经过简单的测试发现可能不存在sql注…

逆向、安全、工具集

0、安卓逆向环境 r0env 原味镜像介绍文章&#xff1a;https://mp.weixin.qq.com/s/gBdcaAx8EInRXPUGeJ5ljQ 原味镜像介绍视频&#xff1a;https://www.bilibili.com/video/BV1qQ4y1R7wW/ 百度盘&#xff1a;链接:https://pan.baidu.com/s/1anvG0Ol_qICt8u7q5_eQJw 提取码:3x2a …

【Spring源码】Spring AOP的核心概念

废话版什么是AOP关于什么是AOP&#xff0c;这里还是要简单介绍下AOP&#xff0c;Aspect Oriented Programming&#xff0c;面向切面编程&#xff0c;通过预编译和运行期间提供动态代理的方式实现程序功能的统一维护&#xff0c;使用AOP可以降低各个部分的耦合度&#xff0c;提高…

openfeign负载均衡策略 | Spring Cloud 5

一、Spring Cloud LoadBalancer介绍 Spring Cloud LoadBalancer是Spring Cloud官网提供的一个客户端负载均衡器&#xff0c;功能类似于Ribbon。在Spring Cloud Nacos 2021移除了中Ribbon组件&#xff0c;Spring Cloud在Spring Cloud Commons项目中&#xff0c;添加了Spring Cl…

华为OD机试题,用 Java 解【N 进制减法】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

Linux | 分布式版本控制工具Git【版本管理 + 远程仓库克隆】

文章目录一、前言二、有关git的相关历史介绍三、Git版本管理1、感性理解 —— 大学生实验报告2、程序员与产品经理3、张三的CEO之路 —— 版本管理工具的诞生四、如何在Linux上使用Git1、创建仓库2、将仓库克隆到本地3、git三板斧① git add② git commit③ git push4、有关git…

yarn run serve报错Error: Cannot find module ‘@vue/cli-plugin-babel‘ 的解决办法

问题概述 关于这个问题&#xff0c;是在构建前端工程的时候遇到的&#xff0c;项目构建完成后&#xff0c;“yarn run serve”启动项目时&#xff0c;出现的问题&#xff1a;“ Error: Cannot find module ‘vue/cli-plugin-babel‘ ” 如下图&#xff1a; 具体信息如下&…

(24秋招笔试准备)回溯专题--代码随想录刷题记录

回溯算法理论基础回溯三部曲&#xff1a;编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;组合问题https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ组合总和https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3whttps://mp.weixin.qq.com/…

Linux系统认知——驱动认知

文章目录一、驱动相关概念1.什么是驱动2.被驱动设备分类3.设备文件的主设备号和次设备号4.设备驱动整体调用过程二、基于框架编写驱动代码1.驱动代码框架2.驱动代码的编译和测试三、树莓派I/O口驱动的编写1.微机的总线地址、物理地址、虚拟地址介绍2.通过树莓派芯片手册确定需要…

zabbix部署

文章目录前言一、zabbix简介二、zabbix下载与部署三、部署完成、访问前端测试前言 一、zabbix简介 Zabbix 是一个企业级分布式开源监控解决方案。Zabbix 软件能够监控众多网络参数和服务器的健康度、完整性。Zabbix 使用灵活的告警机制&#xff0c;允许用户为几乎任何事件配置…

数据结构与算法——4时间复杂度分析(常见的大O阶)

这篇文章是时间复杂度分析的第二篇。在前一篇文章中&#xff0c;我们从0推导出了为什么要用时间复杂度&#xff0c;时间复杂度如何分析以及时间复杂度的表示三部分内容。这篇文章&#xff0c;是对一些常用的时间复杂度进行一个总结&#xff0c;相当于是一个小结论 1.常见的大O…

【LeetCode】剑指 Offer(11)

目录 题目&#xff1a;剑指 Offer 29. 顺时针打印矩阵 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;剑指 Offer 29. 顺时针…

西电计算机通信与网络(计网)简答题计算题核心考点汇总(期末真题+核心考点)

文章目录前言一、简答计算题真题概览二、网桥&#xff0c;交换机和路由器三、ARQ协议四、曼彻斯特编码和差分曼彻斯特编码五、CRC六、ARP协议七、LAN相关协议计算前言 主要针对西安电子科技大学《计算机通信与网络》的核心考点进行汇总&#xff0c;包含总共26章的核心简答。 【…

华为OD机试模拟题 用 C++ 实现 - 自动曝光(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 最多获得的短信条数(2023.Q1)) 文章目录 最近更新的博客使用说明自动曝光题目输入输出描述示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出࿰

Ubuntu搭建maven私服

1.安装JDK8 已经是JDK8的需要配置环境变量&#xff0c;如果是更高版本的JDK则需要修改nexus配置文件 2.下载nexus安装包 百度网盘下载&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1DfKqql8tZNQXEBxAEH7UyA 提取码&#xff1a;hx4p安装到有磁盘的目录如下所示&…

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——Join多种应用

3.7.1Reduce Join 1、工作原理 Map端的主要工作&#xff1a;为来自不同表或文件的key/value对&#xff0c;打标签以区别不同来源的记录。然后用连接字段作为key&#xff0c;其余部分和新加的标志作为value&#xff0c;最后进行输出。 Reduce端的主要工作&#xff1a;在Reduc…