一次性驗證碼的簡單使用
前言
一次性驗證碼(One-Time Password, OTP)是一種動態(tài)生成且僅能使用一次的密碼,主要用于增強賬戶安全性,防止密碼泄露或重放攻擊。
使用
添加依賴
<dependency>
<groupId>com.eatthepath</groupId>
<artifactId>java-otp</artifactId>
<version>0.2.0</version>
</dependency>
代碼實現(xiàn)
package com.imooc;
import com.eatthepath.otp.HmacOneTimePasswordGenerator;
import com.eatthepath.otp.TimeBasedOneTimePasswordGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
/**
* 一次性驗證碼
*/
public class TestOtp2 {
private static TimeBasedOneTimePasswordGenerator totp;
static {
try {
totp = new TimeBasedOneTimePasswordGenerator();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
//同一個輸入在同一個時間窗口內(nèi)驗證碼是一樣的,如果想要不一樣,可以拼接上時間戳或計數(shù)器等變量
String input = "123456";
String otpCode = generateOtpCode(input, Instant.now());
System.out.println("otpCode:" + otpCode);
TimeUnit.SECONDS.sleep(31);
System.out.println(verifyOtpCode(input, otpCode, 0));
}
/**
* 生成驗證碼
*
* @param input 輸入數(shù)據(jù)
* @param timestamp 時間戳
* @return
*/
private static String generateOtpCode(String input, Instant timestamp) throws Exception {
byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(bytes, TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA1);
int code = totp.generateOneTimePassword(keySpec, timestamp);
// 位數(shù)不足左補0
int len = HmacOneTimePasswordGenerator.DEFAULT_PASSWORD_LENGTH;
return String.format("%0" + len + "d", code);
}
/**
* 校驗驗證碼是否正確,比如容忍度是1,那就是校驗90秒內(nèi)這個驗證碼是否是有效的
*
* @param input 之前的輸入數(shù)據(jù)
* @param otpCode 驗證碼
* @param tolerance 容忍度
* @return
*/
private static boolean verifyOtpCode(String input, String otpCode, int tolerance) throws Exception {
byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(bytes, TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA1);
Instant now = Instant.now();
// 當(dāng)前時間戳/30000
long counter = now.toEpochMilli() / totp.getTimeStep().toMillis();
// 30秒一個時間窗口
for (long ts = counter - tolerance; ts <= counter + tolerance; ts++) {
int code = totp.generateOneTimePassword(keySpec, ts);
// 位數(shù)不足左補0
int len = HmacOneTimePasswordGenerator.DEFAULT_PASSWORD_LENGTH;
String newOtpCode = String.format("%0" + len + "d", code);
if (otpCode.equals(newOtpCode)) {
return true;
}
}
return false;
}
}

浙公網(wǎng)安備 33010602011771號