谷歌身份验证器的使用超详细步骤
谷歌身份验证器Google Authenticator是谷歌推出的一款动态口令工具,解决大家各平台账户遭到恶意攻击的问题,一般在相关的服务平台登陆中除了用正常用户名和密码外,需要再输入一次谷歌认证器生成的动态口令才能验证成功,相当于输入二次密码,以达到账户的高安全性。例如交易所、金融平台、以及一些钱包等项目等等,都会使用谷歌身份验证器Google Authenticator来做二次认证,开启谷歌身份验证之后,登录账户,除了输入用户名和密码,还需要输入谷歌验证器上的动态密码。谷歌验证器上的动态密码,也称为一次性密码,密码按照时间或使用次数不断动态变化(默认 30 秒变更一次)
- 使用思路
1、第一次请求,判断未绑定谷歌验证码,那就生成随机base32的秘钥展示到页面,供用户创建账号,或者生成二维码,供用户在手机端使用谷歌验证器扫码创建账号
2、绑定验证,将手机app谷歌验证器生成的验证码输入到需要登录的平台验证,成功后将秘钥存入数据库;
3、绑定过后每次请求查询数据库的秘钥生成二维码传出;
4、取消绑定,清除数据库的数据。 - 使用步骤
手机上下载谷歌身份验证器,便于生成验证码
iPhone手机:在App Store中搜索 Google Authenticator
安卓手机:复制该链接到浏览器下载,http://d7.xiaotongqq.com/googe.apk - 整合java
1.导入依赖
<!--胡图工具包--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.2</version> </dependency><!--二维码的生成工具类--> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency><!--谷歌身份验证器--> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.12</version> </dependency>
编写谷歌身份验证器工具类
import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import org.apache.commons.codec.binary.Base32;import org.apache.commons.codec.binary.Base64;public class GoogleAuthenticator { public static final int SECRET_SIZE = 10; public static final String SEED = "g8GjEvTbW5oVSV7avL47357438reyhreyuryetredLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx"; public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG"; int window_size = 10; // default 3 - max 17 public void setWindowSize(int s) { if (s >= 1 && s <= 17) window_size = s; } public static String generateSecretKey() { SecureRandom sr = null; try { sr = SecureRandom.getInstance(RANDOM_NUMBER_ALGORITHM); sr.setSeed(Base64.decodeBase64(SEED.getBytes())); byte[] buffer = sr.generateSeed(SECRET_SIZE); Base32 codec = new Base32(); byte[] bEncodedKey = codec.encode(buffer); return new String(bEncodedKey); } catch (NoSuchAlgorithmException e) { // should never occur... configuration error } return null; } public static String getQRBarcode(String label, String user, String secret) { String format = "otpauth://totp/%s:%s?secret=%s"; return String.format(format, label, user, secret); } public static String getQRBarcode(String user, String secret) { String format = "otpauth://totp/%s?secret=%s"; return String.format(format, user, secret); } public boolean check_code(String secret, long code, long timeMses) { if(secret == null || "".equals(secret)) { return false; } Base32 codec = new Base32(); byte[] decodedKey = codec.decode(secret); // convert unix msec time into a 30 second "window" // this is per the TOTP spec (see the RFC for details) long t = (timeMses / 1000L) / 30L; // Window is used to check codes generated in the near past. // You can use this value to tune how far you're willing to go. for (int i = -window_size; i <= window_size; ++i) { long hash; try { hash = verify_code(decodedKey, t + i); } catch (Exception e) { // Yes, this is bad form - but // the exceptions thrown would be rare and a static // configuration problem e.printStackTrace(); throw new RuntimeException(e.getMessage()); // return false; } if (hash == code) { return true; } } // The validation code is invalid. 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; // We're using a long because Java hasn't got unsigned int. long truncatedHash = 0; for (int i = 0; i < 4; ++i) { truncatedHash <<= 8; // We are dealing with signed bytes: // we just keep the first byte. truncatedHash |= (hash[offset + i] & 0xFF); } truncatedHash &= 0x7FFFFFFF; truncatedHash %= 1000000; return (int) truncatedHash; }}
测试生成秘钥
import cn.hutool.core.io.FileUtil;import cn.hutool.extra.qrcode.QrCodeUtil;import com.example.vehicleinformationsystem.util.GoogleAuthenticator;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;@SpringBootTestclass VehicleInformationSystemApplicationTests { private static String secretKey = ""; @Test void contextLoads() { //生成秘钥 secretKey = GoogleAuthenticator.generateSecretKey(); System.out.println("秘钥:"+secretKey); }}
结果:
秘钥:DPSKD2HAZVANIXX7
秘钥使用方式:
注:该秘钥应该提示用户备份,切勿泄露给第三方,仅展示一次
3.1.在手机上下载谷歌身份验证器(下载方式参考上文)
3.2.点击右下角加号
3.3.点击输入设置秘钥
3.4.输入需要登录的平台用户名,以及刚才的秘钥,选择基于时间,点击添加
3.5.添加成功后,如下所示
3.6.将账号的二维码填写到需要登录的平台进行验证
4.测试生成二维码
@Test void contextLoads() { //生成秘钥 secretKey = GoogleAuthenticator.generateSecretKey(); System.out.println("秘钥:"+secretKey); //生成二维码信息 String QRBarcode = GoogleAuthenticator.getQRBarcode("system_admin",secretKey); System.out.println("二维码所需要的信息:"+QRBarcode); //生成二维码 300 表示二维码的大小 D:\img\aa\qrcode.jpg 表示为二维码的生成路径 QrCodeUtil.generate(QRBarcode, 300, 300, FileUtil.file("D:\\img\\aa\\qrcode.jpg")); }
生成结果:
使用方式:
4.1.在手机上下载谷歌身份验证器(下载方式参考上文)
4.2.点击右下角加号
4.3.点击扫描二维码
4.4.扫描生成的二维码,即可
5.5.将账号的二维码填写到需要登录的平台进行验证
验证码验证
这里就选择刚才生成的秘钥账户,system
//刚才生成的秘钥 private static String secretKey = "DPSKD2HAZVANIXX7"; @Test void testData() { String code = "126128"; long time = System.currentTimeMillis (); GoogleAuthenticator g = new GoogleAuthenticator (); boolean result = g.check_code (secretKey,Long.valueOf(code),time ); System.out.println ( "验证码是否正确--》"+result ); }
输出结果:
验证码是否正确--》true
来源地址:https://blog.csdn.net/qq_46122292/article/details/127629244
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341