googleauthenticator二次验证

原理

我们先看下别人的文章 Google账户两步验证的工作原理 来了解一下原理。

从上面的文章我们看来有2种算法, 1. HOTP, 2. TOTP, 我们都知道如果算法一样, 输入参数一样, 那么必然得到的结果是一样的

客户端和服务器绑定的时候, 首先需要协商好一个密钥K, 该秘钥只有客户端和服务器知道。

HOTP是基于计数器的密码生成, 服务器和客户端都保存着一个相同的计数器, 当需要验证的时候, 客户端计算一次密码, 客户端的计数器+1, 提交验证的时候, 客户端计算后, 服务器的计数器+1, 这样就服务器和客户端的计数器保持一样。

TOTP是基于时间的密码生成, 服务器和客户端都根据时间来计算密码, 比较客户端提交的密码是否一致。

实战

网站登录二次校验。

流程

绑定阶段:

  1. 生成秘钥
  2. google authenticator绑定

登录阶段:

  1. 登录
  2. 判断账号密码是否正确
  3. 如果正确, 再使用二次校验

开发

  • maven依赖
<!-- https://mvnrepository.com/artifact/com.warrenstrange/googleauth -->
<dependency>
    <groupId>com.warrenstrange</groupId>
    <artifactId>googleauth</artifactId>
    <version>1.5.0</version>
</dependency>
  • 模拟绑定
/**
 * 绑定
 *
 */
public static void bind(){
    // 获取秘钥, 进行协商(使用预先生成好的)
    GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
    GoogleAuthenticatorKey credentials = googleAuthenticator.createCredentials();
    System.out.println(credentials.getKey()); // 记录下来, 绑定设备后, 需要此key来做校验

    // 生成绑定的url
    GoogleAuthenticatorQRGenerator gAuthenQRGenerator = new GoogleAuthenticatorQRGenerator();
    String otpAuthTotpURL = gAuthenQRGenerator.getOtpAuthTotpURL("itkaoti", "xiaodoubi", credentials);
    System.out.println(otpAuthTotpURL);
}

public static void main(String[] args) {
    bind();
}

结果:

M2IG4BPH6PWFQZKZZMA2MARPFEA7LDAF
otpauth://totp/itkaoti:xiaodoubi?secret=M2IG4BPH6PWFQZKZZMA2MARPFEA7LDAF&issuer=itkaoti&algorithm=SHA1&digits=6&period=30

记录上面的 M2IG4BPH6PWFQZKZZMA2MARPFEA7LDAF 秘钥, 后续验证需要, 下面的otpauth链接 直接使用在线二维码转换, 转成二维码

下面开始手机绑定, 我们需要先安装google Authenticator, 打开app 具体操作: 右上角三个点 --> 添加账户 --> 个人账户 --> 扫描QR码

扫描后我们发现多了一个itkaoti xiaodoubi的账号, 点开就可以看到一次性密码代码。

验证

public static void main(String[] args) {
    verify();
}


public static void verify(){
    String key = "M2IG4BPH6PWFQZKZZMA2MARPFEA7LDAF"; // 绑定步骤的生成的key
    while(true){
        System.out.println("请输入authenticator二次校验密码...");
        String next = new Scanner(System.in).next();
        GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
        boolean authorize = googleAuthenticator.authorize(key, Integer.parseInt(next));
        if(authorize){
            System.out.println("校验成功");
        }else{
            System.out.println("校验失败");
        }
    }
}

结果:

请输入authenticator二次校验密码...
097158
校验成功
请输入authenticator二次校验密码...
123456
校验失败
请输入authenticator二次校验密码...

使用二次校验, 极大的增加了网站的安全性。

具体api讲解

GoogleAuthenticator

主要的类, 我们是它来生成了key, 以及校验

方法 说明
createCredentials() 生成秘钥
createCredentials(String userName) 根据用户名生成秘钥
getTotpPassword(String secret) 根据秘钥获取验证码
public int getTotpPassword(String secret, long time) 根据秘钥获取验证码(指定时间)
getTotpPasswordOfUser(String userName) 根据用户名获取验证码
getTotpPasswordOfUser(String userName, long time) 根据用户名获取验证码(指定时间)
authorize(String secret, int verificationCode) 验证
authorize(String secret, int verificationCode, long time) 验证(指定时间)
authorizeUser(String userName, int verificationCode) 验证
authorizeUser(String userName, int verificationCode, long time) 验证(指定时间)

GoogleAuthenticatorConfig

private long timeStepSizeInMillis = TimeUnit.SECONDS.toMillis(30); // 验证码刷新时间
private int windowSize = 3;
private int codeDigits = 6; // 验证码个数
private int numberOfScratchCodes = 5;
private int keyModulus = (int) Math.pow(10, codeDigits);
private int secretBits = 160;
private KeyRepresentation keyRepresentation = KeyRepresentation.BASE32;
private HmacHashFunction hmacHashFunction = HmacHashFunction.HmacSHA1;