• 介绍

既然来看该文章就应该知道Google的两步认证是干什么的,如果需要APP(Google Authenticator)的可以私信我。

验证原理讲解:

为每个用户在注册之前生成32位随机码(该码一般会存入数据库)。

调用API传入32位随机码,生成正确的6位验证码,每隔1分种会变化。

根据用户输入的6位验证码和正确的6位验证码做匹配,相同则登陆成功,不同则验证码时间失效或错误。

用户绑定讲解:

调用API生成32位随机码。。

调用API生成二维码QR字符串,需要传入用户信息(比如邮箱,昵称等),标题,以及生成的32位随机码。

调用API将二维码QR字符串转化为图片后以Base64的方式展现到前端页面上。

用户使用APP(Google Authenticator)扫码添加后,点击确认绑定,即可看到6位验证码。

后端根据API生成的32位随机码,用户信息(用来确定数据库中用户记录),以及输入6位验证码,通过API传入32位随机码验证,当其与输入的验证码相同时,则绑定成功,把32位随机码持久化与用户绑定。

  • 准备工作

导入一下Maven依赖

        <dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>

  

  • 导入工具类GoogleAuthenticatorUtils
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; /**
* @ProjectName: cdkj-framework
* @Package: com.cdkjframework.util.tool
* @ClassName: GoogleAuthenticatorUtils
* @Description: 身份验证
* @Author: xiaLin
* @Date: 2023/4/3 15:16
* @Version: 1.0
*/
public class GoogleAuthenticatorUtils { /**
* 生成的key长度( Generate secret key length)
*/
public static final int SECRET_SIZE = 10; /**
* SEED 值
*/
public static final String SEED = "g8GjEvTbW5oVSV7avL47357438reyhreyuryetredLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx"; /**
* Java实现随机数算法
*/
public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG"; /**
* 最多可偏移的时间
* // default 3 - max 17
*/
private int window_size = 3; /**
* 设置窗口大小。这是一个整数值,表示
* 我们允许30秒的窗口窗口越大
* 时钟歪斜。
*
* @param s window size - must be >=1 and <=17. Other values are ignored
*/
public void setWindowSize(int s) {
if (s >= 1 && s <= 17)
window_size = s;
} /**
* 生成一个随机密钥。这必须由服务器保存,并且
* 与用户帐户关联,以验证谷歌显示的代码
* 身份验证人。用户必须在其设备上注册此机密。
* 生成一个随机秘钥
*
* @return 返回 secret key
*/
public static String generateSecretKey() {
SecureRandom random = null;
try {
random = SecureRandom.getInstance(RANDOM_NUMBER_ALGORITHM);
random.setSeed(Base64.decodeBase64(SEED));
byte[] buffer = random.generateSeed(SECRET_SIZE);
Base32 codec = new Base32();
byte[] bEncodedKey = codec.encode(buffer);
String encodedKey = new String(bEncodedKey);
return encodedKey;
} catch (NoSuchAlgorithmException e) {
// 不应该发生。。。配置错误
}
return null;
} /**
* 生成一个google身份验证器,识别的字符串,只需要把该方法返回值生成二维码扫描就可以了。
*
* @param user 账号
* @param secret 密钥
* @return 返回结果
*/
public static String getQRBarcode(String user, String secret, String issuer) {
String format = "otpauth://totp/%s?secret=%s&issuer=%s";
return String.format(format, user, secret, issuer);
} /**
* 验证code是否合法
*
* @param secret 用户的秘密
* @param code 用户设备上显示的代码
* @param timeMsec 时间(毫秒)
* @return 返回结果
*/
public boolean checkCode(String secret, long code, long timeMsec) {
Base32 codec = new Base32();
byte[] decodedKey = codec.decode(secret);
// 将unix毫秒时间转换为30秒的“窗口”
// 这是根据TOTP规范(有关详细信息,请参阅RFC)
long t = (timeMsec / 1000L) / 30L;
// 窗口用于检查最近生成的代码。
// 您可以使用此值来调整您愿意走多远。
for (int i = -window_size; i <= window_size; ++i) {
long hash;
try {
hash = verifyCode(decodedKey, t + i);
} catch (Exception e) {
// 抛出的异常将是罕见的,并且是静态的
// 配置问题
throw new RuntimeException(e.getMessage());
}
if (hash == code) {
return true;
}
}
// 验证代码无效。
return false;
} /**
* 验证随机码
*
* @param key 值
* @param t 时间
* @return 返回结果
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
private static int verifyCode(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是因为Java没有无符号int。
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认证Google Authenticator的更多相关文章

  1. 搭建Pritunl+Google认证远程连接

    搭建Pritunl+Google认证远程连接VPN 基于Centos7安装 ​ Pritunl是一款免费开源的 VPN 平台软件(但使用的不是标准的开源许可证,用户受到很多限制).这是一种简单有效的V ...

  2. Google高级技巧—google Hack★★★★

    google hacking事实上并算不上什么新东西,当时并没有重视这样的技术,觉得webshell什么的,并无太大实际用途.google hacking事实上并非如此简单... 经常使用的googl ...

  3. Google Inc.:Google APIs:23' 解决方案

    在导入一个项目是,出现 Unable to resolve target 'Google Inc.:Google APIs:6'第一种解决方法: compileSdkVersion 23 改成 com ...

  4. Google发展史 Google十三年

    http://blog.csdn.net/terryzero/article/details/5910617 "1997年9月15日,Larry Page 和 Sergey Brin 正式注 ...

  5. google搜索运算符+101个Google技巧 - Google技巧的终极收集

    下面内容整理自网络 搜索运算符 如果您使用我们的基本搜索技巧后,并未找到想要搜索的内容,可以尝试使用搜索运算符.您只需在 Google 搜索框中将这些符号或字词添加到搜索字词中,即可更好地掌控要显示的 ...

  6. 访问Google搜索,Google学术镜像搜索

    Google学术镜像搜索:http://dir.scmor.com/google/ 不用FQ也能访问谷歌搜索网站,让我们一起Google 不用FQ也能访问谷歌搜索网站,让我们一起Google(摘自:h ...

  7. Google Adsense Google判断广告点击作弊的方式和数据 数据分析

    Google判断广告点击作弊的几种方式和数据 - 王庆东mas - 博客园 http://www.cnblogs.com/x-poior/p/5581327.html 作弊广告点击的CTR数据太高网上 ...

  8. Google css & Google fonts

    最近用某开源模板做提案的时候, 抓包工具老是有外部Request. 问题出在某css中有这么一句: @import url(https://fonts.googleapis.com/css?famil ...

  9. Getting Started with Google Tango(Google Tango开始教程)

    https://developers.google.com/tango/ Build apps that understand space and motion in high fidelity on ...

  10. 纪念Google Reader—Google Reader的最后一天

    从2006年到今天,几乎每天我都会打开Google Reader,但是今天不一样,因为它是最后一天.心情有些依依不舍,像是与一位多年老朋友永别.因此我非常痛恨Google,先给你送来个好朋友,再从你身 ...

随机推荐

  1. Luogu P9870 NOIp2023 双序列拓展 题解 [ 紫 ] [ 动态规划 ] [ 分治 ] [ adhoc ]

    双序列拓展:很妙的特殊性质类 dp 题,由部分分引导向正解. 题意简化 你可以把序列 \(X\) 和序列 \(Y\) 中的每一个数复制若干倍并接到这个数后面,问能否构造出一种方案,使得两个序列长度相等 ...

  2. 如何基于DeepSeek开展AI项目

    关注公众号回复1 获取一线.总监.高管<管理秘籍> 书接上文:DeepSeek怎么突然就比肩GPT了? 最近一直在研究DeepSeek,作为应用层的选手,自然不会傻乎乎的想要去了解底层,我 ...

  3. 创建Graphics对象的三种方法

    参考链接:https://www.cnblogs.com/wax01/p/4982691.html 方法一.利用控件或窗体的Paint事件中的PainEventArgs 在窗体或控件的Paint事件中 ...

  4. [Windows] 联发科秒开bl一键版(mtk)

    声明 不是所有的联发科都可 天机 8000 8100 9000等不行 已知 天机820 天机1000 mtk G90t 天机800 可以 其余自己测试 除了新款均可 第一步 下载软件 (是个压缩包需要 ...

  5. Java进阶 - [1-5] 泛型

    一.什么是泛型   早期Java是使用Object来代表任意类型的,但是向下转型有强转的问题,这样程序并不安全.   针对List.Set.Map等集合类型,它们对存储的元素类型是没有任何限制的.例如 ...

  6. C# Socket通信简单示例

    https://files.cnblogs.com/files/mojiejushi/SocketDemo.rar

  7. linux服务问题传文件连不上问题远程问题等

    通过iptables相关命令实现防火墙的打开和关闭 1.首先可以在打开的终端使用iptables --help查看帮助使用命令: 2.查看防火墙状态:service iptables status(此 ...

  8. PPT图片搭配

  9. 【ABAQUS 二次开发笔记】一次获得多个积分点的输出到dat

    当使用shell单元进行composite laminate 建模时,可以为每一指定Intergration point 的个数,默认是3个.(abaqus有很多variable可以在intergra ...

  10. pandas表格数据-删除/赋值/字符串包含等

    官网:https://www.pypandas.cn/docs/ 1.删除某一固定列 del df['列名'] 删除某列某部分内容,以.str[0]取值 df['开始时间']=df['开始时间'].s ...