Google Authenticator集成java

背景

最近公司要求所有内网未集成单点的系统做双因子验证,为了节约成本,最终选择Google Authenticator

原理

使用密钥和时间戳通过一种算法生成一个6位数字的一次性验证码

集成流程

1、手机下载 Google Authenticator
	IOS:在App Store 搜索 Google Authenticator
	Android:
		打开连接 https://en.softonic.com/download
		右上角搜索 Google Authenticator
		选择平台 Platform:Android
		点击下方 Google Authenticator
		点击 FREE DOWNLOAD
		再点击 FREE APK DOWNLOAD 等待下载完成
2、生成Secret
	调用代码中的 genSecret() 方法生成,记得保存起来,用户需要使用 
3、用户扫描二维化进行绑定(也可以拿到密钥手动绑定)
	1、当前用户生成的密钥可以生成二维码,用户用app右下角扫描二维码即可添加
		参考代码中的main方法
	2、手动添加
		这里需要知道密钥,添加上名称和密钥即可
4、输入用户名、密码、动态码
5、登录成功

集成流程图

在这里插入图片描述

代码

import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
//需要大于1.8 版本 commons-codec-1.8.jar
public class GoogleAuthenticator {
    public static final int SECRET_SIZE = 10;
    public static final String SEED = "g8GjEvTbW5oVSV7avLBdwIHqGlUYNzKFI7izOF8GwLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx";
    public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG";
    int window_size = 3;
    public void setWindowSize(int s) {
        if (s >= 1 && s <= 17)
            window_size = s;
    }
    //生成密钥
    public static String genSecret() {
        return GoogleAuthenticator.generateSecretKey();
    }

    public static void main(String[] args) {
        String format = "otpauth://totp/ACCOUNT?secret=%s&issuer=%s";
        String barcodeURL= String.format(format, "PO4F2DIF74VR4ARO", "appname");
        //生成二维码
        System.out.println(rwm);
    }
    public static String generateSecretKey() {
        String encodedKey = null;
        try {
            SecureRandom 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);
            encodedKey = new String(bEncodedKey);
        }catch (NoSuchAlgorithmException e) {
        }
        return encodedKey;
    }
    //验证密钥
    public 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) {
                return false;
            }
            if (hash == code) {
                return true;
            }
        }
        return false;
    }

    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;
    }
}
以下是 Google AuthenticatorJava 代码: ```java import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base32; public class GoogleAuthenticator { // These fields are required for generating codes. private static final int SECRET_SIZE = 10; private static final int INTERVAL = 30; // These fields are required for validating codes. private static final int WINDOW_SIZE = 3; private static final Base32 base32 = new Base32(); /** * Generate a new secret key. */ public static String generateSecretKey() { SecureRandom random = new SecureRandom(); byte[] bytes = new byte[SECRET_SIZE]; random.nextBytes(bytes); return base32.encodeToString(bytes); } /** * Generate a code for the given secret key and time. */ public static int generateCode(String secret, long time) throws NoSuchAlgorithmException, InvalidKeyException { byte[] key = base32.decode(secret); byte[] data = new byte[8]; long value = time / INTERVAL; for (int i = 7; i >= 0; i--) { data[i] = (byte) (value & 0xff); value >>= 8; } SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(signingKey); byte[] hash = mac.doFinal(data); int offset = hash[hash.length - 1] & 0xf; int truncatedHash = 0; for (int i = 0; i < 4; i++) { truncatedHash <<= 8; truncatedHash |= (hash[offset + i] & 0xff); } truncatedHash &= 0x7fffffff; truncatedHash %= 1000000; return truncatedHash; } /** * Validate a code for the given secret key and time. */ public static boolean validateCode(String secret, int code, long time) throws NoSuchAlgorithmException, InvalidKeyException { for (int i = -WINDOW_SIZE; i <= WINDOW_SIZE; i++) { long t = time + i * INTERVAL; int c = generateCode(secret, t); if (c == code) { return true; } } return false; } public static void main(String[] args) throws Exception { // Generate a new secret key. String secret = generateSecretKey(); System.out.println("Secret key: " + secret); // Get the current time. long time = System.currentTimeMillis(); // Generate a code for the current time. int code = generateCode(secret, time); System.out.println("Code: " + code); // Validate the code for the current time. boolean valid = validateCode(secret, code, time); System.out.println("Valid: " + valid); } } ``` 这个 Java 类包含了三个方法: - `generateSecretKey()`:生成一个新的密钥。 - `generateCode(secret, time)`:使用给定的密钥和时间生成一个验证码。 - `validateCode(secret, code, time)`:使用给定的密钥、验证码和时间验证代码是否有效。 这三个方法都使用了 Google Authenticator 协议,可以用于生成和验证 Google Authenticator 代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值