GoogleCodeUtil.java

Google动态验证码实现  GoogleCodeUtil.java

package zwf;import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;/**
https://mvnrepository.com/artifact/commons-codec/commons-codec/1.18.0<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.18.0</version>
</dependency>*/
import org.apache.commons.codec.binary.Base32;/**
https://mvnrepository.com/artifact/com.warrenstrange/googleauth/1.5.0<!-- https://mvnrepository.com/artifact/com.warrenstrange/googleauth -->
<dependency><groupId>com.warrenstrange</groupId><artifactId>googleauth</artifactId><version>1.5.0</version>
</dependency>*/
import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;/**
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/client/utils/URIBuilderat com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator.getOtpAuthTotpURL(GoogleAuthenticatorQRGenerator.java:168)at com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator.getOtpAuthURL(GoogleAuthenticatorQRGenerator.java:143)at zwf.GoogleAuthenticatorUtil.generateQRUrl(GoogleAuthenticatorUtil.java:92)at zwf.GoogleAuthenticatorUtil.main(GoogleAuthenticatorUtil.java:163)
Caused by: java.lang.ClassNotFoundException: org.apache.http.client.utils.URIBuilderat java.net.URLClassLoader.findClass(Unknown Source)at java.lang.ClassLoader.loadClass(Unknown Source)at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)at java.lang.ClassLoader.loadClass(Unknown Source)... 4 morehttps://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient/4.5.13<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>*//**
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/message/ParserCursorat org.apache.http.client.utils.URLEncodedUtils.splitSegments(URLEncodedUtils.java:320)at org.apache.http.client.utils.URLEncodedUtils.splitPathSegments(URLEncodedUtils.java:348)at org.apache.http.client.utils.URIBuilder.setPath(URIBuilder.java:293)at com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator.getOtpAuthTotpURL(GoogleAuthenticatorQRGenerator.java:171)at com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator.getOtpAuthURL(GoogleAuthenticatorQRGenerator.java:143)at zwf.GoogleAuthenticatorUtil.generateQRUrl(GoogleAuthenticatorUtil.java:108)at zwf.GoogleAuthenticatorUtil.main(GoogleAuthenticatorUtil.java:179)
Caused by: java.lang.ClassNotFoundException: org.apache.http.message.ParserCursorat java.net.URLClassLoader.findClass(Unknown Source)at java.lang.ClassLoader.loadClass(Unknown Source)at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)at java.lang.ClassLoader.loadClass(Unknown Source)... 7 morehttps://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore/4.4.15
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.15</version>
</dependency>*//*** Google动态验证码实现* * https://www.lzltool.com/GoogleDynamicPassword* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com*/
public class GoogleCodeUtil
{/*** 动态密码的有效期,默认30秒, 30 * 1000 = 10秒* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @return*/private static final long TIME_STEP_SIZE_IN_MILLIS = 30 * 1000;/*** 允许的时间窗口时间步长,默认1* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @return*/private static final int WINDOW_SIZE = 1;/*** 生成一个随机的 Base32 编码的密钥* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @return 生成的 Base32 编码的密钥*/public static String generateSecretKey(){// 创建一个安全的随机数生成器SecureRandom random = new SecureRandom();// 生成一个长度为 20 的字节数组byte[] bytes = new byte[20];// 用随机数填充字节数组random.nextBytes(bytes);// 创建一个 Base32 编码器Base32 base32 = new Base32();// 将字节数组编码为 Base32 字符串并返回return base32.encodeToString(bytes);}/*** 根据密钥生成一个可供 Google Authenticator 扫描的二维码链接* * https://api.qrserver.com/v1/create-qr-code/?data=otpauth://totp/YourAppName:user@example.com?secret=YOUR_SECRET_KEY&issuer=YourAppName* * url转义* :     %3A* //    %2F%2F* @     %40* ?     %3F* =     %3D* &     %26* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey            用于生成二维码链接的密钥* @param appName              应用程序的名称* @param email                用户的邮箱地址* @param timeStepSizeInMillis 动态密码的时间步长(毫秒)* @param windowSize           允许的时间窗口时间步长* @return 生成的二维码链接*/public static String generateQRUrl(String secretKey, String appName, String email, long timeStepSizeInMillis,int windowSize){// 构建 GoogleAuthenticator 的配置对象,设置时间步长GoogleAuthenticatorConfig config = new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().setTimeStepSizeInMillis(timeStepSizeInMillis).setWindowSize(windowSize) // 设置允许的时间窗口为 1 个时间步长.build();// 根据配置创建 GoogleAuthenticator 实例@SuppressWarnings("unused")GoogleAuthenticator gAuth = new GoogleAuthenticator(config);// 根据密钥创建一个 GoogleAuthenticatorKey 对象GoogleAuthenticatorKey key = new GoogleAuthenticatorKey.Builder(secretKey).build();// 生成一个可供 Google Authenticator 扫描的二维码链接,其中包含应用名称和用户邮箱信息String url = GoogleAuthenticatorQRGenerator.getOtpAuthURL(appName, email, key);// 对 URL 进行编码try{return URLEncoder.encode(url, StandardCharsets.UTF_8.name());}catch (UnsupportedEncodingException e){// 这里可以考虑记录日志,目前简单打印异常信息System.err.println("URL 编码时出现异常: " + e.getMessage());// 返回 null 表示生成失败,调用者可以根据返回值进行相应处理return null;}}/*** 根据密钥生成一个可供 Google Authenticator 扫描的二维码链接* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey            用于生成二维码链接的密钥* @param appName              应用程序的名称* @param email                用户的邮箱地址* @param timeStepSizeInMillis 动态密码的时间步长(毫秒)* @return 生成的二维码链接*/public static String generateQRUrl(String secretKey, String appName, String email, long timeStepSizeInMillis){// 生成一个可供 Google Authenticator 扫描的二维码链接,其中包含应用名称和用户邮箱信息return generateQRUrl(secretKey, appName, email, timeStepSizeInMillis, WINDOW_SIZE);}/*** 根据密钥生成一个可供 Google Authenticator 扫描的二维码链接* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey 用于生成二维码链接的密钥* @param appName   应用程序的名称* @param email     用户的邮箱地址* @return 生成的二维码链接*/public static String generateQRUrl(String secretKey, String appName, String email){// 生成一个可供 Google Authenticator 扫描的二维码链接,其中包含应用名称和用户邮箱信息return generateQRUrl(secretKey, appName, email, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);}/*** 根据密钥生成当前时间对应的一次性动态密码* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey            用于生成动态密码的密钥* @param timeStepSizeInMillis 动态密码的时间步长(毫秒)* @param windowSize           允许的时间窗口时间步长* @return 当前时间对应的一次性动态密码*/public static int generateCode(String secretKey, long timeStepSizeInMillis, int windowSize){// 构建 GoogleAuthenticator 的配置对象,设置时间步长GoogleAuthenticatorConfig config = new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().setTimeStepSizeInMillis(timeStepSizeInMillis).setWindowSize(windowSize) // 设置允许的时间窗口为 1 个时间步长.build();// 根据配置创建 GoogleAuthenticator 实例GoogleAuthenticator gAuth = new GoogleAuthenticator(config);// 利用密钥生成当前时间对应的一次性动态密码return gAuth.getTotpPassword(secretKey);}/*** 根据密钥生成当前时间对应的一次性动态密码* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey            用于生成动态密码的密钥* @param timeStepSizeInMillis 动态密码的时间步长(毫秒)* @return 当前时间对应的一次性动态密码*/public static int generateCode(String secretKey, long timeStepSizeInMillis){// 利用密钥生成当前时间对应的一次性动态密码return generateCode(secretKey, timeStepSizeInMillis, WINDOW_SIZE);}/*** 根据密钥生成当前时间对应的一次性动态密码* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey 用于生成动态密码的密钥* @return 当前时间对应的一次性动态密码*/public static int generateCode(String secretKey){// 利用密钥生成当前时间对应的一次性动态密码return generateCode(secretKey, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);}/*** 验证输入的动态密码是否与根据密钥生成的密码匹配* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey            用于验证的密钥* @param code                 待验证的动态密码* @param timeStepSizeInMillis 动态密码的时间步长(毫秒)* @param windowSize           允许的时间窗口时间步长* @return 若验证通过返回 true,否则返回 false*/public static boolean checkCode(String secretKey, int code, long timeStepSizeInMillis, int windowSize){// 构建 GoogleAuthenticator 的配置对象,设置时间步长GoogleAuthenticatorConfig config = new GoogleAuthenticatorConfig.GoogleAuthenticatorConfigBuilder().setTimeStepSizeInMillis(timeStepSizeInMillis).setWindowSize(windowSize) // 设置允许的时间窗口为 1 个时间步长.build();// 根据配置创建 GoogleAuthenticator 实例GoogleAuthenticator gAuth = new GoogleAuthenticator(config);// 验证输入的动态密码是否与根据密钥生成的密码匹配return gAuth.authorize(secretKey, code);}/*** 验证输入的动态密码是否与根据密钥生成的密码匹配* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey            用于验证的密钥* @param code                 待验证的动态密码* @param timeStepSizeInMillis 动态密码的时间步长(毫秒)* @return 若验证通过返回 true,否则返回 false*/public static boolean verifyCode(String secretKey, int code, long timeStepSizeInMillis){// 验证输入的动态密码是否与根据密钥生成的密码匹配return checkCode(secretKey, code, timeStepSizeInMillis, WINDOW_SIZE);}/*** 验证输入的动态密码是否与根据密钥生成的密码匹配* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param secretKey 用于验证的密钥* @param code      待验证的动态密码* @return 若验证通过返回 true,否则返回 false*/public static boolean verifyCode(String secretKey, int code){// 验证输入的动态密码是否与根据密钥生成的密码匹配return checkCode(secretKey, code, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);}/*** 程序入口,用于测试动态密码生成和验证功能* * @author ZengWenFeng* @date 2025.04.16* @mobile 13805029595* @email 117791303@qq.com* @param args 命令行参数*/public static void main(String[] args){//// 生成一个用于生成动态密码的密钥String secretKey = generateSecretKey();System.out.println("Key  : " + secretKey);String appName = "ZengWenFeng";String userEmail = "117791303@ZengWenFeng.com";// 根据生成的密钥生成一个可供 Google Authenticator 扫描的二维码链接String qrCodeUrl = generateQRUrl(secretKey, appName, userEmail, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);System.out.println("Url  : " + qrCodeUrl);// 利用生成的密钥生成当前时间对应的一次性动态密码int code = generateCode(secretKey, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);System.out.println("Code  : " + code);// 验证生成的动态密码是否有效boolean isValid = checkCode(secretKey, code, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);System.out.println("Valid : " + isValid);/*Secret Key: SRT5EAIQICUOWEI7QVPQ2DQ4JMQUTV67 QR Code URL:https://api.qrserver.com/v1/create-qr-code/?data=otpauth%3A%2F%2Ftotp%2FZengWenFeng%3A117791303%40ZengWenFeng.com%3Fsecret%3DSRT5EAIQICUOWEI7QVPQ2DQ4JMQUTV67%26issuer%3DZengWenFeng%26algorithm%3DSHA1%26digits%3D6%26period%3D30&size=200x200&ecc=M&margin=0 Current Code: 883702   Is Valid Code: true*/try{// 等待超过有效期,这里设置为 TIME_STEP_SIZE_IN_MILLIS + 1毫秒System.out.println("---------------------------------");System.out.println("Waiting for the code to expire...");Thread.sleep(TIME_STEP_SIZE_IN_MILLIS + 1);}catch (InterruptedException e){e.printStackTrace();}// 再次验证过期的动态密码boolean isExpiredValid = checkCode(secretKey, code, TIME_STEP_SIZE_IN_MILLIS, WINDOW_SIZE);System.out.println("Valid (after expiration): " + isExpiredValid);}
}

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

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

相关文章

【Leetcode 每日一题】2176. 统计数组中相等且可以被整除的数对

问题背景 给你一个下标从 0 0 0 开始长度为 n n n 的整数数组 n u m s nums nums 和一个整数 k k k&#xff0c;请你返回满足 0 ≤ i < j < n 0 \le i < j < n 0≤i<j<n&#xff0c; n u m s [ i ] n u m s [ j ] nums[i] nums[j] nums[i]nums[j] 且…

如何校验一个字符串是否是可以正确序列化的JSON字符串呢?

方法1&#xff1a;先给一个比较暴力的方法 try {JSONObject o new JSONObject(yourString); } catch (JSONException e) {LOGGER.error("No valid json"); } 方法2&#xff1a; Object json new cn.hutool.json.JSONTokener("[{\"name\":\"t…

【路由交换方向IE认证】BGP选路原则之AS-Path属性

文章目录 一、路由器BGP路由的处理过程控制平面和转发平面选路工具 二、BGP的选路顺序选路的前提选路顺序 三、AS-Path属性选路原则AS-Path属性特性AS-Path管进还是管出呢&#xff1f;使用AS-Path对进本AS的路由进行选路验证AS-Path不接收带本AS号的路由 四、BGP邻居建立配置 一…

2025年热门项目管理软件对比:20款工具详解

本文主要盘点的工具有&#xff1a;1. PingCode; 2. Worktile; 3. Jira; 4. Trello; 5. TAPD; 6. Monday.com; 7. 进度猫; 8. 猪齿鱼; 9. 简道云; 10. Tita项目管理等等20款项目管理软件&#xff08;含免费&#xff09;。 在如今竞争激烈的商业环境中&#xff0c;项目管理软件已…

yaffs_write_new_chunk()函数解析

yaffs_write_new_chunk() 是 YAFFS&#xff08;Yet Another Flash File System&#xff09;文件系统中用于将数据写入新物理块&#xff08;chunk&#xff09;的关键函数。以下是其详细解析&#xff1a; 函数原型 int yaffs_write_new_chunk(struct yaffs_dev *dev, const u8 *…

网络安全-Burp Suite基础篇

声明 本文主要用做技术分享&#xff0c;所有内容仅供参考。任何使用或者依赖于本文信息所造成的法律后果均与本人无关。请读者自行判断风险&#xff0c;并遵循相关法律法规。 1 Burp Suite功能介绍 1.1 Burp Suite 简介 Burp Suite 是一款极为强大且广受欢迎的集成化 …

网络编程 - 2

目录 UDP 数据报套接字编程 API 介绍 DatagramSocket DatagramPacket 补充&#xff1a; 代码示例 - 回显服务器 服务器端&#xff1a; 客户端&#xff1a; 补充&#xff1a; 代码演示 梳理代码&#xff1a; 下面是一个大概的流程图~ 文字解释&#xff1a; 图文并…

【C++深入系列】:模版详解(上)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 你不需要很厉害才能开始&#xff0c;但你需要开始才能很厉害。 ★★★ 本文前置知识&#xff1a; 类和对象&#xff08;上&#xff09; …

java 设计模式之策略模式

简介 策略模式&#xff1a;策略模式可以定制目标对象的行为&#xff0c;它通过传入不同的策略实现&#xff0c;来配置目标对象的行为。使用策略模式&#xff0c;就是为了定制目标对象在某个关键点的行为。 策略模式中的角色&#xff1a; 上下文类&#xff1a;持有一个策略类…

Perf学习

重要的能解决的问题是这些&#xff1a; perf_events is an event-oriented observability tool, which can help you solve advanced performance and troubleshooting functions. Questions that can be answered include: Why is the kernel on-CPU so much? What code-pa…

「仓颉编程语言」Demo

仓颉编程语言」Demo python 1)# 仓颉语言写字楼管理系统示例&#xff08;虚构语法&#xff09;# 语法规则&#xff1a;中文关键词 类Python逻辑定义 写字楼管理系统属性:租户库 列表.新建()报修队列 列表.新建()费用单价 5 # 元/平方米方法 添加租户(名称, 楼层, 面积):…

锁(Mutex)、信号量(Semaphore)与条件量(Condition Variable)

一、同步机制的核心意义 在多线程/多进程编程中&#xff0c;当多个执行流共享资源&#xff08;如变量、内存、文件&#xff09;时&#xff0c;可能因操作顺序不确定导致数据竞争&#xff08;Data Race&#xff09;。同步机制的作用是&#xff1a; 保证原子性&#xff1a;确保…

前端基础之《Vue(6)—组件基础(2)》

接上一篇。 七、v-model深入学习 <html> <head><title>组件基础-4</title><style>.score {display: inline-block;}.score>span {display: inline-block;width: 25px;height: 25px;background: url(./assets/star.png) center center / 25p…

SQL:聚合函数(Aggregate Functions)

目录 第一性原理出发思考 ——我们为什么需要聚合函数&#xff1f; 什么是聚合函数&#xff1f; 常见聚合函数 实例讲解 &#x1f538; 1. COUNT() —— 计数 &#x1f538; 2. MAX() / MIN() —— 最大 / 最小值 &#x1f538; 3. SUM() —— 求和 &#x1f538; 4. …

海关总署广东:广东外贸一季度进出口2.14万亿元 同期增长4.2%

大湾区经济网湾区财经报道&#xff0c;据海关总署广东分署统计&#xff0c;今年一季度&#xff0c;广东外贸进出口2.14万亿元&#xff0c;较去年同期&#xff08;下同&#xff09;增长4.2%&#xff0c;增速高于全国2.9个百分点。其中&#xff0c;出口1.34万亿元&#xff0c;增长…

MySQL中高级语法

Mysql高级语法 持续更新中… 1、EXISTS语法 一、基本语法结构 SELECT [列名] FROM [主表] WHERE [条件]AND EXISTS (SELECT 1 -- 子查询内容无关&#xff0c;仅需占位符&#xff08;如1、*、X等&#xff09;FROM [子查询表]WHERE [关联条件] -- 必须与外层查询关联&#xf…

SpringBoot 调用deepseek

个人学习心得&#xff0c;仅供参考 软件环境&#xff1a; JDK 17 你用JDK 11 无法支持SpringBoot 3SpringBoot 3 版本以上才支持spring aimavan 3.6.11.获取Deepseek官网的API-key 官网&#xff1a;https://platform.deepseek.com/api_keys 2.创建项目 这样创建 添加依赖…

性能测试面试题的详细解答

以下是性能测试面试题的详细解答&#xff1a; 1. 性能测试的流程是怎样的&#xff1f; 性能测试流程通常包括以下几个步骤&#xff1a; - **需求分析**&#xff1a;明确测试目标、性能指标&#xff08;如响应时间、吞吐量等&#xff09;。 - **环境搭建**&#xff1a;搭建测试环…

C++程序设计基础实验:C++对C的扩展特性与应用

C程序设计基础实验&#xff1a;C对C的扩展特性与应用 &#x1f525; 本文详细讲解C基础实验&#xff0c;包含C对C语言的扩充与增强特性&#xff0c;从零开始掌握函数重载、引用、指针等核心概念&#xff0c;附详细代码分析与运行结果。适合C初学者和有C语言基础想学习C的同学&a…

量子神经网络编译器开发指南:从理论突破到产业落地全景解析

本文深度剖析IBM Qiskit 5.0量子经典混合编译器的技术架构&#xff0c;详解如何基于含噪量子处理器实现MNIST手写数字分类任务&#xff08;准确率达89%&#xff09;。结合本源量子云、百度量子等国内平台免费配额政策&#xff0c;系统性阐述量子神经网络开发的技术路线与资源获…