你真的了解Shiro框架吗?

news2024/11/22 11:44:18

关注公众号回复20231110获取最新网络安全以及内网渗透等资料。

在这里插入图片描述

文章目录

    • 关注公众号回复20231110获取最新网络安全以及内网渗透等资料。
    • Shiro的核心架构
    • Shiro中的认证
      • 认证
      • shiro中认证的关键对象
    • 认证流程
    • 调试认证流程
    • Shiro的加密过程
    • Shiro中的解密过程
      • 总结

Shiro的核心架构

在这里插入图片描述

Shiro中的认证

认证

身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。

shiro中认证的关键对象

  • Subject:主体

访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体; ****

  • Principal:身份信息

是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。

  • credential:凭证信息

是只有主体自己知道的安全信息,如密码、证书等。

认证流程

在这里插入图片描述

调试认证流程

//1.创建安全管理器对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();


//2.给安全管理器设置realm
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

//3.SecurityUtils 给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);

//4.关键对象 subject主体
Subject subject = SecurityUtils.getSubject();

//5.去创建令牌
UsernamePasswordToken token = new UsernamePasswordToken("123","123456");


try {
    System.out.println("认证状态:" + subject.isAuthenticated());

    subject.login(token); //用户认证
    System.out.println("登录成功");
    System.out.println("认证状态:" + subject.isAuthenticated());
}catch (UnknownAccountException e){
    System.out.println("用户名不存在");
}catch (IncorrectCredentialsException e){
    System.out.println("密码错误");
}


在subject.login这一行代码打上断点然后我们开始进行调试

可以看到他调用securityManager的login方法 传进去两个参数第一个参数是this 代表当前类对象 第二个token就是我们传进去的AuthenticationToken 就是我们由身份信息和凭证信息组成的令牌 其实我们表面执行的是subject.login方法 其实他底层执行的还是securityManager.login方法 就是我们安全管理器
在这里插入图片描述
继续跟进login方法

可以看到这里调用了authenticate方法 将我们token传进去了 这个方法要么在我们的本类 或者在我们的父类 我们跟进去
在这里插入图片描述

可以看到他调用了父类的authenticate方法
在这里插入图片描述
在这里插入图片描述
我们继续跟进去 来到AbstractAuthenticator的authenticate方法

他上线先去判断我们的令牌是否是null 如果是null直接抛出异常 接着去调用dodoAuthenticate方法 把我们的令牌传进去
在这里插入图片描述
此时来到了ModularRealmAuthenticator类的doAuthenticate方法

首先执行assertRealmsConfigured方法 我们的realm是否配置 我们是在shiro.ini文件是配置过的

然后调用getRealms方法 拿到我们的所有域 然后进行判断 因为我们的size肯定是等于1

然后我们进去doSingleRealmAuthentication方法
在这里插入图片描述
此时来到doSingleRealmAuthentication方法

首先上来先去判断你的realm是否支持token

紧接着调用了realm的getAuthenticationInfo方法 我们跟进去

在这里插入图片描述
来到getAuthenticationInfo方法

这里首先从我们的缓存中去拿数据 因为我们是第一次访问 缓存中肯定是没有数据的 所以肯定是null

所以我们进入if判断

进入doGetAuthenticationInfo方法
在这里插入图片描述
来到SimpleAccountRealm类的doGetAuthenticationInfo方法

这里没有进行循环调用

首先把我们的token取出 然后强制转换为UsernamePasswordToken

接着调用getUser方法 传进去我们token中的用户名 也就是说根据我们token中的用户名去拿用户
在这里插入图片描述
我们跟进进去

首先调用upToken.getUsername()方法 从我们的token中提取到用户名 然后调用getUser方法

这里的this.users 其实就是我们在shiro.ini文件中配置的几个user

这里调用get方法去拿这个用户 如果拿到了就返回SimpleAccount

我们返回
在这里插入图片描述

接着我们返回来 接着判断我们的account是不是空的 我们刚在token中给的用户名是不存在的 所以他自然而然也就为空了 最后进行返回


![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/e2198c16ddb44187abe0dcd8596235fe.png) 小总结:

其实最后调用了这么多方法 最后执行用户名比较 其实是在SimpleAccountRealm类的doGetAuthenticationInfo方法完成了用户名的校验


我们继续往回走继续来到getAuthenticationInfo方法

这里可以看到判断token如果不为空 并且 info也不为空的话 给他放入缓存

之后进行判断如果info不为空的话 调用assertCredentialsMatch方法 将我们的token和info传进去
在这里插入图片描述
我们跟进去assertCredentialsMatch方法

首先拿到了密码匹配器

接着判断我们的密码匹配器是否为空 如果不为空过的话 那么调用密码匹配器的方法去校验

可以看到下面 如果不匹配的话 他会抛异常为IncorrectCredentialsException
在这里插入图片描述
我们跟进去doCredentialsMatch方法

可以看到这里调用了getCredentials方法 将我们的token 以及 info信息传递进去 然后进行equals比较 然后返回

这里是因为我们没有涉及到任何加密 所以使用equals进行比较
在这里插入图片描述

Shiro的加密过程

看以下图:

当我们去登录之后 去访问account page的时候 他会在cookie中带上我们的rememberMe字段 我们主要看他这里是怎么加密的
在这里插入图片描述
经过我们上面说过的他其实是调用了securityManager的login方法 其实最后就是调用了我们的安全管理器里面的login方法

然后他又调用了DefaultSecurityManager的login方法
在这里插入图片描述
我们在这个类中搜索一下有没有rememberMe之类方法

在DefaultSecurityManager类中的rememberMeSuccessfulLogin方法 是对我们rememberMe字段的一些操作

我们现在去点击login去登录 然后debug运行 下断点到这里

在这里插入图片描述
首先他会通过getRememberMeManager方法 获取到RememberMe

然后进行if判断是否为空 如果不为空的话 那么就进入onSuccessfulLogin方法 将我们的token和info 传递进去
在这里插入图片描述
我们跟进去这个方法

可以看到来到了AbstractRememberMeManager类的onSuccessfulLogin方法

这里首先会清除我们的认证信息,然后通过isRememberMe方法 进行判断我们的token中是否有认证信息,

如果有认证信息 那么就进入rememberIdentity方法 我们跟进去
在这里插入图片描述
来到rememberIdentity方法

首先他通过getIdentityToRemember方法 获取到我们token中的用户身份

其实就是我们上面写的这行代码 就是我们的令牌 只是上面的代码时通过shiro.ini文件去拿到域中的 也可以通过数据库之类的

UsernamePasswordToken token = new UsernamePasswordToken("123","123456");

然后我们继续进入rememberIdentity方法
在这里插入图片描述
来到rememberIdentity方法

这里是通过我们的convertPrincipalsToBytes方法 将我们的用户身份 就是我们token中存储的用户身份 也就是用户名 转为byte字节格式

我们跟进去convertPrincipalsToBytes方法
在这里插入图片描述
来到convertPrincipalsToBytes方法

这里首先会将我们的转换为byte字节后的用户身份进行序列化

然后再通过encrypt方法进行加密 我们跟进去在这里插入图片描述
我们来到encrypt方法

这里会通过getCipherService方法获取到密码管理器 然后调用密码管理器的encrypt方法通过密钥进行AES加密

Shiro中有很多加密方式 比如我们常见的md5 salt 散列等等

这里的密钥是通过getEncryptionCipherKey方法获取到的

将我们转换为byte字节后的用户身份(也就是我们的root) 以及序列化之后 然后通过密钥进行AES加密
在这里插入图片描述
我们跟进去getEncryptionCipherKey方法

可以看到他是返回一个encryptionCipherKey 我们看到他是一个属性 类型是byte数组 我们去看哪里对encryptionCipherKey属性进行了赋值
在这里插入图片描述
我们可以看到 这里通过setEncryptionCipherKey方法对encryptionCipherKey属性进行了赋值 我们去看哪里调用了setEncryptionCipherKey方法
在这里插入图片描述
我们来到这里 setCipherKey调用了setEncryptionCipherKey方法 进行了赋值 我们继续找哪里调用了setCipherKey

因为现在这个值我们不知道是多少 所以需要继续往前找
在这里插入图片描述
我们可以清楚的看到 这里通过我们的构造器对encryptionCipherKey进行了赋值

DEFAULT_CIPHER_KEY_BYTES 就是我们的key 我们点进去查看
在这里插入图片描述
可以看到 他的key值是写死的
在这里插入图片描述
convertPrincipalsToBytes方法加密完之后我们进行返回

来到rememberSerializedIdentity方法 我们跟进去
在这里插入图片描述
最后通过Base64编码之后 设置到cookie中
在这里插入图片描述

Shiro中的解密过程

我们来到DefaultSecurityManager类的getRememberedIdentity方法

首先获取到rememberMe 然后进行判断 是否等于空 如果不等于空的话 调用getRememberedPrincipals解密方法

我们跟进去
在这里插入图片描述
来到getRememberedPrincipals方法

这里会调用getRememberedSerializedIdentity和convertBytesToPrincipals方法

getRememberedSerializedIdentity方法 会读取我们的cookie然后进行base64解码 因为我们上面加密的时候 会进行base64编码 到解密这里会进行base64解码

convertBytesToPrincipals方法会对cookie进行解密 并且反序列化
在这里插入图片描述
我们跟进去getRememberedSerializedIdentity方法

这里会调用getCookie获取到cookie之后 然后调用Base64的decode方法进行加密 然后返回
在这里插入图片描述
我们进入到convertBytesToPrincipals方法

这里对我们的解密的base64 byte字节 进行AES解密 并且对他进行反序列化
在这里插入图片描述

总结

到这里Shiro的加密和解密就说完了 其实发现 不管我们认证的过程 还是 AES加密和解密的过程 全都在DefaultSecurityManager类中的一些方法中实现的 紧接着会调用其他类。

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

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

相关文章

低代码开发与传统软件开发:未来趋势与竞争格局

近年来,低代码开发平台的快速发展引起了各行各业的广泛关注。低代码开发平台简化了软件开发的复杂性,提供了更快速、更灵活的开发方式。于是,许多人开始产生一个疑问:未来低代码开发是否会取代传统软件开发?今天这篇文…

验收支撑-软件项目验收计划书

软件项目验收计划的作用主要有以下几点: 确保项目质量:通过项目验收,客户或相关方可以对项目的成果进行全面、系统的评估,以确保项目达到预期的质量标准。发现和解决问题:在项目开发过程中,难免会存在一些问…

ROS-ROS运行管理-ROS元功能包

ROS是多进程(节点)的分布式框架,一个完整的ROS系统实现: 可能包含多台主机;每台主机上又有多个工作空间(workspace);每个的工作空间中又包含多个功能包(package);每个功能包又包含多个节点(Node),不同的节…

(Nerf学习)GaussianEditor

论文链接 https://arxiv.org/pdf/2311.14521.pdf 原码链接 https://github.com/buaacyw/GaussianEditor 一、安装(WIN失败,求解决方法) 我使用的环境是:Win11 python3.8 CUDA11.8 显卡3060 1、克隆我们的存储库并创建 conda …

【INTEL(ALTERA)】Agilex7 FPGA Development Kit DK-DK-DEV-AGI027RBES 编程/烧录/烧写/下载步骤

DK-DEV-AGI027RBES 的编程步骤: 将 USB 电缆插入 USB 端口 J8(使用 J10 时,DIPSWITCH SW5.3(DK-DEV-AGI027RES 和 DK-DEV-AGI027R1BES)和 SW8.3(DK-DEV-AGI027RB 和 DK-DEV-AGI027-RA)应关闭&a…

【动态规划】路径问题_不同路径_C++

题目链接:leetcode不同路径 目录 题目解析: 算法原理 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 编写代码 题目解析: 题目让我们求总共有多少条不同的路径可到达右下角; 由题可得: 机器人位于…

蚂蚁SEO实用的网络baidu蜘蛛有哪些

网络蜘蛛是一种用于从互联网上自动抓取信息的程序。它们根据给定的规则和指令,遍历网站上的页面,收集信息并将其存储在数据库中。网络蜘蛛在搜索引擎、数据挖掘、信息提取等领域有着广泛的应用。本文将介绍一种实用的网络蜘蛛,并探讨其实现原…

iOS加密CoreML模型

生成模型加密密钥 必须在Xcode的Preferences的Accounts页面登录Apple ID,才能在Xcode中生成模型加密密钥。 在Xcode中打开模型,单击Utilities选项卡,然后单击“Create Encryption Key”按钮。 从下拉菜单中选择当前App的Personal Team&…

【抽象责任链模式】实践优化

责任链模式 原文来自 ——> https://nageoffer.com/pages/51ffef/#%E8%B4%A3%E4%BB%BB%E9%93%BE%E6%A8%A1%E5%BC%8F (小调整重点标注,我是菜鸡) 1. 什么是责任链 责任链设计模式是一种行为型设计模式,其主要目的是解耦请求发送…

mongoAltas使用

创建项目 https://cloud.mongodb.com/v2#/org/6548f5a62d5ab00f5b67a61a/projects 部署数据库 选择厂商部署 更改数据库用户和密码 添加数据库可访问地址 添加连接信息到vscode MONGO_URLmongodbsrv://burnchi:burnchicluster0.ynoq32i.mongodb.net/Auth-Mongodb偶尔分享web开…

mysql的redolog、undo、binlog的作用

概览: MySQL三大日志包括:undolog,redo log,binlog,它们分别有以下作用: undolog:是Innodb存储引擎事务生成的日志。用于事务的回滚和MVCC,保证了事务的原子性。 redo log&#x…

H5页面生成工具源码

源码介绍 H5是基于Vue2.0开发的,通过拖拽的形式,生成页面的工具,类似易企秀、百度H5等工具。 H5特征: 1、编辑器 参考线 吸附线、组件对齐 拽改变组件形状 元素: 复制(画布) 元素: 删除&#xff08…

Fractal-Streets

title: Fractal Streets date: 2023-12-13 14:48:45 tags: 分形 categories: 算法进阶指南 题目大意 将原来的城市复制一遍放在原城市的上方,将原城市顺时针90放在原城市的左上方,将逆时针90后的城市放在原城市的左边,然后用道路将四部分链接…

美赛F奖经验分享,干货满满,快来查收!

2023年美赛结果出来之后,陆续有人给我发私信求经验,跟一些同学交流后我发现,很多人其实对美赛了解程度很少。我借此机会介绍一下美赛,并分享一下获奖经验。我的内容主要包括以下几个部分:美赛是什么、得奖分布、选题建…

AI全栈大模型工程师(二十六)如何选择 GPU 和云服务厂商

💡 这节课会带给你 如何选择 GPU 和云服务厂商,追求最高性价比 如何部署自己 fine-tune 的模型,向业务提供高可用推理服务 如何控制内容安全,做好算法备案,确保合规 开始上课! 硬件选型 当我们为模型训练及…

从传统型数据库到非关系型数据库

一 什么是数据库 数据库顾名思义保存数据的仓库,其本质是一个具有数据存储功能的复杂系统软件,数据库最终把数据保存在计算机硬盘,但数据库并不是直接读写数据在硬盘,而是中间隔了一层操作系统,通过文件系统把数据保存…

挺进云存储,天翼云全新一代XSSD勇立潮头

引言:自研高性能分布式存储引擎LAVA,实现云硬盘持续创新获得新突。 【全球云观察 | 科技热点关注】 作为算力基础设施的基石,云存储的发展一直备受公有云厂商所重视,对拉动云厂商营收规模带来重要价值,就…

用python打印出菱形图案

你可以使用Python编写一个简单的函数来打印菱形图案。下面是一个例子,这个函数接受一个参数n,表示菱形的高度,然后打印出一个菱形图案: def print_diamond(n): # 上半部分 for i in range(n): print(" " …

云智融合浪潮之下,中国操作系统逆势向上

自从2020年12月CentOS项目宣布 CentOS 8于2021年12月31日停止维护和更新,CentOS 7也将于2024年6月30日停服,就掀起了中国操作系统的替换浪潮。作为基于Red Hat Enterprise Linux的开源操作系统,CentOS广泛应用于企业级服务器和云计算平台。而…

Linux——MySQL数据库系统()

一、访问MySQL数据库 MySQL数据库系统也是一个典型的C/S(客户端/服务器)架构的应用,要访问MySQL数据库需要使用专门的客户端软件。在Linux系统中,最简单、易用的MySQL客户端软件是其自带的mysql命令工具。 1、登录到MySQL服务器经过安装后的初…