Google Authenticator 的原理是服務器隨機生成一個密鑰並保存並告知客戶端。用戶需要登陸時客戶端根據密鑰和時間戳通過一種算法生成一個6位數字的密碼。本文使用 java.util.zip.CRC32 模仿 Google Authenticator 實現此功能。
/**
* 生成驗證碼
* @param secret: 密鑰
* @param timeMinute: 時間戳(分鐘)
* @param codeLength: 驗證碼長度
* @return 指定長度的數字
*/
public static String generateCode(String secret, long timeMinute, int codeLength) {
String key = secret + timeMinute;
CRC32 crc32 = new CRC32();
crc32.update(key.getBytes());
String crc32ValueStr = String.valueOf(crc32.getValue());
return crc32ValueStr.substring(crc32ValueStr.length() - codeLength); // 可以改成其他規則
}
/***
* 校驗驗證碼
* @param secret: 密鑰
* @param verifyCode: 待校驗驗證碼
* @param expireMinute
* @return
*/
public static boolean verifyCode(String secret, String verifyCode, int codeLength, int expireMinute) {
long timeMillisecond = System.currentTimeMillis();
long timeMinute = minuteByMillisecond(timeMillisecond);
for (int i = -expireMinute; i <= expireMinute; ++i) {
String code = generateCode(secret, timeMinute + i, codeLength);
if(code.equals(verifyCode)) {
return true;
}
}
return false;
}
/***
* 獲取時間戳(分鐘)
* @param timeMillisecond: 時間戳(毫秒)
* @return
*/
private static long minuteByMillisecond(long timeMillisecond) {
return timeMillisecond / (1000 * 60);
}
使用:
final int CODE_LENGTH = 6;
final int CODE_EXPIRE_MINUTE = 1;
final String SECRET = "YOUR SECRET";
long timeMillisecond = System.currentTimeMillis();
long timeMinute = minuteByMillisecond(timeMillisecond);
String code = generateCode(SECRET, timeMinute, CODE_LENGTH);
boolean result = verifyCode(SECRET, code, CODE_LENGTH, CODE_EXPIRE_MINUTE);