实现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-编程思想构造函数原型(更新中)
目录 编程思想构造函数原型 编程思想 构造函数 原型...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...