OJ项目【登录】——验证码、失败登录多次账户冻结、用户密码加密,我是如何实现的?
目录
前言
1、验证码
1.1、引入pom
1.2、前端核心代码
1.3、后端核心代码
2、账户冻结
2.1、思路:
2.2、核心代码示例:
3、密码加密——加盐算法
3.1、思路:
3.2、代码实现示例:
4、小结:展示我的项目
4.1、后端代码:
4.2、效果展示:
前言
前端代码,我只展示核心代码,其他的代码需要小伙伴们自行编写哦~
项目是Spring项目,需要小伙伴们有一点点Spring基础~
我这些实现方式,只是一个参考,并不是最优解~
1、验证码
验证码这里,我们使用的是easy-captcha,对他感兴趣的伙伴,可以自行查一下资料,下面,我只实现4位验证码,有字母和数字组成的这种~
1.1、引入pom
<!-- 验证码 --><dependency><groupId>com.github.whvcse</groupId><artifactId>easy-captcha</artifactId><version>1.6.2</version></dependency>
1.2、前端核心代码
准备一个html:
<div class="row"><input type="text" id="authCode" class="form-control" name="verifyCode" placeholder="请输入验证码" required="true"><img class="imgCode" alt="点击图片刷新!" src="/common/kaptcha" onclick="this.src='/common/kaptcha?d='+new Date()*1">
</div>
说明:
- 就是准备了一个input输入框,供我们输入验证码;准备一个图片,显示我们的验证码
- 重点要说的就是照片img标签中,src的路径是一个URL,也就是说,这张照片的来源就是从这个URL来的;点击照片时,会触发onclick事件,这个事件会改变该图片src的属性,新的src为:'/common/kaptcha?d='new Date()*1,这个表达式会生成一个新的日期时间戳,并将其附加到图片的URL后面,从而获取一个新的图片~ 【src中的URL由后端实现~】
1.3、后端核心代码
准备一个controller类:
package com.example.demo.controller;import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Controller
@RequestMapping("/common")
public class commonCotroller {@GetMapping("/kaptcha")public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {httpServletResponse.setHeader("Cache-Control", "no-store");httpServletResponse.setHeader("Pragma", "no-cache");httpServletResponse.setDateHeader("Expires", 0);httpServletResponse.setContentType("image/gif");// 三个参数分别为宽、高、位数SpecCaptcha captcha = new SpecCaptcha(150, 30, 4);// 设置字体captcha.setCharType(Captcha.FONT_9);// 验证码存入sessionhttpServletRequest.getSession().setAttribute("authCode", captcha.text().toLowerCase());// 输出图片流captcha.out(httpServletResponse.getOutputStream());}
}
说明:

到这里,验证码的模块就实现完成了,具体,在登录时如何操作的,下面第四点中会举例说明~
2、账户冻结
2.1、思路:
关于账户冻结,我是在数据库设计中,给用户表添加了两个字段:状态state和冷却时间lTime。默认的state值为1,默认的lTime为0。当用户每登录错误一次时,给该用户的state加一;当state大于3时,表示该用户已经连续错误登录三次了,该账户将被冻结;冻结时间设置:获取现在的时间戳加上30000,换算成秒就是,给当前时间加上30s;在登录前,先验证给账户是否被冻结了,也就是查看当前时间戳是否小于该用户数据库中存储的冻结时间戳~
2.2、核心代码示例:
@RequestMapping("/login")public AjaxResult login(HttpServletRequest request, String username, String password,String authCode) {//0.参数校验if(!StringUtils.hasLength(username) || username.length() > 50) {return AjaxResult.fail("用户名输入违法,请重新输入!");}if(!StringUtils.hasLength(password) ||password.length() > 10) {return AjaxResult.fail("密码输入违法,请重新输入!");}if(!StringUtils.hasLength(authCode)) {return AjaxResult.fail("验证码不能为空!");}//1、校验验证码是否正确相关操作// ...//2、验证该用户的登录功能是否被冻结//2.1、先根据用户名查询出数据中的username的信息Userinfo userinfo = userService.getUserExist(username);if(userinfo == null) {return AjaxResult.fail("用户名或密码错误,请重新输入~");}//2.2、查看该用户的登录功能是否被冻结了if(userinfo.getState() > 3 && userinfo.getLTime() > System.currentTimeMillis()) {return AjaxResult.fail("登录已锁定,请等待" + (userinfo.getLTime() - System.currentTimeMillis())/1000 + "秒后重试");} else if(userinfo.getState() > 3 && userinfo.getLTime() < System.currentTimeMillis()) {//放置state为1--时间过了,解除冻结userinfo.setState(1);userService.stateOne(userinfo);}//3、对比密码是否正确相关操作// ...//3.3、可以正确登录,将之间的state标记恢复原状userinfo.setState(1);userService.stateOne(userinfo);//4、可以正确登录,后续操作// ....return AjaxResult.success("登陆成功");}
上述代码还是很好理解的,我就不做过多解释了~
3、密码加密——加盐算法
我们准备一个类,这个类主要就是处理密码的加密和验证密码操作。
3.1、思路:
- 1:我们使用UUID生成一个随机盐值;
- 2:密码加工1:把密码和盐值加起来,然后使用MD5哈希算法进行加密
- 3:密码加工2:为了后续可以取出盐值,从而来验证密码是否正确,所以最终的密码:盐值 + "$" + 密码加工1 【这里是以字符串的形式拼接的】
- 4:密码验证:先通过$符,取出盐值,再通过相同的加密方式加密,验证新密码加密后的值是否与数据库中的值相等~
3.2、代码实现示例:
public class PasswordUtils {//密码加盐:public static String encrypt(String password) {//1、生成一个32位的盐值String salt = UUID.randomUUID().toString().replace("-","");//2、生成加盐后的密码,并将盐值和加盐后的密码并在一起return splicing(password,salt);}//验证密码是否正确public static boolean check(String inputPassword,String finPassword) {//1、获取saltString salt = finPassword.split("\\$")[0];//2、使用一样的盐值,加密String inputFinPassword = splicing(inputPassword,salt);if(inputFinPassword.equals(finPassword)) {return true;}return false;}//密码加盐的辅助方法private static String splicing(String password, String salt) {//1、使用md5生成加盐后的密码1String finpassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());//2、返回最终密码【盐值 $ 密码1】return (salt + "$" +finpassword);}
}
4、小结:展示我的项目
上述重复的代码,我就不展示了,展示一下,我的UserController类的实现吧~
4.1、后端代码:
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/login")public AjaxResult login(HttpServletRequest request, String username, String password,String authCode) {//0.参数校验if(!StringUtils.hasLength(username) || username.length() > 50) {return AjaxResult.fail("用户名输入违法,请重新输入!");}if(!StringUtils.hasLength(password) ||password.length() > 10) {return AjaxResult.fail("密码输入违法,请重新输入!");}if(!StringUtils.hasLength(authCode)) {return AjaxResult.fail("验证码不能为空!");}//1、校验验证码是否正确HttpSession session = request.getSession();//默认为true,有则获取,无则会先新建再获取String trueAuthCode = (String) session.getAttribute("authCode");if(!trueAuthCode.equalsIgnoreCase(authCode)) {return AjaxResult.fail("验证码输入错误!");}//2、验证该用户的登录功能是否被冻结//2.1、先根据用户名查询出数据中的username的信息Userinfo userinfo = userService.getUserExist(username);if(userinfo == null) {return AjaxResult.fail("用户名或密码错误,请重新输入~");}//2.2、查看该用户的登录功能是否被冻结了if(userinfo.getState() > 3 && userinfo.getLTime() > System.currentTimeMillis()) {return AjaxResult.fail("登录已锁定,请等待" + (userinfo.getLTime() - System.currentTimeMillis())/1000 + "秒后重试");} else if(userinfo.getState() > 3 && userinfo.getLTime() < System.currentTimeMillis()) {//放置state为1--时间过了,解除冻结userinfo.setState(1);userService.stateOne(userinfo);}//3、对比密码是否正确if(!PasswordUtils.check(password,userinfo.getPassword())) {//3.1、如果密码错误,则数据库中标记+1userinfo.setState(userinfo.getState() + 1);//给数据库中的state+1userService.stateOne(userinfo);//3.2、错误次数达标,设置冷却时间if(userinfo.getState() > 3) {userinfo.setLTime(System.currentTimeMillis() + 30000);userService.setLTime(userinfo);}return AjaxResult.fail("用户名或密码错误,请重新输入~");}//3.3、可以正确登录,将之间的标记恢复原状userinfo.setState(1);userService.stateOne(userinfo);//4、可以正确登录,给session中存储给用户的信息-放置session信息session.setAttribute(AppVariable.USER_SESSION_KEY,userinfo);//5、返回登陆成功return AjaxResult.success("登陆成功");}
}
前端代码,我就不展示了~ 大家自行发挥~~~
4.2、效果展示:


好啦,本期就到这里咯,对效果展示中的弹窗感兴趣的伙伴,可以看看持续关注我后续的动态,会出一个简单的教程
相关文章:
OJ项目【登录】——验证码、失败登录多次账户冻结、用户密码加密,我是如何实现的?
目录 前言 1、验证码 1.1、引入pom 1.2、前端核心代码 1.3、后端核心代码 2、账户冻结 2.1、思路: 2.2、核心代码示例: 3、密码加密——加盐算法 3.1、思路: 3.2、代码实现示例: 4、小结:展示我的项目 4…...
js鼠标点击添加图标并获取图标的坐标值
给这个图片添加摄像头图标,并获取图标的坐标值,也就是图标的css样式是positon:absolute,获取left和top的值。 图片1 思路是这样的,获取这里的长度, 图片2 1.鼠标点击时距浏览器的左边距离和上边距离,相当于(0,0)坐标 …...
How to add a jar to a project in eclipse?
Project -> Properties -> Java Build Path -> Libraries -> Add External JARs...
动手实现H5仿原生app前进后退切换效果
动手实现H5仿原生app前进后退切换效果 前言 最近在优化H5页面,我注意到当开发完成的移动端H5页面嵌入到微信小程序或者原生app中时,当触发页面路由切换会与原生app看上去有点格格不入,因为H5页面<router-view>切换路由时是直接替换了…...
【标准化封装 SOT系列 】 D SOT-323 SOT-363
〇、关键词 SC70 。 一、D部分 SOT-323 SOT-363 这个应该叫SC-70可能更合适,典型特征 pin 间距 0.65mm ; body size 2.0mm1.25mm 这一节很像SOT-23,即A部分,因此也是最容易被混淆的。 二、SC70-3 / -5/ -6 鉴于此,封装最好给…...
软件测试肖sir__python之ui自动化实战和讲解03
python之ui自动化实战和讲解...
Kafka序列化反序列化解析、kafka schema
Kafka序列化反序列化解析、kafka schema。 kafka有自己的rpc协议,即nio bytebuf中的数据格式,详见之前的kafka相关介绍的文章。这里我们来看一下大家常用,有时又疑惑的序列化反序列化,对应rpc协议中的records,kafka叫Serdes,实际上也是字面上的意思serialize and deseri…...
谷歌浏览器中如何审查隐藏的元素
谷歌浏览器中如何审查隐藏的元素 方法1: 打开控制台 先鼠标移上先显示出来 快捷键按 CtrlShiftC,只能简单查看宽高,做不到复杂的的样式查询 方法2: 在控制台输入一个以下代码, 并保留光标在控制台闪烁,鼠标移上去显示…...
【vue】使用less报错:显示this.getOptions is not a function
在vue-cli中使用 lang“less” 时报错: Module build failed: TypeError: this.getOptions is not a function at Object.lessLoader 原因:版本过高所致,所用版本为 解决:降低版本:npm install less-loader4.1.0 --s…...
代码随想录第48天 | ● 739. 每日温度 ● 496.下一个更大元素 I
739. 每日温度 /*** param {number[]} temperatures* return {number[]}*/ var dailyTemperatures function(temperatures) {const ntemperatures.lengthconst resArray(n).fill(0)const stack[] // 递增栈:用于存储元素右面第一个比他大的元素下标stack.push(0…...
团购页面.
<!DOCTYPE html> <html><head><title>团购</title><meta http-equiv"content-type" content"text/html; charsetutf-8"/><meta name"apple-mobile-web-app-capable" content"yes"/><lin…...
linux-系统日志/var/log/简介
日志在排查文件的时候至关重要,在Linux上一般跟系统相关的日志默认都会放到/var/log下面。 1、/var/log/boot.log 一般包含系统启动时的日志,包括自启动的服务。 2、/var/log/btmp 记录所有失败登录信息。非文本文件,可以使用last -f /va…...
2022最新版-李宏毅机器学习深度学习课程-P26RNN-2
一、RNN网络结构 与时间有关的反向传播(每次不同) 损失函数 实验其实不容易跑,因为他的损失函数曲线幅度很大 画出来差不多是这个样子。突然一下升高是因为从右到左碰到陡峭的地方梯度一下变大了,所以弹回去了。 原作者在训练时…...
docker 配置mongoDB
## 拉取镜像 docker pull mongo## 设置默认账号密码 test:test 默认数据 test docker run -d --name mongo-container -e MONGO_INITDB_ROOT_USERNAMEtest -e MONGO_INITDB_ROOT_PASSWORDtest -e MONGO_INITDB_DATABASEtest -p 27017:27017 mongo...
基于PHP的宠物爱好者交流平台管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...
盘点数据采集中14种常见的反爬策略
引言 随着互联网的飞速发展, 爬虫技术不断演进, 为数据获取和信息处理提供了强大支持。然而, 滥用爬虫和恶意爬取数据的行为日益增多, 引发了反爬虫技术的兴起。在这场看似永无止境的 技术较量 中, 爬虫与反爬虫技术相互博弈、角力。本文将简单过下目前已知的几种反爬策略, 旨…...
直播预告:防御升级-SMC2精准对抗账号劫持和漏洞威胁
当邮箱账号出现疑似被盗风险和遭受外部攻击时,企业管理员需要尽快发现或排除潜在威胁,并采取处置措施,阻止威胁扩大。 那么面对账号失陷风险,企业管理员如何做到账号异常行为的精准检测和即时处置?当账号遭受外部攻击时…...
班主任好物 班级查询系统来啦
哈喽各位,作为一名教育博主,今天我要给大家分享一个班主任的好物——班级查询系统!这个系统可真是太方便了呢,那么,这个神秘的班级查询系统到底是什么呢?别急,听我慢慢道来。 班级查询系统&…...
【性能测试】使用JMeter对code论坛进行压力测试
1.项目介绍 项目简介 code 论坛是一个技术交流社区。主要功能有发布帖子,查看帖子,评价帖子,删除帖子,点赞帖子,站内信,个人中心,修改个人信息等。是一个基于 Spring 的前后端分离项目。 项目链…...
Windows 事件日志监控
Windows 事件日志是记录 Microsoft 系统上发生的所有活动的文件,在 Windows 环境中,将记录系统上托管的系统、安全性和应用程序的事件,事件日志提供包含有关事件的详细信息,包括日期、时间、事件 ID、源、事件类型和发起它的用户。…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
