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

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

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

相关文章

14-Kafka-Day03

第 5 章 Kafka 消费者 5.1 Kafka 消费方式 5.2 Kafka 消费者工作流程 5.2.1 消费者总体工作流程 一个消费者组中的多个消费者&#xff0c;可以看作一个整体&#xff0c;一个组内的多个消费者是不可能去消费同一个分区的数据的&#xff0c;要不然就消费重复了。 5.2.2 消费者…

WIC 图像处理初体验——读取像素的值

先放上运行结果&#xff1a; 可以发现红绿蓝是从后往前的。 必须以C方式编译代码&#xff01; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <wincodec.h>int main(void) {CoInitialize(nullptr);IWICImagingFactory* fac;CoCreateInstance(CLS…

勒索病毒猖狂,请提前做好安全防护,德迅卫士保护你的安全

随着互联网的飞速发展&#xff0c;网络安全问题日益凸显。其中&#xff0c;勒索病毒作为一种极具危害性的网络安全威胁&#xff0c;已经引起了广泛关注。为了帮助大家更好地预防和应对勒索病毒攻击&#xff0c;我们特地为您精心准备了这份超实用的勒索病毒自救预防指南。让我们…

数据中心技术:大数据时代的机遇与挑战

在大数据时代&#xff0c;数据中心网络对于存储和处理大量信息至关重要。随着云计算的出现&#xff0c;数据中心已成为现代技术的支柱&#xff0c;支持社交媒体、金融服务等众多行业。然而&#xff0c;生成和处理的大量数据带来了一些挑战&#xff0c;需要创新的解决方案。在这…

Android系统 抓trace方法(手机及车机)

1、先说说什么是trace trace是一种以perfetto.trace结尾的文件。一般用来分析卡顿、启动时间慢等问题&#xff0c;还可以用来分析方法耗时&#xff0c;android系统的性能、功耗等等问题。所需要使用到的网站是&#xff1a; Perfetto UI 他的前身是Systrace&#xff0c;不过Pe…

分布式事务的八种方案解析

分布式事务的八种方案解析 针对不同的分布式场景业界常见的解决方案有2PC、TCC、可靠消息最终一致性、最大努力通知等方案&#xff0c;以下总结8 种常见的解决方案&#xff0c;帮助大家在实际的分布式系统中更好地运用事务。 1.2PC 二阶段提交协议&#xff08;Two-phase commit…

2024年旅游与经济发展国际会议(ICTED 2024)

2024年旅游与经济发展国际会议&#xff08;ICTED 2024&#xff09; 2024 International Conference on Tourism and Economic Development 【重要信息】 大会地点&#xff1a;青岛 大会官网&#xff1a;http://www.icicted.com 投稿邮箱&#xff1a;icictedsub-conf.com 【注意…

第一个Java程序

编写第一个Java程序通常从经典的"Hello,World!"程序开始。下面是一个简单的Java程序示例&#xff0c;它将打印出"Hello, World!"到控制台&#xff1a; 1.编写代码&#xff1a; 打开文本编辑器&#xff08;如记事本、Notepad、Visual StudioCode等&#x…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十五)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 23 - 24 节&#xff09; P23《22.Stage模型-基本概念》 一个应用可以有很多的能力&#xff0c;每个能力可以成为一个 Ability Mod…

领域驱动设计(DDD)微服务架构模式总结

part1. Domain Driven Design(Strategic Design,Tactical Design) Top Down focus on business or activityy domain Ubiquitous Language:统一语言 Tactical Design Tools&#xff1a;战术性设计工具 Implementing Domain Driven Design(Event storming,DDD in code) DDD总结…

阿里巴巴橙点同学达摩院认证证书

网址&#xff1a;https://orange-class.com/ 为竞争激烈的职业做好充分的准备&#xff0c;无需相关经验立即开始学习。 阿里达摩院组织背书认证。 内容包括八个职业方向&#xff0c;涉及AI、开发、营销、设计等不同岗位&#xff1a; 其中&#xff0c;AI的高级认证情况如下&…

收藏丨世界地形图(超高清)

原文链接https://mp.weixin.qq.com/s?__bizMzUyNzczMTI4Mg&mid2247668146&idx2&snbebd2f4921994ab05ed47efdebe8e706&chksmfa770e8fcd008799bf1d1cabd62edca7f60a5c7a1ef9c0bacf3bdc102bccf0f12d54d6c07c49&token1405091246&langzh_CN&scene21#we…

Ubuntu 22.04.4 LTS openresty(Nginx) 通过Lua+Redis 实现动态封禁IP

1 系统环境 testiZbp1g7fmjea77vsqc5hmmZ:~$ cat /etc/os-release PRETTY_NAME"Ubuntu 22.04.4 LTS" NAME"Ubuntu" VERSION_ID"22.04" VERSION"22.04.4 LTS (Jammy Jellyfish)" VERSION_CODENAMEjammy IDubuntu ID_LIKEdebian HOME…

星谷案例入选新华社国家高端智库报告,彰显国际影响力!

中关村科学城星谷(创新园)以其在商业航天领域的卓越创新能力和显著产业影响力,被新华社国家高端智库专题组认可,并入选《更好赋能中国繁荣世界——新质生产力的理论贡献和实践价值》智库报告,成为新质生产力的典型代表案例。 这是中关村科学城星谷(创新园)继登上《新闻联播》后…

卓越的 App UI 风格引领潮流

卓越的 App UI 风格引领潮流

RAG实操教程langchain+Milvus向量数据库创建你的本地知识库 二

Miluvs 向量数据库 关于 Milvui 可以参考我的前两篇文章 • 一篇文章带你学会向量数据库Milvus&#xff08;一&#xff09;[1]• 一篇文章带你学会向量数据库Milvus&#xff08;二&#xff09;[2] 下面我们安装 pymilvus 库 pip install --upgrade --quiet pymilvus如果你…

如何开启Claude 3的Artifacts功能以及如何注册Claude3

就很突然&#xff0c;Claude 3.5&#xff0c;它来了&#xff01; Anthropic发布3.5系列第一个版本Claude 3.5 Sonnet。在多个关键指标中&#xff0c;GPT-4o几乎被吊打&#xff01; 另外Claude 3.5 Sonnet是免费的&#xff0c;提供了跟gpt-4o一样的次数。更高的速度和次数&…

python循环写入新样本到csv文件,并解决中文乱码的问题

新样本循环写入csv中 def write_sample(self):# 创建一个包含所有字段的列表&#xff0c;它将作为CSV的一行fields [基地, 拉线, 正/负极车间, 罐体编号, 样本ID, 工步序号, 检测结果]row_data [self.base_id, self.line_id, self.workshop_id, self.device, self.filename[:…

微信公众号多域名回调系统V1.5 源码

这是一款基于ThinkPHP6.0开发的微信公众号多域名回调系统。本系统有如下功能&#xff1a; 微信公众号多域名回调功能&#xff1a;微信公众号后台默认只能授权2个网页域名&#xff0c;用本系统突破这个限制&#xff0c;用同一个公众号对接无限多个网站。网站后台支持回调域名白…

王者荣耀图鉴皮肤怎么来的

王者荣耀图鉴皮肤怎么来的 最近一个王者荣耀图鉴开源很火 这个项目里面有很多的图片和音效资源&#xff0c;最简单的方法就是利用爬虫技术爬取这些图片资源。 第一步环境准备 Pyhton3.12macos系统 第二步查看王者荣耀官网 这些图片资源最简单的来源就是王者荣耀官网网站…