当前位置: 首页 > news >正文

ruoyi登录功能源码分析

Ruoyi登录功能源码分析

上一篇文章我们分析了一下若依登录验证码生成的代码,今天我们来分析一下登录功能的代码

1、发送登录请求

前端通过http://localhost/dev-api/login向后端发送登录请求并携带用户的登录表单

在后端中的com.ruoyi.web.controller.system包下的SysLoginController响应登录信息,后端接受到请求后首先将操作信息设置为成功,然后对用户的登录表单进行校验,校验通过返回token

在这里插入图片描述

2、登录校验

接下来我们来看一看登录校验的代码

   /*** 校验验证码* * @param username 用户名* @param code 验证码* @param uuid 唯一标识* @return 结果*/public void validateCaptcha(String username, String code, String uuid){// 判断当前是否需要生成验证码boolean captchaEnabled = configService.selectCaptchaEnabled();if (captchaEnabled){// 根据生成验证码时返回给前端的uuid拼接验证码在redis中的key值String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");// 从redis中获取验证码String captcha = redisCache.getCacheObject(verifyKey);// 删除验证码redisCache.deleteObject(verifyKey);if (captcha == null){// 开启异步任务记录用户信息AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));throw new CaptchaExpireException();}if (!code.equalsIgnoreCase(captcha)){AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));throw new CaptchaException();}}}

2.1 前置校验

后端在进行登录校验时首先会对登录验证码进行校验然后会对用户名和密码进行前置校验,验证码校验上一篇文章中已经说过所以这一章不再赘述

登录前置校验会调用loginPreCheck函数

        // 验证码校验validateCaptcha(username, code, uuid);// 登录前置校验loginPreCheck(username, password);
    /*** 校验验证码* * @param username 用户名* @param code 验证码* @param uuid 唯一标识* @return 结果*/public void validateCaptcha(String username, String code, String uuid){// 判断当前是否需要生成验证码boolean captchaEnabled = configService.selectCaptchaEnabled();if (captchaEnabled){// 根据生成验证码时返回给前端的uuid拼接验证码在redis中的key值String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");// 从redis中获取验证码String captcha = redisCache.getCacheObject(verifyKey);// 删除验证码redisCache.deleteObject(verifyKey);if (captcha == null){// 开启异步任务记录用户信息AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));throw new CaptchaExpireException();}if (!code.equalsIgnoreCase(captcha)){AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));throw new CaptchaException();}}}

2.2、登录认证

接下来是生成token,首先定义一个UsernamePasswordAuthenticationToken对象用来存放用户登录提供的认证凭证表示一个为认证的请求,然后是将用户的提供的登录认证凭证放到线程池的上下文中,调用authenticationManager的authenticate方法进行认证,最后记录登录信息并返回token

    /*** 登录验证* * @param username 用户名* @param password 密码* @param code 验证码* @param uuid 唯一标识* @return 结果*/public String login(String username, String password, String code, String uuid){// 验证码校验validateCaptcha(username, code, uuid);// 登录前置校验loginPreCheck(username, password);// 用户验证Authentication authentication = null;try{// 将用户名和密码存放到UsernamePasswordAuthenticationToken中UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);// 将authenticationToken放到线程池的上下文中AuthenticationContextHolder.setContext(authenticationToken);// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername// 对用户信息进行认证authentication = authenticationManager.authenticate(authenticationToken);}catch (Exception e){if (e instanceof BadCredentialsException){// 认证失败记录错误信息AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));throw new UserPasswordNotMatchException();}else{AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));throw new ServiceException(e.getMessage());}}finally{// 清除上下文中的信息AuthenticationContextHolder.clearContext();}// 认证成功 记录信息AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));// 从认证成功的authentication中取出用户信息LoginUser loginUser = (LoginUser) authentication.getPrincipal();// 记录登录信息recordLoginInfo(loginUser.getUserId());// 生成tokenreturn tokenService.createToken(loginUser);}

通过SpringSecurity的过滤器链调用UserDetailsServiceImpl进行用户名和密码的校验

/*** 用户验证处理** @author ruoyi*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);@Autowiredprivate ISysUserService userService;@Autowiredprivate SysPasswordService passwordService;@Autowiredprivate SysPermissionService permissionService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{// 根据用户名查询用户SysUser user = userService.selectUserByUserName(username);if (StringUtils.isNull(user)){// 用户为空log.info("登录用户:{} 不存在.", username);throw new ServiceException(MessageUtils.message("user.not.exists"));}else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())){log.info("登录用户:{} 已被删除.", username);throw new ServiceException(MessageUtils.message("user.password.delete"));}else if (UserStatus.DISABLE.getCode().equals(user.getStatus())){log.info("登录用户:{} 已被停用.", username);throw new ServiceException(MessageUtils.message("user.blocked"));}// 校验密码passwordService.validate(user);return createLoginUser(user);}public UserDetails createLoginUser(SysUser user){return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));}
}

2.3 生成token令牌

生成token

    /*** 创建令牌** @param loginUser 用户信息* @return 令牌*/public String createToken(LoginUser loginUser){String token = IdUtils.fastUUID();loginUser.setToken(token);setUserAgent(loginUser);refreshToken(loginUser);Map<String, Object> claims = new HashMap<>();claims.put(Constants.LOGIN_USER_KEY, token);return createToken(claims);}

设置用户信息

    /*** 设置用户代理信息** @param loginUser 登录信息*/public void setUserAgent(LoginUser loginUser){UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));String ip = IpUtils.getIpAddr();loginUser.setIpaddr(ip);loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));loginUser.setBrowser(userAgent.getBrowser().getName());loginUser.setOs(userAgent.getOperatingSystem().getName());}

将token缓存到redis并设置过期时间(默认30分钟)

    /*** 刷新令牌有效期** @param loginUser 登录信息*/public void refreshToken(LoginUser loginUser){loginUser.setLoginTime(System.currentTimeMillis());loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);// 根据uuid将loginUser缓存String userKey = getTokenKey(loginUser.getToken());redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);}
  • expireTime * MILLIS_MINUTE);
    // 根据uuid将loginUser缓存
    String userKey = getTokenKey(loginUser.getToken());
    redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);

    }


到就登录成功了并且后端成功返回token

相关文章:

ruoyi登录功能源码分析

Ruoyi登录功能源码分析 上一篇文章我们分析了一下若依登录验证码生成的代码&#xff0c;今天我们来分析一下登录功能的代码 1、发送登录请求 前端通过http://localhost/dev-api/login向后端发送登录请求并携带用户的登录表单 在后端中的com.ruoyi.web.controller.system包下…...

推动产业数字化转型,六个方面引领变革

从工业经济时代走向数字经济时代&#xff0c;世界经济发生着全方位、革命性的变化&#xff0c;产业数字化便是最显著的表现之一。当前&#xff0c;产业数字化不断深入发展&#xff0c;平台经济、工业互联网、智能制造等新业态、新模式不断涌现&#xff0c;成为了数字经济的重要…...

设施布置之车间布局优化SLP分析

一 物流分析&#xff08;Flow Analysis&#xff09; 的基本方法 1、当物料移动是工艺过程的主要部分时&#xff0c;物流分析就是工厂布置设计的核心工作&#xff0c;也是物料搬运分析的开始。 2、零部件物流是该部件在工厂内移动时所走过的路线&#xff0c; 物流分析不仅要考虑…...

帕金森的锻炼方式

帕金森病&#xff0c;这个看似陌生的名词&#xff0c;其实离我们并不遥远。它是一种常见的神经系统疾病&#xff0c;影响着许多中老年人的生活质量。虽然帕金森病目前尚无根治之法&#xff0c;但通过科学合理的日常锻炼&#xff0c;可以有效缓解病情&#xff0c;提高生活质量。…...

PyTorch(一)模型训练过程

PyTorch&#xff08;一&#xff09;模型训练过程 #c 总结 实践总结 该实践从「数据处理」开始到最后利用训练好的「模型」预测&#xff0c;感受到了整个模型的训练过程。其中也有部分知识点&#xff0c;例如定义神经网络&#xff0c;只是初步的模仿&#xff0c;有一个比较浅的…...

windows下cmd命令行模式中cd变换路径命令无效的解决办法

一&#xff0c;出现的情况 二&#xff0c;解决方法 当出现转换盘的时候打开 cmd 之后可能是无法生效的 &#xff0c;因为在cmd 中转换盘首先需要用到换盘符 。 Solve1 : 先进行换盘 C: c: // 转换到 C盘 D: d: // 转化到 D盘 Solve2 : 直接进行强转 cd /dE:\ACM算法资源\XCP…...

收藏||电商数据采集流程||电商数据采集API接口

商务数据分析的流程 第一步&#xff1a;明确分析目的。首先要明确分析目的&#xff0c;并把分析目的分解成若干个不同的分析要点&#xff0c;然后梳理分析思路&#xff0c;最后搭建分析框架。 第二步&#xff1a;数据采集。主流电商API接口数据采集&#xff0c;一般可以通过数…...

修改源码,打patch包,线上环境不生效

1.首先看修改的源码文件是否正确 在node_modules中&#xff0c;找对应的包&#xff0c;然后查看包中package.json 的main和module。如果用require引入&#xff0c;则修改lib下面的组件&#xff0c;如果是import引入则修改es下面的文件 main 对应commonjs引入方式的程序入口文件…...

NUC980-OLED实现全中文字库的方法

1.背景 有一个产品&#xff0c;客户需要屏幕展示一些内容&#xff0c;要带一些中文&#xff0c;实现了OLED12864的驱动&#xff0c;但是它不带字库&#xff0c;现在要实现OLED全字库的显示 2.制作原始字库 下载软件pctolcd2002 设置 制作字库 打开原始文件 用软件自带的&…...

UEFI 启动原理及qemu 虚拟化中使用

UEFI 启动原理及qemu 虚拟化中使用 什么是BIOS&#xff1f;什么是 UEFI&#xff1f; 什么是BIOS&#xff1f; 计算机启动时会加载 BIOS&#xff0c;以初始化和测试硬件功能。它使用 POST 或 Power On Self Test 来确保硬件配置有效且工作正常&#xff0c;然后寻找存储引导设…...

35、正则表达式

一、正则表达式命令 正则表达式&#xff1a;匹配的是文本内容&#xff0c;linux的文本三剑客都是针对文本内容。 ​ grep 过滤文本内容 ​ sed 针对文本内容进行增删改查 ​ awk 按行取列 文本三剑客----都是按照行进行匹配。 1.1、grep筛选&#xff1a; grep的作用就是…...

Ubuntu20.04中复现FoundationPose

Ubuntu20.04中复现FoundationPose 文章目录 Ubuntu20.04中复现FoundationPose1.安装cuda和cudnn2.下载相关资源3.环境配置4.运行model-based demo5.运行ycbv demoReference &#x1f680; 非常重要的环境配置 &#x1f680; ubuntu 20.04cuda 11.8.0cudnn v8.9.7python 3.9.19…...

【Qt快速入门(四)】- QLabel文本框的使用

目录 Qt快速入门&#xff08;四&#xff09;- QLabel文本框的使用QLabel文本框的使用QLabel的基本用法1. 创建和设置文本2. 动态设置文本 设置文本样式1.设置字体和颜色2.文本对齐方式3.富文本显示 显示图片QLabel的交互功能可点击标签 QLabel的高级特性1.缩放图片以适应标签大…...

用Python设置Excel工作表网格线的隐藏与显示

Excel表格界面的直观性很大程度上得益于表格中的网格线设计&#xff0c;这些线条帮助用户精确对齐数据&#xff0c;清晰划分单元格。网格线是Excel界面中默认显示的辅助线&#xff0c;用于辅助定位&#xff0c;与单元格边框不痛&#xff0c;不影响打印输出。然而&#xff0c;在…...

自回归模型胜过扩散模型:用于可扩展图像生成的 Llama

&#x1f4dc; 文献卡 Autoregressive Model Beats Diffusion: Llama for Scalable Image Generation作者: Peize Sun; Yi Jiang; Shoufa Chen; Shilong Zhang; Bingyue Peng; Ping Luo; Zehuan YuanDOI: 10.48550/arXiv.2406.06525摘要: We introduce LlamaGen, a new family …...

访问外网的安全保障——反向沙箱

反向沙箱作为一种网络安全技术&#xff0c;其核心理念在于通过构建一个隔离且受控的环境&#xff0c;来有效阻止潜在的网络威胁对真实系统的影响。在当今日益复杂的网络环境中&#xff0c;如何借助反向沙箱实现安全上网&#xff0c;已成为众多用户关注的焦点。 随着信息化的发…...

【绝对有用】C++ 字符串进行排序、vector增加内容 和 剔除值

在 C 中对字符串进行排序&#xff0c;可以使用标准库中的 std::sort 函数。std::sort 函数可以用于容器或范围内的元素排序&#xff0c;包括字符串中的字符。以下是一个简单的示例代码&#xff0c;展示了如何对字符串中的字符进行排序&#xff1a; #include <iostream> …...

GenICam标准(一)

系列文章目录 GenICam标准&#xff08;一&#xff09; GenICam标准&#xff08;二&#xff09; GenICam标准&#xff08;三&#xff09; GenICam标准&#xff08;四&#xff09; GenICam标准&#xff08;五&#xff09; GenICam标准&#xff08;六&#xff09; 文章目录 系列文…...

【Redis】分布式锁基本理论与简单实现

目录 分布式锁解释作用特性实现方式MySQL、Redis、Zookeeper三种方式对比 原理 reids分布式锁原理目的容错redis简单分布式锁实现锁接口实现类下单场景的实现容错场景1解决思路优化代码 容错场景2Lua脚本Redis利用Lua脚本解决多条命令原子性问题 释放锁的业务流程Lua脚本来表示…...

Web开发技术大作业(HTML\CSS\PHP\MYSQL\JS)

从6月13日到6月15日&#xff0c;经过一系列的操作&#xff0c;终于把老师布置的大作业写完了&#xff0c;虽然有很多水分&#xff0c;很多东西都是为了应付&#xff08;特别是最后做的那几个网页&#xff09;&#xff0c;真的是惨不忍睹&#xff0c;不过既然花时间写了&#xf…...

【全开源】沃德会务会议管理系统(FastAdmin+ThinkPHP+Uniapp)

沃德会务会议管理系统一款基于FastAdminThinkPHPUniapp开发的会议管理系统&#xff0c;对会议流程、开支、数量、标准、供应商提供一种标准化的管理方法。以达到量化成本节约&#xff0c;风险缓解和服务质量提升的目的。适用于大型论坛、峰会、学术会议、政府大会、合作伙伴大会…...

尚硅谷大数据技术ClickHouse教程-笔记01【ClickHouse单机安装、数据类型】

视频地址&#xff1a;一套上手ClickHouse-OLAP分析引擎&#xff0c;囊括Prometheus与Grafana_哔哩哔哩_bilibili 01_尚硅谷大数据技术之ClickHouse入门V1.0 尚硅谷大数据技术ClickHouse教程-笔记01【ClickHouse单机安装、数据类型】尚硅谷大数据技术ClickHouse教程-笔记02【表引…...

生产管理系统看板,在自动化设备领域的创新应用

在自动化设备领域&#xff0c;生产管理系统看板的创新应用是一项引人注目的技术进步。以广州某自动化设备有限公司为例&#xff0c;他们是一家涂装工程设备制造企业&#xff0c;将讯鹏生产管理系统电子看板成功应用于全自动立式静电喷粉线、卧式静电喷粉线、氟碳喷涂生产线等领…...

分享一个图片转换工具XnConvert

目录 stablediffusion3 生成图片效果图图片转换工具XnConvertpixzip stablediffusion3 生成图片效果图 今天在使用stablediffusion3时&#xff0c;尝试生成了几张Java的图片&#xff0c;发现确实很好看&#xff0c;文生图的效果超出我的预期&#xff0c;忍不住想要给自己的csd…...

Nginx后端超时504重复请求

在一次业务中客户端请求osb平台再经过nginx转发后端&#xff0c;开发反馈请求次数大于1导致问题&#xff0c;经排查客户端请求一次&#xff0c;osb平台设置超时为30s&#xff0c;nginx配置等待上游服务器响应时最多等待30秒 部分配置文件 upstream xx {server 10.6.6.1:8080 w…...

环境配置04:Pytorch下载安装

说明&#xff1a; 显存大于4G的建议使用GPU版本的pytorch&#xff0c;低于4G建议使用CPU版本pytorch&#xff0c;直接使用命令安装对应版本即可 GPU版本的pytorch的使用需要显卡支持&#xff0c;需要先安装CUDA&#xff0c;即需要完成以下安装 1.查看已安装CUDA版本 GPU对应…...

【杂记-浅谈私有地址】

私有地址 一、私有IP地址概述1、私有IP地址的实用性2、私有IP地址的局限性 二、私有IP地址范围1、A类私有地址2、B类私有地址3、C类私有地址 三、私有IP地址与公网IP地址的区别 一、私有IP地址概述 私有IP地址是互联网工程任务组&#xff08;IETF&#xff09;为组织机构内部使…...

Java基础学习-数组

目录 数组定义 注意点&#xff1a; 地址值是数组在内存中实际存储的地址。 案例遍历&#xff1a;遍历数组得到每一个元素&#xff0c;求数组里面所有数据和 案例&#xff1a;定义数组&#xff0c;遍历能被3整除的数字 案例&#xff1a;遍历一个数组&#xff0c;奇数将当前…...

爬虫 pandas Linux Flume Pig填空题

目录 试卷&#xff1a;Python网络数据处理 答案 试卷&#xff1a;Pandas基础操作 答案 试卷&#xff1a;Linux基础指令 答案 试卷&#xff1a;Apache Flume基础指令 答案 试卷&#xff1a;Apache Pig基础指令 答案&#xff1a; Hadoop题 答案 试卷&#xff1a;Pyth…...

Spring框架中哪些地方使用了反射

Spring框架中哪些地方使用了反射&#xff1f; 1. 依赖注入&#xff1a;Spring 使用反射机制获取对象并进行属性注入&#xff0c;从而实现依赖注入。 2. AOP&#xff1a;Spring AOP 使用 JDK 动态代理或者 CGLIB 字节码增强技术来实现 AOP 的切面逻辑&#xff0c;这其中就包含…...

优秀的网站建设解决方案/网络营销软件

打开终端输入su进入根目录1 卸载旧版本docker1.较旧的Docker版本称为docker或docker-engine。如果已安装这些程序&#xff0c;请卸载它们以及相关的依赖项。sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrot…...

微信小程序可以做音乐网站吗/当下最流行的营销方式

从昨天开始就在刷手机&#xff0c;换了各种rom&#xff0c;今天中午总算刷了一个还算不错的rom&#xff0c;用了不到半天&#xff0c;晚上突发奇想修改了以下/system/build.prop文件&#xff0c;哪知手机重启后再也进不了系统&#xff0c;真是悲剧。不想再刷了&#xff0c;于是…...

网站域名查主机/百度快速优化软件

我的第一篇博客&#xff0c;咱们直奔主题。先上个效果图在android中自定义PopupWindow&#xff1a;1、首先定义好你想要显示的窗口的布局文件&#xff0c;再实例化一个View对象&#xff1a;窗口布局可灵活变化&#xff0c;dialog_layout.xml代码如下&#xff1a;android:id&quo…...

怀化二手车网站/黑马培训价目表

2019独角兽企业重金招聘Python工程师标准>>> New XAMPP security concept: Access to the requested directory is only available from the local network. This setting can be configured in the file “httpd-xampp.conf”. 解决办法&#xff1a; 打开httpd-xam…...

邯郸专业做wap网站/网络市场调研

第一步&#xff1a;下载detours3.0&#xff0c;安装detours 第二步&#xff1a;构建库文件&#xff0c;nmake编译 第三步&#xff1a;包含库文件和头文件 #include “detours.h” //载入头文件 #pragma comment(lib,”detours.lib”) //表明要使用静态库 第四步&#xff1…...

南京做网站找哪家/百度的特点和优势

官网hbase有两种获得connection的方法&#xff0c;分别是如下两种&#xff1a;Connection connection ConnectionFactory.createConnection(conf);Connection connection HConnectionManager.createConnection(conf);这两种方法还有重载方法&#xff0c;在重载方法里可以传递…...