Shiro介绍以及一个原始例子

目录

      • 基本功能
      • 核心组件
      • 应用场景
      • 优势
      • Shiro 核心工作流程(以 Web 应用登录为例)
      • 一个例子【验证,授权]:

Shiro 是一个强大且易用的 Java 安全框架,提供了 身份验证、授权、加密和会话管理等功能,可帮助开发人员轻松确保应用程序的安全,以下是对它的详细介绍:

基本功能

  • 身份验证:也称为 “登录”,用于验证用户身份。Shiro 支持多种身份验证方式,如用户名 / 密码验证、基于证书的验证等。 比如在一个 Web 应用中,用户输入用户名和密码登录,Shiro 会对输入的凭证与存储在数据源(如数据库、文件系统)中的凭证进行比对,以确认用户身份的合法性。
  • 授权: 确定 “已认证的用户” 被允许做什么,即访问控制。Shiro 支持基于角色的访问控制(RBAC), 也支持更细粒度的基于资源和权限的访问控制。例如,在一个企业管理系统中,普通员工角色只能查看自己的任务信息,而管理员角色可以进行系统设置、用户管理等操作,Shiro 可以通过配置角色和权限来实现这种访问控制。
  • 加密:对数据进行加密处理,以保护数据的保密性和完整性。Shiro 提供了常用的加密算法支持,如 MD5、SHA 等, 并且还支持加盐(salt)加密,增加破解难度。比如存储用户密码时,使用 Shiro 的加密功能对密码进行加密存储,当用户登录输入密码时,再对输入的密码进行加密并与存储的加密密码进行比对。
  • 会话管理:管理用户的会话,即使在无状态的应用(如 Web 应用)中也能跟踪用户的活动。Shiro 的会话可以脱离 Web 容器独立存在,这使得它不仅适用于 Web 应用,也适用于非 Web 的 Java 应用,如桌面应用等。例如,在一个电商应用中,用户在浏览商品、添加购物车等操作过程中,Shiro 的会话管理可以记录用户的操作信息,保证用户在整个购物流程中的状态一致性。

核心组件

  • Subject:即 “当前操作用户”,可以是一个通过浏览器请求的用户,也可以是一个运行的程序。Subject 代表了与应用交互的 “人” 或 “事物”,内部维护了与安全相关的状态,如身份认证信息、角色、权限等。
  • SecurityManager:Shiro 的核心,协调 Shiro 内部各种安全组件,管理 Subject。它就像是 Shiro 的 “大管家”,负责处理 Subject 的认证、授权请求,与数据源(如数据库、文件系统)交互获取用户信息和权限信息等。
  • Realms:Shiro 与应用安全数据间的桥梁,用于从数据源获取用户的身份验证和授权相关数据,如用户的凭证(用户名 / 密码)、角色、权限等。开发人员可以自定义 Realm,以适应不同的数据源,如从关系型数据库(MySQL、Oracle)、LDAP 服务器等获取安全数据。

应用场景

  • Web 应用安全:对 Web 应用的页面、接口进行访问控制,确保只有经过认证和授权的用户才能访问特定资源,同时管理用户的会话,提供安全的登录、注销等功能。
  • 企业级应用:在大型企业级应用中,处理不同部门、不同角色用户的复杂权限管理需求,如人力资源管理系统中不同角色的员工对员工信息、考勤信息、薪资信息等的访问权限控制。
  • 移动应用后端:为移动应用的后端服务提供安全保障,确保移动客户端与服务器之间数据交互的安全性,对用户进行身份验证和授权,保护后端接口不被非法访问。

优势

  • 易于集成:Shiro 可以很方便地集成到各种 Java 应用中,无论是基于 Spring、Struts 等框架的 Web 应用,还是独立的 Java SE 应用,都能快速整合 Shiro 实现安全功能。
  • 功能全面:涵盖了身份验证、授权、加密、会话管理等多个方面的安全功能,开发人员无需再去整合多个不同的安全组件。
  • 灵活性高:开发人员可以根据应用的实际需求,灵活自定义 Realm、授权策略等,以适应不同的业务场景和安全要求。

Shiro 核心工作流程(以 Web 应用登录为例)

Shiro 的安全逻辑围绕 Subject(用户) 和 SecurityManager(安全管理器) 展开,典型的登录认证流程如下,可清晰理解其内部协作机制:
1.用户发起登录请求:前端提交用户名 / 密码,后端接收请求后,通过 SecurityUtils.getSubject() 获取当前 Subject(此时 Subject 处于 “未认证” 状态)。
2.封装认证凭证:创建 UsernamePasswordToken 对象,将用户名 / 密码封装为 Shiro 可识别的 “认证令牌”。
3.触发认证流程:调用 subject.login(token) 方法,Shiro 会将认证请求委托给核心组件 SecurityManager。
4.SecurityManager 转发请求:SecurityManager 本身不直接处理认证,而是将请求转发给配置好的 Realm(数据桥梁)。
5.Realm 验证凭证:Realm 从数据库 / 缓存中查询该用户的真实密码(通常是加密后的密码),与 token 中的密码(加密后)进行比对:
若比对成功:Realm 返回包含用户角色 / 权限的 AuthenticationInfo 对象,SecurityManager 会将认证状态更新到 Subject,此时 subject.isAuthenticated() 结果为 true。
若比对失败:抛出 IncorrectCredentialsException(密码错误)、UnknownAccountException(账号不存在)等异常,登录失败。
认证结果处理:后端根据是否抛出异常,向前端返回登录成功 / 失败的响应,成功后 Subject 可后续进行授权校验。

一个例子【验证,授权]:

思路:
初始化:加载配置 → 创建 SecurityManager → 绑定到环境。
认证:subject.login(token) → 调用 Realm 的 doGetAuthenticationInfo → 校验用户名密码 → 认证成功。
授权:调用 hasRole/isPermitted → 触发 Realm 的 doGetAuthorizationInfo → 获取角色 / 权限 → 校验并返回结果。

//整个流程的核心是 自定义 Realm,它同时处理认证(验证用户身份)和授权(分配角色权限),是 Shiro 与业务数据的桥梁。

添加依赖:

  <!-- shiro的核心依赖--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.3.2</version></dependency><!--  测试      --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--日志--><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.1.3</version></dependency>

shiro-test.ini:

[main]
# 声明自定义 Realm:给类取一个别名(myClass),指向实际的类路径
myClass=com.my.MyRealm
#注册realm到securityManager中
#作用:将前面声明的 myClass(即你的 MyRealm)注册到 ShiroSecurityManager 中。
#SecurityManagerShiro 的核心管理器,必须知道使用哪个 Realm 来获取用户数据(认证和授权信息),
#否则 Shiro 无法完成认证授权。
securityManager.realms=$myClass

ShiroTest:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;public class ShiroTest {@Testpublic void testLogin() {//!!!这样理解更易理解//我们写的.ini文件是 “原材料清单+组装规则”;//工厂是 “按规则加工的机器”;//SecurityManager 是 “最终加工好的核心设备”;//后续 Subject(用户)的登录、权限校验,都要靠这个 “核心设备” 来协调。// 1. 根据配置文件创建「生产SecurityManager的工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-test.ini");//2.通过工厂获取SecurityManagerSecurityManager securityManager = factory.getInstance();//3.将SecurityManager绑定到当前运行环境//→ 把 SecurityManager 存入 ThreadLocal(线程私有变量)//→ 目的是让当前线程中所有需要 SecurityManager 的地方(比如获取 Subject)都能拿到它SecurityUtils.setSecurityManager(securityManager);//→ 内部会先从 ThreadLocal 中取出之前存入的 SecurityManager//→ 再通过 SecurityManager 创建 / 获取当前用户的 Subject 对象//→ 所以 Subject 可以理解为:SecurityManager 根据当前交互对象(用户 / 程序)生成的 “安全操作代理”//简单说就是:先把 SecurityManager 放到 “线程全局仓库”,Subject 需要时就从这个仓库里找 SecurityManager 帮忙创建自己。//这种设计的好处是:在多线程环境下(比如 Web 应用同时处理多个用户请求),//每个线程的 SecurityManager 和 Subject 都是独立的,不会互相干扰(比如用户 A 的登录状态不会影响用户 B)。Subject subject = SecurityUtils.getSubject();String name="zqn";String password="123456";//用户输入(username/password)//→ 封装成 UsernamePasswordToken(凭证信封)//→ subject.login(token)(启动认证)//→ Subject 转发给 SecurityManager//→ SecurityManager 委托给 Authenticator//→ Authenticator 调用 Realm 的 doGetAuthenticationInfo(查数据库)//→ Shiro 比对凭证 → 认证成功/失败UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(name,password);//执行login-->realm域中的认证方法subject.login(usernamePasswordToken);//认证成功后,首次调用这些方法时,会触发 doGetAuthorizationInfoSystem.out.println(subject.hasRole("role1"));//true 检查角色 → 触发授权System.out.println(subject.hasRole("role2"));//true 检查权限 → 触发授权//检查用户是否有 user:save 权限 → 授权方法中添加了该权限,返回 true。System.out.println(subject.isPermitted("user:save"));//trueSystem.out.println(subject.isPermitted("user:update"));//trueSystem.out.println(subject.isPermitted("user:find"));//true}
}

MyRealm:

package com.my;import org.apache.shiro.authc.*;
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 java.util.ArrayList;
import java.util.List;public class MyRealm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行授权方法");//1.获取安全数据  username,用户idString username = (String)principalCollection.getPrimaryPrincipal();// 2. 模拟查询数据库获取角色和权限(实际开发中会从数据库查询)List<String> perms = new ArrayList<String>();perms.add("user:save");perms.add("user:update");// 硬编码给用户分配四个权限perms.add("user:delete");perms.add("user:find");List<String> roles = new ArrayList<String>();roles.add("role1");roles.add("role2");// 硬编码给用户分配两个角色// 3. 封装授权信息并返回SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//设置权限集合info.addStringPermissions(perms);   // 设置角色info.addRoles(roles); // 设置权限return info; //设置角色集合}//验证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行认证方法");UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;String username = upToken.getUsername();char[] passwd = upToken.getPassword();String password = new String(passwd);if ("zqn".equals(username) && "123456".equals(password)) {SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, "myRealm");//1.安全数据,2.密码。3。当前realm域名称return info;} else {//6.失败,抛出异常或返回nullthrow new RuntimeException("用户名或密码错误");}}
}

结果:
在这里插入图片描述

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

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

相关文章

AI-调查研究-59-机器人 行业职业地图:发展路径、技能要求与薪资全解读

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布&#xff01;“快的…

LeetCode算法日记 - Day 22: 提莫攻击、Z字形变换

目录 1. 提莫攻击 1.1 题目解析 1.2 解法 1.3 代码实现 2. Z字形变换 2.1 题目解析 2.2 解法 2.3 代码实现 1. 提莫攻击 495. 提莫攻击 - 力扣&#xff08;LeetCode&#xff09; 在《英雄联盟》的世界中&#xff0c;有一个叫 “提莫” 的英雄。他的攻击可以让敌方英…

Unity笔记(七)——四元数、延迟函数、协同程序

写在前面&#xff1a;写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解&#xff0c;方便自己以后快速复习&#xff0c;减少遗忘。主要是C#代码部分。六、四元数欧拉角具有旋转约定&#xff0c;也就是说&#xff0c;无论你调整角度的顺序是什么&…

用大语言模型提升语音翻译:一种全新的端到端方法

用大语言模型提升语音翻译:一种全新的端到端方法 在语音翻译领域,如何将说话内容快速准确地转化为另一种语言,一直是研究者们关注的焦点。随着大语言模型(LLM)的兴起,我们迎来了一个全新的机遇:利用LLM的强大能力,来提升语音翻译系统的性能。最近,一项名为“End-to-E…

freeModbus TCP收发数据一段时间后,出现掉线情况(time out问题)

话说这个是真难找啊。我仅仅发表我找到的问题。我在接收几十到几百次数据的时候&#xff0c;会出现连接超时&#xff0c;也就是time out。而且ping也ping不通。也就是说明lwip出了问题。首先我先介绍modbus的这个流程。首先是函数eMBTCPInit( MB_TCP_PORT_USE_DEFAULT )我们进入…

Linux Web环境一键安装脚本集合(非docker)

✨重磅&#xff01;盹猫的个人小站正式上线啦&#xff5e;诚邀各位技术大佬前来探秘&#xff01;✨ —— 专为开发者打造的宝藏基地&#xff0c;等你来探索&#xff01; 这里有&#xff1a; &#x1f525; 硬核技术干货&#xff1a;编程技巧、开发经验、踩坑指南&#xff0c;带…

原生安卓#基于Android的爱好者分享论坛的设计与实现/基于Android在线论坛系统app/基于Android的论坛系统的设计与实现的设计与实现

原生安卓#基于Android的爱好者分享论坛的设计与实现/基于Android在线论坛系统app/基于Android的论坛系统的设计与实现的设计与实现

基于Android的超市购物系统的设计与实现、基于android的在线商城app/基于android的在线销售系统app#android

基于Android的超市购物系统的设计与实现、基于android的在线商城app/基于android的在线销售系统app#android

C++14 到 C++20 全面解析:语言新特性、标准库演进与实战案例

一、前言C 作为一门历史悠久且不断演进的编程语言&#xff0c;在 C11 之后进入了“现代化”的快车道。C11 被称为 C 的第二次诞生&#xff0c;引入了 lambda 表达式、智能指针、右值引用、并发支持等革命性特性。然而&#xff0c;C 的标准化进程并没有止步于此。C14、C17 和 C2…

HarvardX TinyML小笔记2(番外1:TFLite)

1 原理 tflite就是Tensorflow的轻量化模型&#xff0c;核心处理就是量化和剪枝。不过这部分目前是在Tensorflow中封装了&#xff0c;所以这里也不会去看细节&#xff0c;主要就是看看原理和使用方法。 量化Quantization&#xff0c;其实就是把原来的float32换成int8。这样一个…

向量库Qdrant vs Milvus 系统详细对比

Qdrant vs Milvus 系统详细对比 一、它们是什么&#xff08;定位&#xff09; 两者都是专门做向量相似搜索的数据库&#xff1a;支持ANN&#xff08;近似最近邻&#xff09;检索、向量结构化过滤、REST/gRPC 接口与官方SDK&#xff1b;Milvus 官方也定位为"面向GenAI、可…

适配欧拉操作系统

背景 客户指定服务器环境欧拉操作系统&#xff0c;版本&#xff1a;6.6.0-72.0.0.76.oe2403sp1.x86_64 需要把Java 应用以及各种中间件部署在欧拉操作系统上。 问题适配MySQL 1.1 编译报错 mysql-5.7.40-el7-x86_64.tar.gz版本在CentOS7环境安装正常 当前欧拉环境直接使用CentO…

学习spring Bean的生命周期

完整项目结构 ├── pom.xml └── src/├── main/│ ├── java/│ │ └── com/│ │ └── zhang/│ │ ├── bean/│ │ │ ├── Address.java│ │ │ ├── MyBeanPostProcessor.java│ │ …

elasticsearch 7.17.23 使用spring data es实现高亮分页,scroll查询分页查询

一 介绍 1.1 工程结构 1.2 启动elasticsearch服务 1.3 高亮分页 DeepSeek 代码 效果&#xff1a; 1.4 scroll分页 代码 2.效果 后台日志 1.5 完整代码 https://gitee.com/jurf-liu/es-2.17.x-demo.git

onlyoffice整合springboot+vue实现文档在线编辑保存

项目上需要用到在线word、excel文档编辑功能&#xff0c;通过游览器在线打开一个远程的word文档编辑保存&#xff0c;这里记录下整合思路。 onlyoffice简介 ONLYOFFICE 是一款开源的办公套件&#xff0c;提供了一系列在线文档编辑和协作工具&#xff0c;适用于团队和个人使用…

Linux笔记10——shell编程基础-4

补充$#——取参数个数“$n”,有值取值&#xff0c;无值取空字符&#xff0c;一般都会加引号&#xff0c;在某些情况下避免报语法错误一、read接收键盘输入[rootlocalhost ~]# cat demo.sh #!/bin/bash echo -n "请输入你的姓名&#xff1a;" read nameecho "你…

(Redis)过期删除策略

1. 背景Redis 支持为 Key 设置过期时间&#xff08;TTL&#xff09;&#xff0c;让数据在一定时间后自动失效。 例如&#xff1a;SET session:1001 "userA" EX 60 # 60 秒后过期但是问题来了&#xff1a;Key 到期后&#xff0c;Redis 什么时候、如何删除它&#xf…

nodejs 集成mongodb实现增删改查

初始化项目: npm init -y npm install mongoose -save 安装mongoose 插件 mongoose 链接数据库语法&#xff1a; mongodb://[username:password]host1[:poert1],host2[:port2]…/[databsase]?[options…] userame&#xff1a; 用户名 passwrod: 密码 host1:port1,host2:port…

音视频学习(五十八):STAP-A模式

什么是 STAP-A&#xff1f; STAP-A 是一种特殊的 RTP 封装机制&#xff0c;专为 H.264 和 H.265 这类视频编码协议设计。它的核心目的只有一个&#xff1a;将多个小的 NALU&#xff08;网络抽象层单元&#xff09;打包进一个 RTP 包中&#xff0c;以此来减少网络开销&#xff0…

管理型交换机通过VLAN划分实现不同IP跨网段通信配置方法

管理型交换机应用场景丰富&#xff0c;如果要实现不同IP跨网段通信(比如172.22.106.X和192.168.100.X实现通信)&#xff0c;通过VLAN划分是可以满足&#xff0c;下面分享基于弱三层交换机RTL9301方案核心模块SW-24G4F-301EM配置方法&#xff01; 1. 一般结合交换机的应用场景&a…