验证码生成工具google authenticator

目录

1.定义种子秘钥

2.生成私钥

3.根据私钥到app应用上获取验证

4.校验验证码


应用场景:通过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方法中实际校验结果)

网上搜索一堆:在线二维码生成工具   生成下载即可;代码方面的可参考搜其他相关二维码生成工具代码

猜你喜欢

转载自blog.csdn.net/haohaounique/article/details/127031593