目录
应用场景:通过google authenticator 生成验证码进行登录
原理:本文不再陈述,参考网上搜索结果
过程:定义种子秘钥-->生成私钥-->根据私钥到app应用上获取验证--->校验验证码
app: ios 和andriod的app会有一定差异,网上可以找到,ios可以到app store搜索获取

1.定义种子秘钥
种子秘钥根据项目自己定义一个高复杂度的秘钥
代码中这段
public static final String SEED = "F583513762484929976ED25B18FDE6B4";
以下工具完成:定义种子秘钥-->生成私钥
@Slf4j
public class GoogleAuthenticatorUtils {
public static final int SECRET_SIZE = 10;// 来自谷歌文档,不用修改
public static final String SEED = "F583513762484929976ED25B18FDE6B4";// 产生密钥的种子 种子秘钥一个 私钥可以生成多个,main方法中
public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG";// 安全哈希算法(Secure Hash Algorithm)
private static Integer window_size = 3;//可偏移的时间 -- 3*30秒的验证时间(客户端30秒生成一次验证码)
/**
* 生成密钥
*
* @return
*/
public static String generateSecretKey() {
SecureRandom sr;
try {
sr = SecureRandom.getInstance(RANDOM_NUMBER_ALGORITHM);
sr.setSeed(Base64.decodeBase64(SEED));
byte[] buffer = sr.generateSeed(SECRET_SIZE);
Base32 codec = new Base32();
byte[] bEncodedKey = codec.encode(buffer);
return new String(bEncodedKey);
} catch (Exception e) {
log.error("generateSecretKey:" + e.getMessage(), e);
}
return null;
}
/**
* 校验验证码
*
* @param secret
* @param code
* @param timeMsec
* @return
*/
public static Boolean check_code(String secret, long code, long timeMsec) {
Base32 codec = new Base32();
byte[] decodedKey = codec.decode(secret);
long t = (timeMsec / 1000L) / 30L;
for (int i = -window_size; i <= window_size; ++i) {
long hash;
try {
hash = verify_code(decodedKey, t + i);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("校验异常");
}
if (hash == code) {
return true;
}
}
return false;
}
/**
* 生成验证码
*
* @param key
* @param t
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
private static int verify_code(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException {
byte[] data = new byte[8];
long value = t;
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signKey);
byte[] hash = mac.doFinal(data);
int offset = hash[20 - 1] & 0xF;
long truncatedHash = 0;
for (int i = 0; i < 4; ++i) {
truncatedHash <<= 8;
truncatedHash |= (hash[offset + i] & 0xFF);
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= 1000000;
return (int) truncatedHash;
}
public static void main(String[] args) {
String secretKey = generateSecretKey();
System.out.println(secretKey);
Boolean aBoolean = check_code("KISNJ4O2OMHKB73F", Long.valueOf("943952"), System.currentTimeMillis());
System.out.println(aBoolean);
}
}
2.生成私钥
String secretKey = generateSecretKey(); 生成私钥 ,生成的私钥配置到app中,名称随便,秘钥填生成的,实际使用中你有可能使用接口api或者扫描方式来调用接口获取
3.根据私钥到app应用上获取验证
生成的私钥配置到app中,名称随便,秘钥填生成的,即可立即获取
4.校验验证码
登录校验则是这段核心,取用户配置的私钥+传递过来的6位验证码
check_code("KISNJ4O2OMHKB73F", Long.valueOf("943952"), System.currentTimeMillis());
关于私钥,二维码生成可通过在线二维码生成工具获取,私钥配置到数据库中用于后续登录校验使用(即main方法中实际校验结果)
网上搜索一堆:在线二维码生成工具 生成下载即可;代码方面的可参考搜其他相关二维码生成工具代码
本文详细介绍了如何使用Google Authenticator进行两步验证的实现步骤,包括定义种子秘钥、生成私钥、在APP中获取验证码以及校验验证码的过程。主要代码示例展示了如何在Java中生成和校验密钥,对于iOS和Android应用,可以搜索相关教程获取更多信息。
2500

被折叠的 条评论
为什么被折叠?



