Java 图片验证码需求分析

在这里插入图片描述

💗wei_shuo的个人主页

💫wei_shuo的学习社区

🌐Hello World !


图片验证码

需求分析

在这里插入图片描述

  • 连续因输错密码而登录失败时,记录其连续输错密码的累加次数;若在次数小于5时,用户输入正确的密码并成功登录,则次数被清零
  • 连续5次因输错密码而登录失败后,系统弹框提示【您已连续5次输入错误的密码,暂时不允许登录,请10分钟后再次尝试登录】;点击提示框中的【确定】按钮,提示框被关闭
  • 10分钟内再次尝试登录,则系统弹框提示【您已连续5次输入错误的密码,暂时不允许登录,7分43秒后可再次尝试登录】;点击提示框中的【确定】按钮,提示框被关闭;注:提示框中的剩余时间动态倒数至0分0秒
  • 10分钟后,用户可再次尝试登录;此时,若用户在输错密码次数小于5次时成功登录,则其连续输错密码的次数、曾被锁定1次的信息被清空归零;反之,若用户再次连续5次输错密码,则系统弹框提示【您已连续10次输入错误的密码,账号已被锁定、不允许登录,请联系管理员解锁】;点击提示框中的【确定】按钮,提示框被关闭。此后,用户每次用该账号尝试登录时,均弹出此提示框。此时,在运营端,该用户详情页面中的【登录状态】已被自动切换为【锁定】。用户须主动联系莫族密运营人员,运营人员确认用户没有被盗号、遭遇网络攻击等风险后,主动将其【登录状态】置为【解锁】;此时,用户连续输错密码的次数、曾被锁定2次的信息被清空归零
  • 用户登录时,须输入正确的【验证码】
  • 若用户看不清,则可点击【看不清?换一张】字样,也可直接点击验证码部件,点击后自动刷新验证码
  • 点击【登录】按钮后,【用户名】、【密码】、【验证码】这3项但凡有1项校验不通过,则登录失败,【用户名】、【密码】、【验证码】框中已录入的内容被清空,验证码自动刷新
  • 点击【登录】按钮后,若【用户名】、【密码】校验通过,唯独【验证码】校验不通过,则登录失败的系统提示内容为【验证码错误,请重新录入验证码】。同时验证码自动刷新。
  • 【验证码】的有效时间为60秒,超过之后则失效,但不自动刷新。失效之后若录入正确的【用户名】【密码】同时录入页面上已失效的【验证码】,则登录失败,且登录失败的系统提示内容为【验证码错误,请重新录入验证码】,同时验证码自动刷新

实施

验证码接口 | 请求头方式传递
  • 依赖导入
        <!-- 添加图形验证码依赖 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-captcha</artifactId><version>5.8.5</version></dependency>
  • 图片验证码接口编写
    /*** 生成验证码图片* @return*/@ApiOperation("获取图形验证码")@GetMapping("/identifyImage")public Result<String> identifyImage(HttpServletResponse response,@ApiParam(value = "图形验证码id,无值:生成验证码,有值:刷新验证码")@RequestParam(name = "codeId", required = false) String codeId) throws IOException {// 创建验证码,设置宽、高、长度、干扰线数量LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 90, 4, 100);// 获取验证码字符串,赋值codeString code = lineCaptcha.getCode();if (codeId == null) {// IdWorker.getId():IdWorker工具类生成唯一ID,并转换成String类型codeId = String.valueOf(IdWorker.getId());// 将codeId、code.toUpperCase()、过期时间60秒:存储入Redis中// code.toUpperCase():code装换成大写形式存储redisOps.set(codeId,code.toUpperCase(),60);} else {redisOps.set(codeId,code.toUpperCase(),60);}// 将图片验证码codeId设置请求头中response.setHeader("codeId", codeId);// 获取向客户端发送响应数据的输出流try (ServletOutputStream outputStream = response.getOutputStream()) {// 验证码图片数据写入到输出流lineCaptcha.write(outputStream);} catch (Exception e) {throw new AuthException("图形验证码输出错误");}return Result.succ(codeId);}
  • Postman调用测试
http://localhost:9036/api/identifyImage

在这里插入图片描述

在这里插入图片描述

验证码接口 | base64方式传递
    /*** 生成验证码图片* @return*/@ApiOperation("获取图形验证码")@GetMapping("/identifyImage")public Result<IdentifyImageResp> identifyImage(HttpServletResponse response,@ApiParam(value = "图形验证码id,无值:生成验证码,有值:刷新验证码")@RequestParam(name = "codeId", required = false) String codeId) throws IOException {LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 90, 4, 100);String code = lineCaptcha.getCode();if (codeId == null) {codeId = String.valueOf(IdWorker.getId());redisOps.set(codeId,code.toUpperCase(),60);} else {redisOps.set(codeId,code.toUpperCase(),60);}IdentifyImageResp identifyImageResp = new IdentifyImageResp(codeId, lineCaptcha.getImageBase64Data());return Result.succ(identifyImageResp);}

在这里插入图片描述

登录接口
  • 登录接口编写
@PostMapping("login")
@ApiOperation("用户登录")
public Result login(@Validated @RequestBody LoginRequest request) {// request.getCodeId():请求体中获取codeId// redisOps.get(request.getCodeId():codeId为键,获取redis中对应的值String codeId = (String) redisOps.get(request.getCodeId());if (codeId.isEmpty()){throw new AuthException("验证码已过期请刷新重试");}AuthContext login = authService.login(request);// 登录成功后,通过 login.getMerchant() 获取到登录的用户对象,跟新登录信息Merchant merchant = login.getMerchant();merchant.setLastLoginAt(merchant.getLoginAt());merchant.setLoginAt(new Date());merchant.setLastLoginIp(merchant.getLoginIp());merchant.setLoginIp(CommonTools.getIp(httpServletRequest));merchantRepo.updateById(merchant);login.setMerchant(merchant);// JsonMapper.objectToJson(login):将login对象转换成 JSON 格式的字符串log.info("LOGIN - > {}", JsonMapper.objectToJson(login));return Result.succ("登录成功");
}
  • LoginRequest.java:请求体字段
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginRequest {@NotEmpty@ApiModelProperty("登录名")private String username;@NotEmpty@ApiModelProperty("密码,md5加密全小写")private String password;@ApiModelProperty("验证码")private String code;@ApiModelProperty("验证码Id")private String codeId;}
  • AuthService.java
    public AuthContext login(LoginRequest login) {// 登录验证和处理if (StringUtils.isBlank(login.getUsername())) {throw new AuthException("用户名不能为空");}if (StringUtils.isBlank(login.getPassword())) {throw new AuthException("密码不能为空");}// 缓存清空,登出操作logout();Merchant merchant = findMerchantByLoginEmail(login.getUsername());if (merchant == null) {authError("账户不存在,或状态不正确");} else if (merchant.getIsLocked()) {authError("账户已停用");}// 从redis获取login.getUsername()+"lock-time")的键对应的值if (redisOps.get(login.getUsername()+"lock-time") != null){// redisOps.getExpire:获取 Redis 中指定键的过期时间long expire = redisOps.getExpire(login.getUsername() + "lock-time");// 转换为分钟int minutes = (int) (expire / 60);// 转换为秒钟int seconds = (int) (expire % 60);authError("您已连续5次输入错误的密码,暂时不允许登录,"+minutes+"分"+seconds+"秒后可再次尝试登录");}System.out.println(merchant.getLoginPassword());System.out.println(SecretUtils.encrypt(login.getPassword()));Integer errorNum = (Integer) redisOps.get(login.getUsername());if (!merchant.getLoginPassword().equals(SecretUtils.encrypt(login.getPassword()))) {//密码错误次数为null时创建键值对if (errorNum == null){redisOps.set(login.getUsername(),1);}else if  ((errorNum > 0 && errorNum < 4) || (errorNum > 5 && errorNum < 10)){//密码错误次数为0-4、5-10时incrredisOps.incr(login.getUsername(),1);}else if (errorNum+1==5){//密码错误次数为5时锁定10分钟redisOps.set(login.getUsername()+"lock-time","lock",600);authError("您已连续5次输入错误的密码,暂时不允许登录,请10分钟后再次尝试登录");}else {//密码错误次数为10时锁定merchant.setIsLocked(true);merchantRepo.updateById(merchant);authError("您已连续10次输入错误的密码,账号已被锁定、不允许登录,请联系管理员解锁");}authError("密码不正确");}String code= (String) redisOps.get(login.getCodeId());if (code == null || login.getCode()==null || !code.equals(login.getCode().toUpperCase())){authError("请输入正确的验证码");}
//        merchant.setLoginPassword("*");String token = Sha.sha256(UUID.randomUUID().toString());AuthContext authContext = new AuthContext(token, merchant, null);redisOps.set(token, JsonMapper.objectToJson(authContext), authProp.getExpiresSeconds());CookieUtils.setCookie(response, "/", authProp.getTokenHeader(), token, authProp.getExpiresSeconds());//登陆完成删除账号错误次数if (errorNum!=null)redisOps.delete(login.getUsername());return authContext;}public String logout() {String cookie = CookieUtils.getCookie(request, authProp.getTokenHeader());String token = StringUtils.isNotBlank(cookie) ? cookie : request.getHeader(authProp.getTokenHeader());if (StringUtils.isNotBlank(token)) {redisOps.delete(token);}return "登出成功";}private void authError(String errorMsg) {throw new AuthException(errorMsg);}
  • Postman测试

在这里插入图片描述


🌼 结语:创作不易,如果觉得博主的文章赏心悦目,还请——点赞👍收藏⭐️评论📝


在这里插入图片描述

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

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

相关文章

前K个高频单词(Java详解)

一、题目描述 给定一个单词列表 words 和一个整数 k &#xff0c;返回前 k 个出现次数最多的单词。 返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率&#xff0c; 按字典顺序 排序。 示例1&#xff1a; 输入: words ["i", "love&…

浅谈硬件连通性测试几大优势

硬件连通性测试是确保硬件系统正常运行、提高系统可靠性和降低生产成本的关键步骤。在现代工程和制造中&#xff0c;将连通性测试纳入生产流程是一个明智的选择&#xff0c;有助于确保硬件产品的质量和性能达到最优水平。本文将介绍硬件连通性测试的主要优势有哪些! 一、提高系…

游戏测试和软件测试有什么区别

针对手游而言&#xff0c;游戏测试的本质是APP&#xff0c;所以不少手游的测试方式与APP测试异曲同工&#xff0c;然而也有所不同。APP更多的是具有一种工具&#xff0c;一款APP好不好用不重要&#xff0c;关键点在于实用。而游戏则具有一种玩具属性&#xff0c;它并不见得实用…

基于Python+requests编写的自动化测试项目-实现流程化的接口串联

框架产生目的&#xff1a;公司走的是敏捷开发模式&#xff0c;编写这种框架是为了能够满足当前这种发展模式&#xff0c;用于前后端联调之前&#xff08;后端开发完接口&#xff0c;前端还没有将业务处理完毕的时候&#xff09;以及日后回归阶段&#xff0c;方便为自己腾出学(m…

图像异常检测研究现状综述

论文标题&#xff1a;图像异常检测研究现状综述 作者&#xff1a;吕承侃 1, 2 沈 飞 1, 2, 3 张正涛 1, 2, 3 张 峰 1, 2, 3 发表日期&#xff1a;2022年6月 阅读日期 &#xff1a;2023年11月28 研究背景&#xff1a; 图像异常检测是计算机视觉领域的一个热门研究课题, 其目…

leetCode 39.组合总和 + 回溯算法 + 剪枝 + 图解 + 笔记

39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合 can…

2015年五一杯数学建模A题不确定性条件下的最优路径问题解题全过程文档及程序

2015年五一杯数学建模 A题 不确定性条件下的最优路径问题 原题再现 目前&#xff0c;交通拥挤和事故正越来越严重的困扰着城市交通。随着我国交通运输事业的迅速发展&#xff0c;交通“拥塞”已经成为很多城市的“痼疾”。在复杂的交通环境下&#xff0c;如何寻找一条可靠、快…

HarmonyOS 数据持久化 Preferences 如何在页面中对数据进行读写

背景介绍 最近在了解并跟着官方文档尝试做一个鸿蒙app 小demo的过程中对在app中保存数据遇到些问题 特此记录下来 这里的数据持久化以 Preferences为例子展开 废话不多说 这里直接上节目(官方提供的文档示例:) 以Stage模型为例 1.明确preferences的类型 import data_prefer…

印刷企业建设数字工厂管理系统的工作内容有哪些

随着科技的不断进步&#xff0c;数字工厂管理系统在印刷企业中的应用越来越广泛。这种系统可以有效地整合企业内外资源&#xff0c;提高生产效率&#xff0c;降低生产成本&#xff0c;并为印刷企业提供更好的业务运营与管理模式。本文将从以下几个方面探讨印刷企业建设数字工厂…

如何用postman实现接口自动化测试

postman使用 开发中经常用postman来测试接口&#xff0c;一个简单的注册接口用postman测试&#xff1a; 接口正常工作只是最基本的要求&#xff0c;经常要评估接口性能&#xff0c;进行压力测试。 postman进行简单压力测试 下面是压测数据源&#xff0c;支持json和csv两个格…

Kibana部署

服务器 安装软件主机名IP地址系统版本配置KibanaElk10.3.145.14centos7.5.18042核4G软件版本&#xff1a;nginx-1.14.2、kibana-7.13.2-linux-x86_64.tar.gz 1. 安装配置Kibana &#xff08;1&#xff09;安装 [rootelk ~]# tar zxf kibana-7.13.2-linux-x86_64.tar.gz -C…

easyExcel 注解开发 快速以及简单上手 以及包含工具类

easyExcel 简单快速使用 1. mevan 这里版本我这里选的是 poi 4.1.2和 ali的easyexcel 的 3.3.1。 因为阿里easy是根据poi的依赖开发的有关系&#xff0c;两者需要对应要不然就会有很多bug和错误在运行时发生。需要版本对应&#xff0c;然而就是easy的代码也会有bug这个版本是比…

运动鞋品牌识别

一、前期工作 1. 设置GPU from tensorflow import keras from tensorflow.keras import layers,models import os, PIL, pathlib import matplotlib.pyplot as plt import tensorflow as tfgpus tf.config.list_physical_devices("GPU")if gpus:gpu0 …

Leetcode—18.四数之和【中等】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—18.四数之和 实现代码 class Solution { public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ans;sort(nums.begin(), nums.end());int n …

chatgpt prompt提示词

ChatGPT 最近十分火爆&#xff0c;今天我也来让 ChatGPT 帮我阅读一下 Vue3 的源代码。 都知道 Vue3 组件有一个 setup函数。那么它内部做了什么呢&#xff0c;今天跟随 ChatGPT 来一探究竟。 实战 1.setup setup 函数在什么位置呢&#xff0c;我们不知道他的实现函数名称&…

12 网关实战:Spring Cloud Gateway基础理论

为什么需要网关? 传统的单体架构中只有一个服务开放给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,那么作为客户端如何去调用这些微服务呢?如果没有网关的存在,只能在本地记录每个微服务的调用地址。 无网关的微服务架构往往存在以下问题: 客户端多次请求…

人机交互3——多主题多轮对话

1.主动切换 2.被动切换 3.多轮状态记忆

3.2 Windows驱动开发:内核CR3切换读写内存

CR3是一种控制寄存器&#xff0c;它是CPU中的一个专用寄存器&#xff0c;用于存储当前进程的页目录表的物理地址。在x86体系结构中&#xff0c;虚拟地址的翻译过程需要借助页表来完成。页表是由页目录表和页表组成的&#xff0c;页目录表存储了页表的物理地址&#xff0c;而页表…

使用Sui天气预言机获取全球实时天气数据

新的Sui天气预言机为全球1000多个城市的建设者提供天气数据&#xff0c;并作为一个独特的随机数生成器&#xff0c;适用于需要可信赖的随机结果的游戏和投注应用。它由基于Sui的智能合约和一个从OpenWeather API获取天气数据的后端服务组成&#xff0c;任何人都可以将天气数据集…

SpringCloudAlibaba之Nacos——详细讲解

目录 一、SpringCloudAlibaba简介 1. spring cloud alibaba 特点 2.springcloud 组件 二、环境搭建 1.构建项目并引入依赖 三、Nacos 1.什么是Nacos 2.安装Nacos 3.启动安装服务 4.访问nacos的web服务管理界面 四、开发服务注册到nacos 1.创建项目并引入依赖 2.配置注册地…