实现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-编程思想构造函数原型(更新中)
目录 编程思想构造函数原型 编程思想 构造函数 原型...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
