实现Java后端的图形验证码和行为验证码
登录添加图形验证码:
在 Java 中,我们可以使用一些图形处理库(如 java.awt 和 javax.imageio)生成图形验证码,并将验证码文本存储在会话(session)中以供验证。下面是一个完整的实现步骤,包括 验证码图片生成、验证码接口、以及 验证逻辑。
1. Maven 依赖(可选)
如需引入依赖管理,可以使用 Maven 项目结构。示例中我们主要依赖 Java 自带的 javax 库,所以无需添加额外依赖。
如果你需要更多验证码功能,kaptcha 是一个常用的 Java 验证码生成库,可以通过 Maven 添加:
xml
<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version>
</dependency>
2. 验证码生成与接口实现
下面是一个使用 javax.imageio 和 java.awt 库生成验证码图片的例子,并通过 Servlet 提供 HTTP 接口。
生成验证码的 Java Servlet
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;@WebServlet("/captcha")
public class CaptchaServlet extends HttpServlet {private static final int WIDTH = 160;private static final int HEIGHT = 40;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 创建验证码图片BufferedImage captchaImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);Graphics2D g = (Graphics2D) captchaImage.getGraphics();Random random = new Random();// 生成随机验证码文本String captchaText = generateCaptchaText(6);HttpSession session = request.getSession();session.setAttribute("captcha", captchaText); // 将验证码存储在 session 中// 设置图片背景颜色g.setColor(Color.LIGHT_GRAY);g.fillRect(0, 0, WIDTH, HEIGHT);// 设置字体与颜色g.setFont(new Font("Arial", Font.BOLD, 30));g.setColor(Color.BLACK);g.drawString(captchaText, 20, 30);// 画干扰线for (int i = 0; i < 5; i++) {g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));int x1 = random.nextInt(WIDTH);int y1 = random.nextInt(HEIGHT);int x2 = random.nextInt(WIDTH);int y2 = random.nextInt(HEIGHT);g.drawLine(x1, y1, x2, y2);}g.dispose(); // 释放资源// 设置响应类型为图片格式response.setContentType("image/png");ImageIO.write(captchaImage, "png", response.getOutputStream()); // 输出图片}// 生成随机验证码文本private String generateCaptchaText(int length) {String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";StringBuilder sb = new StringBuilder();Random random = new Random();for (int i = 0; i < length; i++) {sb.append(chars.charAt(random.nextInt(chars.length())));}return sb.toString();}
}
解释:
- CaptchaServlet:
-
- 使用
BufferedImage创建验证码图片。 - 使用
Graphics2D在图片上绘制文字和干扰线。 - 验证码文本存储在 session 中,以便后续验证。
- 使用
- 会话存储:
session.setAttribute("captcha", captchaText);将验证码保存到用户会话中。 - 图片响应:
ImageIO.write(captchaImage, "png", response.getOutputStream());将图片直接写入 HTTP 响应流中。
3. 验证码验证逻辑
在用户提交表单时,后端需要验证用户输入的验证码与 session 中存储的验证码是否一致。
登录接口示例
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String userAccount = request.getParameter("userAccount");String userPassword = request.getParameter("userPassword");String captchaInput = request.getParameter("captcha");HttpSession session = request.getSession();String captcha = (String) session.getAttribute("captcha");// 验证验证码是否正确if (captcha == null || !captcha.equalsIgnoreCase(captchaInput)) {response.getWriter().write("验证码错误");return;}// TODO: 验证账号和密码的逻辑if ("admin".equals(userAccount) && "password".equals(userPassword)) {response.getWriter().write("登录成功");} else {response.getWriter().write("账号或密码错误");}}
}
解释:
- 验证码验证:获取用户输入的验证码,并与会话中的验证码进行比对。
- 忽略大小写:使用
equalsIgnoreCase忽略大小写进行比较。 - 验证逻辑:如果验证码正确且账号密码验证成功,则返回“登录成功”。
4. 前端代码:提交表单与验证码显示
前端代码需要请求验证码图片,并将验证码输入框的内容一并提交给后端。
HTML 示例:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页面</title>
</head>
<body><form action="/login" method="POST"><input type="text" name="userAccount" placeholder="请输入账号" required /><input type="password" name="userPassword" placeholder="请输入密码" required /><img src="/captcha" alt="验证码" onclick="this.src='/captcha?'+Math.random()" /><input type="text" name="captcha" placeholder="请输入验证码" required /><button type="submit">登录</button></form>
</body>
</html>
解释:
- 验证码刷新:点击验证码图片时,通过
this.src='/captcha?' + Math.random()强制刷新验证码。 - 表单提交:在用户填写验证码后,将表单提交到
/login接口。
使用行为验证码:
在开发中添加行为验证码是一种有效的防止自动化攻击和机器人行为的方式。以下是一些免费且公开可用的行为验证码解决方案:
1. hCaptcha
- 概述:hCaptcha 是一个免费的验证码服务,提供用户交互验证,防止恶意自动化。
- 特点:
-
- 简单易用,与 Google reCAPTCHA 类似。
- 提供奖励系统,网站可以通过用户完成验证获取收益。
- 使用:
-
- 访问 hCaptcha官网 注册并获取 API 密钥。
- 根据文档进行集成。
2. Google reCAPTCHA
- 概述:虽然 reCAPTCHA 主要是为识别机器人设计的,但其 "Checkbox" 和 "Invisible" 选项可以用作行为验证码。
- 特点:
-
- 广泛使用,用户熟悉。
- 提供多种验证方式,包括隐形验证。
- 使用:
-
- 注册 Google reCAPTCHA 获取密钥。
- 按照文档进行集成。
3. Friendly Captcha
- 概述:Friendly Captcha 提供了一种不依赖于用户交互的验证码系统,适合于保护用户隐私。
- 特点:
-
- 不需要用户填写验证码,用户体验更佳。
- 通过计算资源验证用户行为。
- 使用:
-
- 访问 FriendlyCaptcha官网 注册并获取 API 密钥。
- 根据文档进行集成。
实战hCaptcha:
在vue项目中创建组件:
<template><div><!-- hCaptcha 容器 --><divref="hcaptchaContainer"class="h-captcha":data-sitekey="siteKey"></div></div>
</template><script setup lang="ts">
import { onMounted, ref, defineEmits } from "vue";
const token = ref<string | null>(null); // 存储验证 token// 定义事件,向父组件发送 token
const emit = defineEmits(["verify"]);
interface Props {siteKey: string;
}// const props = defineProps<Props>(); // 接收 siteKey 作为参数
const hcaptchaContainer = ref<HTMLDivElement | null>(null); // hCaptcha 容器的引用// 生命周期钩子,确保 hCaptcha 在组件挂载后初始化
onMounted(() => {if (window.hcaptcha) {console.log("hCaptcha 已加载");window.hcaptcha.render(hcaptchaContainer.value!, {sitekey: "10000000-ffff-ffff-ffff-000000000001",callback: onVerify,// sitekey: "fbc8723c-c356-49d6-a524-bf327f9ac81a",});} else {console.error("hCaptcha 脚本未加载");}
});const onVerify = (response: string) => {console.log("hCaptcha 验证成功,token:", response);emit("verify", response); // 通过事件发送 token 给父组件
};
</script><style>
.h-captcha {margin: 10px 0;
}
</style>
然后在登录页面中使用,并且进行拦截:
<template><div id="userLoginView"><h1 style="margin-bottom: 56px; color: #fff">用户登录</h1><a-formstyle="display: flex;flex-direction: column;justify-content: space-between;max-width: 520px;min-height: 350px;margin: 0 auto;background: rgba(255, 255, 255, 0.9);padding: 20px;border-radius: 10px;box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);"label-align="left"auto-label-width:model="form"@submit="handleSubmit"><a-form-item field="userAccount" label="账号" style="margin-top: 40px"><a-input v-model="form.userAccount" placeholder="请输入账号" /></a-form-item><a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码"><a-input-passwordv-model="form.userPassword"placeholder="请输入密码"/></a-form-item><HCaptcha @verify="onCaptchaVerify" /><a-form-item style="margin-bottom: 40px"><a-buttontype="primary"html-type="submit"style="width: 120px; height: 40px; margin-right: 20%">登录</a-button><a-buttontype="primary"@click="turnToRegister()"style="width: 120px; height: 40px; margin-left: 20%">新用户注册</a-button></a-form-item></a-form></div>
</template><script setup lang="ts">
import HCaptcha from "../../components/HCaptcha.vue";
import { reactive, ref } from "vue";
import { UserControllerService, UserLoginRequest } from "../../../generated";
import message from "@arco-design/web-vue/es/message";
import { useRouter } from "vue-router";
import { useStore } from "vuex";/*** 表单信息*/
const form = reactive({userAccount: "",userPassword: "",
} as UserLoginRequest);const router = useRouter();
const store = useStore();const captchaToken = ref<string | null>(null); // 存储 hCaptcha 的 token
const onCaptchaVerify = (token: string) => {captchaToken.value = token; // 接收 hCaptcha 的 token
};/*** 提交表单* @param data*/
const handleSubmit = async () => {if (!captchaToken.value) {message.error("请先通过验证码验证");return; // 阻止提交}const res = await UserControllerService.userLoginUsingPost(form);// 登录成功,跳转到主页if (res.code === 0) {await store.dispatch("user/getLoginUser");router.push({path: "/",replace: true,});} else {message.error("登陆失败," + res.message);}
};/*** 跳转到注册页面*/
const turnToRegister = () => {router.push({path: "/user/register",replace: true,});
};
</script>
<style>
#userLoginView {margin-top: 20vh;/*margin-left: 40vh;*/
}
</style>相关文章:
实现Java后端的图形验证码和行为验证码
登录添加图形验证码: 在 Java 中,我们可以使用一些图形处理库(如 java.awt 和 javax.imageio)生成图形验证码,并将验证码文本存储在会话(session)中以供验证。下面是一个完整的实现步骤&#x…...
事务的原理、MVCC的原理
事务特性 数据库事务具有以下四个基本特性,通常被称为 ACID 特性: 原子性(Atomicity):事务被视为不可分割的最小工作单元,要么全部执行成功,要么全部失败回滚。这意味着如果事务执行过程中发生…...
Golang反射原理
Golang反射原理 Go语言中的反射机制是通过标准库中的reflect包实现的。反射允许程序在运行时检查变量的类型和值,甚至可以修改变量的值。以下是反射的基本原理和使用方法: 基本原理 类型和种类: 反射中的类型信息通过reflect.Type表示&…...
MATLAB计算朗格朗日函数
1. 朗格朗日函数介绍 朗格朗日函数(Lagrange function)通常用于优化问题,尤其是带有约束的优化问题。其一般形式为: 其中: f(x) 是目标函数。 是约束条件。 是拉格朗日乘子。 为了编写一个MATLAB代码来计算和绘制…...
嵌入式linux跨平台基于mongoose的TCP C++类的源码
嵌入式linux开发中,需要使用http服务器时,mongoose是个很好的选择,linux,win双平台都支持,代码全开放,简单明了,我非常喜欢这种尽在撑控中的感觉(关于mongoose实现一个小型的http服务…...
入驻商家必看:如何在TikTok实现多店铺高效上货及运营?
TikTok作为跨境电商平台之一,越来越多人进入其电商赛道——TikTok Shop,运营者想要长远发展,了解平台的政策动向并进行调整店铺至关重要。本文整理了TikTok Shop降低入驻门槛的资讯,并为广大TikTok电商运营者提供实用、有效的开店…...
spring-boot-starter-data-redis
一、几个依赖的关系 在spring与redis整合时有下面几种: spring-boot-starter-data-redis spring-boot-starter-redis spring-data-redis 其中,spring-boot-starter-data-redis和spring-boot-starter-redis中都包含有spring-data-redis, 现在…...
科研绘图神器:机制图、模式图有哪些好用的工具推荐?
我是娜姐 迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。 最近不少学员在问科研绘图相关的问题。前面娜姐介绍过AI辅助绘图的方法和思路: 顶刊的图文摘要Graphical Abstract,如何巧用AI绘制? 目前…...
DIFFUSIONSAT: A GENERATIVE FOUNDATION MODEL FOR SATELLITE IMAGERY(2024-ICLR)
论文:DIFFUSIONSAT: A GENERATIVE FOUNDATION MODEL FOR SATELLITE IMAGERY(2024-ICLR) 习惯用飞书做笔记了,大家见谅 Diffusionsat:卫星图像生成基础模型...
文件中台与安全:集成方案的探索与实践
在企业数字化转型加速的今天,文件中台已成为支撑数据共享与高效协作的关键基础设施。然而,随着企业文件需求的增多和内容复杂性的提升,文件的安全问题也日益突显。如何在构建强大文件中台的同时,保障文件数据的安全性,…...
Redis 哨兵 总结
前言 相关系列 《Redis & 目录》《Redis & 哨兵 & 源码》《Redis & 哨兵 & 总结》《Redis & 哨兵 & 问题》 参考文献 《Redis的主从复制和哨兵机制详解》《Redis中的哨兵(Sentinel)》《【Redis实现系列】Sentinel自动故…...
Systemd 和 Systemctl命令详解
Systemd 和 Systemctl命令详解 在现代 Linux 系统中,systemd 是一种高度灵活且广泛应用的系统管理工具。它主要负责系统引导和进程管理,支持并行化启动服务,并提供高级的服务管理和依赖控制。systemctl 是 systemd 的核心命令行工具…...
基于Multisim的音频放大电路设计与仿真
基本设计要求:设计并仿真实现一个音频功率放大器。功率放大器的电源电压为+5V(电路其他部分的电源电压不限),负载为8Ω电阻。具体要求如下:1)3dB通频带为300~3400Hz,输出…...
这是一款专门为SQL新手小白量身定制的工具!
首先!它永久免费!SQLynx对于个人用户和教育从业者永久免费!且真正实现了跨平台操作!支持Windows Linux和Mac,无需任 何安装和配置,更支持国产操作系统,如银河 麒麟统信等。 功能直观!…...
springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38819)
刚解决Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38816)没几天,又来一个新的,真是哭笑不得啊。 springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38816)https://blog.csdn.ne…...
Android Input的流程和原理
Android Input事件机制 Android系统是由事件驱动的,而Input是最常见的事件之一,用户的点击、滑动、长按等操作,都属于Input事件驱动,其中的核心就是InputReader和InputDispatcher。InputReader和InputDispatcher是跑在system_serv…...
InfiMM-WebMath-40B——利用由 24 亿数学文档组成的数据集提高 LLM 的数学性能
1. 前言 论文地址:https://arxiv.org/abs/2409.12568 本文提出了一个新的大规模多模态预训练数据集 InfiMM-WebMath-40B,以提高数学推理能力。该数据集包含 24 亿个科学和数学相关的网络文档、85 亿个图片 URL 和约 400 亿个文本标记。该数据集支持多模…...
Swarm-LIO: Decentralized Swarm LiDAR-inertial Odometry论文翻译
文章目录 前言一、介绍二、相关工作三、方法A. 问题表述B. 框架概述C. 群体系统的初始化D. 去中心化激光雷达-惯性状态估计 四. 实验A. 室内飞行B. 退化环境飞行C. 去中心化部署 五. 结论和未来工作 前言 原文:原文 准确的自我状态和相对状态估计是完成群体任务的关…...
第十八章 Vue组件样式范围配置之scoped
目录 一、引言 二、案例演示 2.1. 工程结构图 2.2. 核心代码 2.2.1. main.js 2.2.2. App.vue 2.2.3. BaseOne.vue 2.2.4. BaseTwo.vue 2.3. 运行效果 2.4. 调整代码 2.4.1. BaseTwo.vue 2.4.2. 运行效果 三、scoped原理 一、引言 前面的几个章节在介绍组件的时…...
【JavaScript】JavaScript 进阶-3-编程思想构造函数原型(更新中)
目录 编程思想构造函数原型 编程思想 构造函数 原型...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
