SpringSecurity+jwt+captcha登录认证授权总结
SpringSecurity+jwt+captcha登录认证授权总结
版本信息:
springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5
认证授权思路和流程:
未携带token,访问登录接口:
1、用户登录携带账号密码
2、请求到达自定义Filter,自定义Filter(如JwtAuthenticationTokenFilter)继承OncePerRequestFilter(此Filter只会进行一次过滤,在请求返回时,不会再进行调用),在SecurityConfig中配置,将自定义Filter添加到过滤器链中并加在UsernamePasswordAuthenticationFilter过滤器之前
3、自定义Filter逻辑
3.1、查询到用户未携带token,直接放行,进入到后面认证流程
3.2、将用户信息封装成Authentication对象,调用authticate()方法进行验证,一直到DaoAuthenticationProvider中,会调用UserDetailService的loadUserByUserName()方法;自定义UserDetailServiceImpl继承UserDetailService接口;重写其loadUserByUserName()方法;查到用户后,封装成UserDetail对象返回
4、调用passwordEncoder的验证方法进行用户信息的认证(一般使用BCryptPasswordEncoder,创建此Bean并放入容器中)
5、认证通过后,使用JWT创建token并放到redis中;返回token到前端
携带token访问:
1、请求到达自定义Filter中,获取token,先验证token的正确性,从token中获取到userId,根据userId从redis中获取用户信息,将用户信息封装成Authentication对象,放进SecurityContextHolder中,后面的过滤器会在SecurityContextHolder中获取用户的信息
2、请求到达FilterSecurityInterceptor,在springSecurity中默认使用FilterSecurityInterceptor来进行权限校验;FilterSecurityInterceptor会从SecurityContextHolder中获取Authentication,然后获取其中的权限信息,判断当前用户是否拥有当前资源的访问权限;
3、通过权限判断,获取资源返回给前端;
登录认证流程图:

基于RBAC的授权控制:
RBAC概念:
Role-Based Access Control,中文意思是:基于角色(Role)的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。
简单来说,就是通过将权限分配给角色,再将角色分配给用户,来实现对系统资源的访问控制。一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般是多对多的关系
模型:

在数据库中主要体现用户表、角色表、菜单表、用户角色关联表、角色菜单关联表五个模型:
CREATE TABLE "mySchema"."t_user"
(
"id" INT IDENTITY(1, 1) NOT NULL,
"username" VARCHAR(100) NOT NULL,
"password" VARCHAR(100) NOT NULL,
"email" VARCHAR(100) NOT NULL,
"phone" VARCHAR(100),
UNIQUE("id"),
UNIQUE("username"),
UNIQUE("email"),
UNIQUE("phone"),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."t_user" IS '用户表';
COMMENT ON COLUMN "mySchema"."t_user"."id" IS '用户id';
COMMENT ON COLUMN "mySchema"."t_user"."username" IS '用户名';
COMMENT ON COLUMN "mySchema"."t_user"."password" IS '密码';
COMMENT ON COLUMN "mySchema"."t_user"."email" IS '用户邮箱';
COMMENT ON COLUMN "mySchema"."t_user"."phone" IS '电话';CREATE TABLE "mySchema"."sys_role"
(
"id" BIGINT IDENTITY(1, 1) NOT NULL,
"name" VARCHAR(128) DEFAULT NULL,
"role_key" VARCHAR(100) DEFAULT NULL,
"status" CHAR(1) DEFAULT '0',
"del_flag" INT DEFAULT 0,
"create_by" BIGINT DEFAULT NULL,
"create_time" DATETIME(6) DEFAULT NULL,
"update_by" BIGINT DEFAULT NULL,
"update_time" DATETIME(6) DEFAULT NULL,
"remark" VARCHAR(500) DEFAULT NULL,
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_role" IS '角色表';
COMMENT ON COLUMN "mySchema"."sys_role"."id" IS '角色id';
COMMENT ON COLUMN "mySchema"."sys_role"."name" IS '角色名称';
COMMENT ON COLUMN "mySchema"."sys_role"."role_key" IS '角色权限字符串';
COMMENT ON COLUMN "mySchema"."sys_role"."status" IS '角色状态(0正常, 1停用)';
COMMENT ON COLUMN "mySchema"."sys_role"."del_flag" IS '删除标志(0未删除,1已删除)';
COMMENT ON COLUMN "mySchema"."sys_role"."remark" IS '备注';CREATE TABLE "mySchema"."sys_menu"
(
"id" BIGINT IDENTITY(2, 1) NOT NULL,
"menu_name" VARCHAR(64) DEFAULT 'NULL' NOT NULL,
"path" VARCHAR(200) DEFAULT NULL,
"component" VARCHAR(50) DEFAULT NULL,
"visible" CHAR(1) DEFAULT '0',
"status" CHAR(1) DEFAULT '0',
"perms" VARCHAR(100) DEFAULT NULL,
"icon" VARCHAR(100) DEFAULT '#',
"create_by" BIGINT DEFAULT NULL,
"create_time" DATETIME(6) DEFAULT CURRENT_TIMESTAMP,
"update_by" BIGINT DEFAULT NULL,
"update_time" DATETIME(6) DEFAULT CURRENT_TIMESTAMP,
"delete_f1ag" INT DEFAULT 0,
"remark" VARCHAR(500) DEFAULT NULL,
UNIQUE("id"),
NOT CLUSTER PRIMARY KEY("id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_menu" IS '菜单表';
COMMENT ON COLUMN "mySchema"."sys_menu"."menu_name" IS '菜单名';
COMMENT ON COLUMN "mySchema"."sys_menu"."path" IS '路由地址';
COMMENT ON COLUMN "mySchema"."sys_menu"."component" IS '组件路径';
COMMENT ON COLUMN "mySchema"."sys_menu"."visible" IS '菜单状态(0显示1隐藏)';
COMMENT ON COLUMN "mySchema"."sys_menu"."status" IS '菜单状态(0正常1停用)';
COMMENT ON COLUMN "mySchema"."sys_menu"."perms" IS '权限标识';
COMMENT ON COLUMN "mySchema"."sys_menu"."icon" IS '菜单图标';
COMMENT ON COLUMN "mySchema"."sys_menu"."delete_f1ag" IS '是否删除(0未删除1已删除)';
COMMENT ON COLUMN "mySchema"."sys_menu"."remark" IS '备注';CREATE TABLE "mySchema"."sys_user_role"
(
"user_id" BIGINT DEFAULT 0 NOT NULL,
"role_id" BIGINT DEFAULT 0 NOT NULL,
NOT CLUSTER PRIMARY KEY("user_id", "role_id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_user_role" IS '用户角色表';
COMMENT ON COLUMN "mySchema"."sys_user_role"."user_id" IS '用户id';
COMMENT ON COLUMN "mySchema"."sys_user_role"."role_id" IS '角色id';CREATE TABLE "mySchema"."sys_role_menu"
(
"role_id" BIGINT DEFAULT 0 NOT NULL,
"menu_id" BIGINT DEFAULT 0 NOT NULL,
NOT CLUSTER PRIMARY KEY("role_id", "menu_id")) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "mySchema"."sys_role_menu" IS '角色菜单关联表';
COMMENT ON COLUMN "mySchema"."sys_role_menu"."role_id" IS '角色id';
COMMENT ON COLUMN "mySchema"."sys_role_menu"."menu_id" IS '菜单id';
权限流程:
用户表、角色表、菜单表、部门表、用户角色关联表、角色菜单关联表;数据权限分为5种:个人、全部、本部门、指定部门、本部门及以下
链路:
1、用户注册,指定部门;创建角色,给角色赋菜单权限、数据权限;给用户赋予角色;
2、用户登录,通过用户的所有角色,获取所有的菜单权限和最大数据权限;菜单数据直接展示在页面;所有数据都有创建人,则数据的部门id是创建人的部门id;
3、在访问数据接口时,通过mybatis的拦截器对用户的数据进行过滤(拼接sql),返回给前端;
captcha图片验证码:
实现思路:
1、图片验证码获取,并将验证码验证码存放起来(单机应用可放在session中,分布式应用放在redis中)
2、当用户登录时,携带验证码以及验证码的key,进入到后端从redis中获取值进行验证
<!-- 谷歌kaptcha验证码依赖 -->
<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version>
</dependency>
代码思路:
1、生成验证码
public Result<CaptchaVO> getCaptcha() throws IOException {// 生成文字验证码String content = defaultKaptcha.createText();// 生成图片验证码ByteArrayOutputStream outputStream = null;BufferedImage image = defaultKaptcha.createImage(content);outputStream = new ByteArrayOutputStream();ImageIO.write(image, "jpg", outputStream);// 对字节数组Base64编码String str = "data:image/jpeg;base64,";String base64Img = str + Base64.getEncoder().encodeToString(outputStream.toByteArray()).replace("\n", "").replace("\r", "");CaptchaVO captchaVO = captchaService.cacheCaptcha(content);captchaVO.setBase64Img(base64Img);return Result.success(captchaVO);
}
2、存储验证码
@Service
public class CaptchaService {private Long timeout = 300L;@Autowiredprivate RedisUtils redisUtils;private final String CAPTCHA_KEY_PREFIX = "captcha:verification:";public CaptchaVO cacheCaptcha(String captcha){//生成一个随机标识符String randomStr = UUID.randomUUID().toString();//缓存验证码并设置过期时间String captchaKey = CAPTCHA_KEY_PREFIX.concat(randomStr);redisUtils.set(captchaKey, captcha, timeout, TimeUnit.SECONDS);CaptchaVO captchaVO = new CaptchaVO();captchaVO.setCaptchaKey(captchaKey);captchaVO.setExpire(timeout);captchaVO.setCaptcha(captcha);return captchaVO;}
}
3、校验验证码
Object captcha = redisUtils.get(reqVO.getCaptchaKey());
if (Objects.isNull(captcha)) {return "验证码已过期";
}
if (!captcha.equals(reqVO.getCaptcha())) {return "验证码错误";
}相关文章:
SpringSecurity+jwt+captcha登录认证授权总结
SpringSecurityjwtcaptcha登录认证授权总结 版本信息: springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5 认证授权思路和流程: 未携带token,访问登录接口: 1、用户登录携带账号密码 2、请求到达自定义Filter&am…...
项目技术栈-解决方案-web3去中心化
web3去中心化 Web3 DApp区块链:钱包:智能合约:UI:ETH系开发技能树DeFi应用 去中心化金融P2P 去中心化网络参考Web3 DApp 区块链: 以以太坊(Ethereum)为主流,也包括Solana、Aptos等其他非EVM链。 区块链本身是软件,需要运行在一系列节点上,这些节点组成P2P网络或者半…...
【AI声音克隆整合包及教程】第二代GPT-SoVITS V2:创新与应用
一、引言 随着科技的迅猛发展,声音克隆技术已经成为一个炙手可热的研究领域。SoVITS(Sound Voice Intelligent Transfer System),作为该领域的先锋,凭借其卓越的性能和广泛的适用性,正在为多个行业带来前所…...
分清数据链路层、网络层、传输层的区别,以及这些层面的代表协议
目录 数据链路层 网络层 传输层 数据链路层 OSI模型的第二层,负责在相邻节点之间传输帧,处理帧的封装、地址、差错控制和流量控制等。确保数据在物理介质上可靠地传输,并为上层协议提供服务。 以太网(Ethernet)&…...
git没有识别出大写字母改成小写重命名的文件目录
Git 默认不会跟踪大写字母和小写字母的区别,因为在大多数文件系统中,大写字母和小写字母被认为是相同的文件,只有在区分大小写的文件系统中(如 macOS 的 HFS 或 Windows 的 NTFS),这才是一个问题。 如果重命…...
自己动手写Qt Creator插件
文章目录 前言一、环境准备1.先看自己的Qt Creator IDE的版本2.下载源码 二、使用步骤1.参考原本的插件2.编写自定义插件1.cmakelist增加一个模块2.同理,qbs文件也增加一个3.插件源码 三、效果总结 前言 就目前而言,Qt Creator这个IDE,插件比…...
数据重塑:长宽数据转换【基于tidyr】
在数据分析和可视化过程中,数据的组织形式直接影响着我们能够进行的分析类型和可视化效果。这里简单介绍两种常见的数据格式:长格式(Long Format)和宽格式(Wide Format),以及如何使用tidyr包进行…...
多模态大模型开启AI社交新纪元,Soul App创始人张璐团队亮相2024 GITEX GLOBAL
随着AI在全球范围内的加速发展和广泛应用,各行业纷纷在此领域发力。作为全球最大的科技盛会之一,2024年的GITEX GLOBAL将目光再次聚焦于人工智能的飞速发展,吸引了超过6700家来自各个领域的企业参与。在这样的背景下,Soul App作为国内较早将AI技术应用于社交领域的平台,首次亮相…...
实验6记录网络与故障排除
实验6记录网络与故障排除 实验目的及要求: 通过实验,掌握如何利用文档记录网络设备相关信息并完成网络拓扑结构的绘制。能够使用各种技术和工具来找出连通性问题,使用文档来指导故障排除工作,确定具体的网络问题,实施…...
QEMU 模拟器中运行的 Linux 系统
这两个文件通常用于在 QEMU 模拟器中运行的 Linux 系统,具体作用如下: 1. linux-aarch64-qemu.ext4: - **文件类型**:这是一个文件系统镜像文件,通常是 ext4 文件系统格式。 - **作用**:它包含了 Li…...
Ceph PG(归置组)的状态说明
Ceph PG(Placement Group)的状态反映了Ceph集群中数据的健康状况和分布情况。以下是Ceph PG的一些常见状态: Creating:创建状态。在创建存储池时,会创建指定数量的归置组(PG)。Ceph在创建一或多…...
Docker使用docker-compose一键部署nacos、Mysql、redis
下面是一个简单的例子,展示如何通过Docker Compose文件部署Nacos、MySQL和Redis。请确保您的机器上已经安装了Docker和Docker Compose。 1,准备好mysql、redis、nacos镜像 sudo docker pull mysql:8 && sudo docker pull redis:7.2 &&…...
HTTP常见的状态码有哪些,都代表什么意思
HTTP 协议定义了一系列的状态码,用于描述服务器对客户端请求的处理结果。这些状态码分为五个类别,每个类别都有特定的用途。 常见状态码 1开头 信息性状态码 这些状态码表示请求已被接收,继续处理。 100 Continue:客户端应继续…...
WebKit的Windows接口(适用2024年11月份版)
WebKit的Windows接口 使用cairo作为图形后端,libcurl作为网络后端。并且它只支持64位的Windows。 安装开发工具 安装带有“使用c进行桌面开发”工作负载的最新Visual Studio。 Activate Developer Mode.激活开发者模式。Build-webkit脚本创建一个指向生成的comp…...
Android 最新的AndroidStudio引入依赖失败如何解决?如:Failed to resolve:xxxx
错误信息: 在引入依赖时报错:Failed to resolve: xxx.xxxx:1.1.0 解决方案: 需要修改maven库的代理,否则就需要翻墙编译 新的AndroidStudio版本比较坑,修改代理的位置发生了变化: 最新变化:…...
ue5 蓝图学习(一)结构体的使用
在内容浏览器中右键 蓝图-选择结构体 下面这东西就是结构体,和C的结构体差不多 双击一下 可以添加变量,设置变量的类型和默认值。 可以在关卡蓝图中调用它。 点击打开关卡蓝图,添加变量 在变量的右侧,变量类型里搜索strcut&#…...
docker--工作目录迁移
前言 安装docker,默认的情况容器的默认存储路径会存储系统盘的 /var/lib/docker 目录下,系统盘一般默认 50G,容器输出的所有的日志,文件,镜像,都会存在这个地方,时间久了就会占满系统盘。 一、…...
Golang | Leetcode Golang题解之第556题下一个更大元素III
题目: 题解: func nextGreaterElement(n int) int {x, cnt : n, 1for ; x > 10 && x/10%10 > x%10; x / 10 {cnt}x / 10if x 0 {return -1}targetDigit : x % 10x2, cnt2 : n, 0for ; x2%10 < targetDigit; x2 / 10 {cnt2}x x2%10 -…...
2分钟在阿里云ECS控制台部署个人应用(图文示例)
作为一名程序员,我有大量的个人代码和应用托管在Github/Gitee这些代码仓库。当我想要部署这些代码到我的阿里云ECS服务器时,往往会很麻烦,主要问题有这些: 需要手动安装和配置git,过程非常繁琐。每次都需要登录到机器…...
2023.8 用于生物医学问答的选择性 UMLS 知识注入
Selective UMLS knowledge infusion for biomedical question answering Selective UMLS knowledge infusion for biomedical question answering | Scientific Reports 韩国首尔国立大学研究生院生物工程跨学科项目 问题 如何高效地将生物医学知识注入预训练语言模型&#x…...
免费AI抠像插件:OBS背景移除与虚拟绿幕的完整指南
免费AI抠像插件:OBS背景移除与虚拟绿幕的完整指南 【免费下载链接】obs-backgroundremoval An OBS plugin for removing background in portrait images (video), making it easy to replace the background when recording or streaming. 项目地址: https://gitc…...
FPGA SoC设计:基于eMMC的RISC-V Linux系统启动方案详解
1. 项目概述与核心价值在嵌入式系统开发,尤其是基于FPGA的SoC设计中,如何为运行在RISC-V等处理器上的Linux系统提供一个稳定、大容量且易于管理的存储介质,一直是个关键问题。FPGA芯片本身不具备非易失性存储能力,传统的方案如SD卡…...
CARLA与Autoware融合实践:从自定义地图构建到闭环仿真测试
1. 自定义高精地图的构建与格式转换 在自动驾驶仿真开发中,高精地图是车辆感知和决策的基础。CARLA仿真环境提供了灵活的地图编辑工具,但要将自建地图与Autoware无缝对接,需要特别注意数据格式的兼容性。我曾在实际项目中遇到过多次地图导入…...
彻底告别iPhone过热降频!thermalmonitordDisabler让你的设备性能满血释放
彻底告别iPhone过热降频!thermalmonitordDisabler让你的设备性能满血释放 【免费下载链接】thermalmonitordDisabler A tool used to disable iOS daemons. 项目地址: https://gitcode.com/gh_mirrors/th/thermalmonitordDisabler 你是否曾经在游戏激战中突然…...
Petrel地质建模许可不够用?自动回收,油气勘探团队高效
你是不是也遇到这种情况?项目组突然来了个新成员,结果所有许可都满了,连老员工都得排队等。别慌,我搞懂了,Petrel许可不够用,最大的问题就是没回收,几十万的授权就浪费在没人用的角落。 闲置许…...
踩坑实录:用YOLOv8训练小目标(足球)数据集时,我是如何通过调整图像尺寸把mAP提上去的
小目标检测优化实战:YOLOv8图像尺寸调整如何提升足球识别精度 足球在绿茵场上划出的弧线总是令人着迷,但当这份优雅遇上目标检测算法时,却常常变成开发者的噩梦——那些直径不足20像素的小球,在常规训练参数下往往成为模型"视…...
为Claude Code配置Taotoken解决密钥被封与Token不足难题
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 为Claude Code配置Taotoken解决密钥被封与Token不足难题 应用场景类,针对经常使用Claude Code但受限于官方限制的开发者…...
除了高精度定位,CORS基准站网还能为你提供哪些意想不到的数据服务?
解锁CORS基准站网的隐藏价值:从厘米级定位到时空大数据平台 当大多数人提起CORS基准站网时,第一反应往往是"高精度定位"。确实,这套由数百个地面站点组成的网络系统,能够为各类GNSS设备提供实时厘米级甚至毫米级的定位修…...
专业休闲卤味零食包装设计公司排名榜单盘点-哲仕设计上榜
专业休闲卤味零食包装设计公司排名榜单盘点-哲仕设计上榜休闲卤味零食属于大众刚需休闲食品,涵盖肉类卤制熟食、素菜卤味小吃、真空独立卤包、常温即食卤品、麻辣风干肉干、组合卤味礼盒等品类,广泛适用于居家休闲解馋、办公下午茶加餐、追剧娱乐食用、出…...
如何快速备份微信聊天记录:Mac用户的完整解决方案
如何快速备份微信聊天记录:Mac用户的完整解决方案 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 你是否曾经因为误删重要微信聊天记录而懊恼不已?…...
