【RuoYi-Cloud项目研究】【ruoyi-auth模块】登录请求(/login)分析
文章目录
- 0. 网关如何处理登录请求
- 1. Controller
- 1.1. 获取用户信息
- 1.2. 创建用户的token
- 2. Service
- 2.1. FeignClient远程查询用户信息
- 2.2. 验证密码
- 3. 何时刷新 token,如何刷新【本文重点】
本文主要是分析登录请求 /login 的过程。
调用过程是:ruoyi-auth —> ruoyi-system
0. 网关如何处理登录请求
登录请求 127.0.0.1:8080/auth/login是特殊的请求。经过的过滤器有:
AuthFilter(order=-200)
XssFilter(order=-100)
CacheRequestFilter(order=1)
ValidateCodeFilter(order=2)
StripPrefix(order=3)
AuthFilter 认证过滤器对需要排除的 uri 地址,不检查是否有 token 直接放行(需要排除的配置可以在nacos中配置)。默认配置如下:
# 安全配置
security:# 验证码captcha:enabled: truetype: math# 防止XSS攻击xss:enabled: trueexcludeUrls:- /system/notice# 不校验白名单ignore:whites:- /auth/logout- /auth/login- /auth/register- /*/v2/api-docs- /csrf
(注意是“认证”不是“鉴权”,认证主要是判断 token 是否有效,不涉及权限)
1. Controller
@PostMapping("login")public R<?> login(@RequestBody LoginBody form){// 用户登录LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());// 获取登录tokenreturn R.ok(tokenService.createToken(userInfo));}
- 用户登录
- 生成 token 返回
1.1. 获取用户信息
请看 Service
1.2. 创建用户的token
- 创建token返回给前端
/*** 创建令牌*/
public Map<String, Object> createToken(LoginUser loginUser)
{String token = IdUtils.fastUUID();// <1> 封装用户信息Long userId = loginUser.getSysUser().getUserId();String userName = loginUser.getSysUser().getUserName();loginUser.setToken(token);loginUser.setUserid(userId);loginUser.setUsername(userName);loginUser.setIpaddr(IpUtils.getIpAddr());// <2> 刷新tokenrefreshToken(loginUser);// <3> Jwt存储信息Map<String, Object> claimsMap = new HashMap<String, Object>();claimsMap.put(SecurityConstants.USER_KEY, token);claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);claimsMap.put(SecurityConstants.DETAILS_USERNAME, userName);// 接口返回信息Map<String, Object> rspMap = new HashMap<String, Object>();rspMap.put("access_token", JwtUtils.createToken(claimsMap));rspMap.put("expires_in", expireTime);return rspMap;
}
在 <1> 处:
把从 ruoyi-system 模块获取到的用户信息(用户、角色、权限)连同关键部分(uuid、userId、userName)重新封装
在 <2> 处:
refreshToken方法负责刷新token。何时刷新、如何刷新是一个值得讨论的问题。在本文的第三章重点讨论了这个问题。
在 <3> 处:
创建 token 的负载信息,把 uuid、userId、userName 作为 token 的负载,来创建 token。并返回给用户
2. Service
public LoginUser login(String username, String password){...// IP黑名单校验【在哪里初始化黑名单的???】String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST));if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())){recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单");throw new ServiceException("很遗憾,访问IP已被列入系统黑名单");}// 查询用户信息R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);...passwordService.validate(user, password);return userInfo;}
主要包括 2 个部分。
- 用 FeignCilent 从远程服务查询用户信息
- 密码验证
注意: remoteUserService.getUserInfo(username, SecurityConstants.INNER) 的 INNER 指定了该请求是“内部”请求,模块 auth 还会对 INNER 做处理。
2.1. FeignClient远程查询用户信息
以下代码com.ruoyi.system.api.RemoteUserService在 ruoyi-api-system 中,只是定义了相关的 api 并不是实现。RuoYi 抽象了与系统相关的 ruoyi-api-system。在里面写公共的类或接口
@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
public interface RemoteUserService
{/*** 通过用户名查询用户信息** @param username 用户名* @param source 请求来源* @return 结果*/@GetMapping("/user/info/{username}")public R<LoginUser> getUserInfo(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
}
url是:/user/info/{username}。
调用服务是: ruoyi-system。
设置了降级 fallback 处理:RemoteUserFallbackFactory
备注:获取用户信息的详细分析参考:https://www.yuque.com/yuchangyuan/tkb5br/vktircc4smqw8ggs
2.2. 验证密码
- 验证密码
主要是验证“可重试次数”和“密码正确性”
1、验证重试次数(默认如果错误超过5次就锁定 10分钟)
2、验证密码是否与数据库匹配。如登录成功需要清除密码错误次数。注册和验证密码用到的密码验证器要一致。
3. 何时刷新 token,如何刷新【本文重点】
- 何时刷新
只有在将要达到过期时间,才会刷新,来续期,通常可以认为是 2/3 的时间点。
① 调用refresh方法刷新:refresh 接口
② 创建 token 时:createToken方法
③ 设置用户信息时:setLoginUser方法
④ 验证 token 时:verifyToken方法
主要是第四点。是通过 mvc 拦截器实现的
- 如何刷新
1、定时任务方案:
① 拦截用户请求,保存 key=userId,value=需要刷新的时间点到一个全局的 map 中
② 用 quartz 启动一个定时任务间隔一段时间扫描 map 来刷新
缺点:不太好控制
2、拦截器方案:
原理:是通过 mvc 的拦截器 HandlerInterceptor 实现的。
为什么不通过过滤器实现,而是拦截器?
答案:因为我们的目的不是要过滤掉请求,而是拦截请求并根据条件设置token的过期时间
public class HeaderInterceptor implements AsyncHandlerInterceptor
{@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{........String token = SecurityUtils.getToken();if (StringUtils.isNotEmpty(token)){LoginUser loginUser = AuthUtil.getLoginUser(token);if (StringUtils.isNotNull(loginUser)){// 验证和刷新 token 的过期时间AuthUtil.verifyLoginUserExpire(loginUser);SecurityContextHolder.set(SecurityConstants.LOGIN_USER, loginUser);}}return true;}
}
如上面的代码,RuoYi 采用的也是拦截器方案,在HeaderInterceptor拦截器中,针对每个请求验证和刷新 token 的过期时间。详情参考:https://www.yuque.com/yuchangyuan/tkb5br/d387fbc5d3f5522fa013b5e087a0dad9
相关文章:
【RuoYi-Cloud项目研究】【ruoyi-auth模块】登录请求(/login)分析
文章目录 0. 网关如何处理登录请求1. Controller1.1. 获取用户信息1.2. 创建用户的token 2. Service2.1. FeignClient远程查询用户信息2.2. 验证密码 3. 何时刷新 token,如何刷新【本文重点】 本文主要是分析登录请求 /login 的过程。 调用过程是:ruoyi-…...
Git 学习笔记 | Git 项目创建及克隆
Git 学习笔记 | Git 项目创建及克隆 Git 学习笔记 | Git 项目创建及克隆创建工作目录与常用指令本地仓库搭建克隆远程仓库 Git 学习笔记 | Git 项目创建及克隆 创建工作目录与常用指令 工作目录(WorkSpace)一般就是你希望Git帮助你管理的文件夹,可以是…...
C++默认参数(实参)
在本文中,您将学习什么是默认参数,如何使用它们以及使用它的必要声明。在C 编程中,您可以提供函数参数的默认值。默认参数背后的想法很简单。如果通过传递参数调用函数,则这些参数将由函数使用。但是,如果在调用函数时…...
Datax数据同步支持SqlServer 主键自增
允许写入的SQL SET IDENTITY_INSERT table_name ON;-- 插入数据,指定主键值 INSERT INTO table_name (id, column1, column2, ...) VALUES (new_id_value, value1, value2, ...);SET IDENTITY_INSERT table_name OFF; 写入插件处理 核心类:com.alibab…...
C++开发学习笔记3
C 中枚举的使用 在C中,枚举常量(Enumeration Constants)是一种定义命名常量的方式。枚举类型允许我们为一组相关的常量赋予有意义的名称,并将它们作为一个独立的类型来使用。 以下是定义和使用枚举常量的示例: enum…...
计算机中常说的SDK是什么意思?
SDK是Software Development Kit的英文缩写,意思是软件开发包。 软件开发包中往往包含有多种辅助进行软件开发的内容,包括一些软件开发工具、文档说明、库和示例代码。这些内容能够帮助使用SDK进行软件开发的人员更好地开发程序。 SDK的作用就是简化软件…...
漏刻有时数据可视化大屏(16)数据指标KPI和柱图折线图混排
CSS样式表 /*面板*/ .pannel {width: 100%;margin-top: 30px;clear: both; }.item_l {float: left;width: 20%; /*3格60%*/margin: 0; }.item_r {float: left;width: 10%; /*4格40%*/margin: 0; }.item_child {float: left;width: 50%; }.item_child_b {float: left;width: 10…...
基于Stable Diffusion的图像合成数据集
当前从文本输入生成合成图像的模型不仅能够生成非常逼真的照片,而且还能够处理大量不同的对象。 在论文“评估使用稳定扩散生成的合成图像数据集”中,我们使用“稳定扩散”模型来研究哪些对象和类型表现得如此逼真,以便后续图像分类正确地分配…...
云计算:常用运维软件工具
目录 一、理论 1.云管理工具 2.虚拟化工具 3.容器管理工具 4.运维自动化工具 5.版本控制工具 6.配置管理工具 7.编辑器工具 8.代码质量工具 9.网络管理工具 10.数据库管理工具 11.数据中心设备管理工具 12.数据可视化工具 13.服务器管理工具 14.应用性能管理工具…...
多测师肖sir_高级金牌讲师_python的安装002
一、python安装 1、python包(我们目前学习的版本是3.7) python-3.7.3 版本 2、Python下载的官网:https://www.python.org/downloads/ 最新包:3.12 3、下载好python安装包,在新建一个python文件件,我们要…...
gin实现event stream
event stream是属于http的一种通信方式,可以实现服务器主动推送。原理于客户端请求服务器之后一直保持链接,服务端持续返回结果给客户端。相比较于websocket有如下区别: 基于http的通信方式,在各类框架的加持下不需要开发人员自己…...
pytorch中transform库中常用的函数有哪些及其用法?
在PyTorch的torchvision.transforms库中,有许多常用的图像变换函数可用于数据增强和预处理。下面列举了一些常用的函数及其用法: Resize(size): 调整图像大小为给定的尺寸。 transform transforms.Resize((256, 256))RandomCrop(size, paddingNone): 随…...
抖音手机实景无人直播间怎么搭建?
手机无人直播已成为用户直播和商家直播带货的一项热门技术趋势,为消费者提供了全新的观看体验。无人直播,顾名思义,即通过无人直播软件或数字人来进行无人直播。这一技术的广泛应用,不仅为短视频渠道带来了更丰富的玩法࿰…...
【新书推荐】当 Python 遇到 ChatGPT —— 自动化办公落地
文章目录 当 Python 遇到 ChatGPT:一种强大的组合1. 文本生成2. 自动翻译3. 对话生成4. 情感分析 新书推荐《Python自动化办公应用大全(ChatGPT版):从零开始教编程小白一键搞定烦琐工作(上下册)》前言内容简…...
RSA攻击:Smooth攻击
目录 前言:缘起 P-1光滑攻击 P1光滑攻击 前缀知识 Lucas-Subsquence(卢卡斯序列) 编码实现与理解 小试牛刀 [NCTF 2019]childRSA 引用 前言:缘起 Smooth攻击(光滑攻击),在最近刷题的时候总是能偶尔蹦跶到我的脑子里面。不是天天遇见它&am…...
什么是位域和位段?如何定义和使用位域?
位域(Bit Fields)是C语言中一种用于在数据结构中以位为单位对数据进行精确控制的技术。它们允许程序员将一个整数字段分割成多个更小的部分,每个部分可以存储不同的信息。位域通常在对内存节省要求高、数据压缩或硬件寄存器描述等情况下使用。…...
网络攻防备课笔记
从“踩点”到“创建后门”的攻击流程 踩点:攻击者在实施攻击前对目标进行初步的探索和调查的过程,包括收集目标的IP地址、开放的端口、服务版本、可能的漏洞等信息。 扫描:使用工具如Nmap、Masscan等对目标进行端口扫描,找出开放…...
Apache Solr9.3 快速上手
Apache Solr 简介 Solr是Apache的顶级开源项目,使用java开发 ,基于Lucene的全文检索服务器。 Solr比Lucene提供了更多的查询语句,而且它可扩展、可配置,同时它对Lucene的性能进行了优化。 安装 下载 : 下载地址解压 : tar -zxv…...
按关键字搜索淘宝商品API接口获取商品销量、优惠价、商品标题等参数示例
关键词搜索商品接口的作用是提供搜索功能,让用户根据关键词在电商平台上搜索商品,并根据搜索条件和偏好获取相关的商品列表和推荐结果,提高用户购物体验和准确度。对于电商平台而言,这个接口也能帮助用户发现更多商品、提升销量和…...
【外汇天眼】价格波动的节奏感:优化止盈方法!
止盈,依然是一种经验,而不是一种技术。它涉及到价格波动的灵活应对,以确保我们不会错失潜在的盈利,同时也不会让盈利被逆市波动所侵蚀。以下是关于如何有效实施止盈策略的一些建议: 首先,我们要明确&#…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
