我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java 图片验证码需求分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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>
  • 图片验证码接口编写
        @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);        // 获取验证码字符串,赋值code        String 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方式传递
        @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@AllArgsConstructorpublic 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时incr                redisOps.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测试

在这里插入图片描述


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


在这里插入图片描述

来源地址:https://blog.csdn.net/weixin_62765017/article/details/131963978

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java 图片验证码需求分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java实现动态图片验证码

目的:防止恶意表单注册生成验证码图片1、定义宽高int width = 100;int height = 50;2、使用BufferedImage在内存中生成图片BufferedImage image = new BufferedImage(width, he
java实现动态图片验证码
2019-04-24

JAVA中如何验证图片验证码是否正确

知识补充:toString() 方法用于返回以一个字符串表示的 Number 对象值。equalsIgnoreCase() 方法用于将字符串与指定的对象比较,不考虑大小写。验证方法:首先需要先获取用户输入的验证码对象,然后先判断验证码是否为空,若不为空则通过“
JAVA中如何验证图片验证码是否正确
2016-02-24

python生成验证码图片代码分享

本文实例为大家分享了python生成验证码图片代码,分享给大家供大家参考,具体内容如下 基本上大家使用每一种网络服务都会遇到验证码,一般是网站为了防止恶意注册、发帖而设置的验证手段。其生成原理是将一串随机产生的数字或符号,生成一幅图片,图片
2022-06-04

基于Java生成图片验证码的方法解析

这篇文章主要来为大家详细介绍一下基于Java生成图片验证码的具体方法,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
2023-02-06

在Python web中实现验证码图片代码分享

系统版本: CentOS 7.4 Python版本: Python 3.6.1在现在的WEB中,为了防止爬虫类程序提交表单,图片验证码是最常见也是最简单的应对方法之一。 1.验证码图片的生成 在python中,图片验证码一般用PIL或者Pi
2022-06-04

java怎么实现随机验证码图片生成

这篇文章主要介绍“java怎么实现随机验证码图片生成”,在日常操作中,相信很多人在java怎么实现随机验证码图片生成问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么实现随机验证码图片生成”的疑惑有所
2023-06-25

使用java如何生成一个验证码图片

本文章向大家介绍使用java如何生成一个验证码图片的基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表,实现了面向对象理论,允许程
2023-06-06

三分钟带你掌握Java开发图片验证码功能方法

这篇文章主要来为大家详细介绍Java实现开发图片验证码的具体方法,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下
2023-02-13

android实现图片验证码方法解析(自绘控件)

自绘控件的内容都是自己绘制出来的 大致流程如下: 1.定义一个类继承view 1.使用TypedArray初始化属性集合 在view的构造方法中 有一个AttributeSet的参数 很明显是用来保存控件属性信息的 我们也的确可
2022-06-06

node+vue前后端分离实现登录时使用图片验证码功能

这篇文章主要介绍了node+vue前后端分离实现登录时使用图片验证码,记录前端使用验证码登录的过程,后端用的是node.js,关键模块是svg-captcha,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录