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;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值