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.pswp.cn/bicheng/77383.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/77383.shtml
英文地址,請注明出處:http://en.pswp.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;系統性闡述量子神經網絡開發的技術路線與資源獲…