实现一个Google身份验证代替短信验证

最近才知道公司还在做国外的业务,要实现一个登陆辅助验证系统。咱们国内是用手机短信做验证,当然 这个google身份验证只是一个辅助验证登陆方式。看一下演示

 

看到了嘛。 手机下载一个谷歌身份验证器就可以 。

谷歌身份验证器,我本身是一个基于时间做加密计算然后得出相同结果 本身很简单。

下边在网上查的 可以做一下了解:谷歌身份验证就是基于TOTP算法

TOTP算法,全称为“Time-based One-time Password algorithm”,中文译为基于时间的一次性密码算法。它是一种从共享密钥和当前时间计算一次性密码的算法,已被采纳为Internet工程任务组标准RFC 6238。TOTP是开放身份验证计划(OATH)的基石,并被用于许多双因素身份验证系统。详细的可以百度一下搜索原理,我们这里只是介绍一下使用。

下边是代码 :

import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;
import org.springframework.util.StringUtils;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;public class GoogleAuthenticator {/*** 时间前后偏移量 目的解决30秒内有计算有误差不一致的发生*/private static int WINDOW_SIZE = 0;/*** 加密方式,HmacSHA1、HmacSHA256、HmacSHA512*/private static final String CRYPTO = "HmacSHA1";/*** 生成二维码内容** @param secretKey 密钥* @param account   账户名* @param issuer    网站地址(可不写)* @return*/public static String getQrCodeText(String secretKey, String account, String issuer) {String normalizedBase32Key = secretKey.replace(" ", "").toUpperCase();try {return "otpauth://totp/"+ URLEncoder.encode((!StringUtils.isEmpty(issuer) ? (issuer + ":") : "") + account, "UTF-8").replace("+", "%20")+ "?secret=" + URLEncoder.encode(normalizedBase32Key, "UTF-8").replace("+", "%20")+ (!StringUtils.isEmpty(issuer) ? ("&issuer=" + URLEncoder.encode(issuer, "UTF-8").replace("+", "%20")) : "");} catch (UnsupportedEncodingException e) {throw new IllegalStateException(e);}}/*** 检验 code 是否正确** @param secret 密钥* @param code   code* @param time   时间戳* @return*/public static boolean checkCode(String secret, long code, long time) {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 = (time / 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.long hash;for (int i = -WINDOW_SIZE; i <= WINDOW_SIZE; ++i) {try {hash = verifyCode(decodedKey, t + i);} catch (Exception e) {return false;}if (hash == code) {return true;}}return false;}/*** 根据时间偏移量计算** @param key* @param t* @return* @throws NoSuchAlgorithmException* @throws InvalidKeyException*/private static long 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, CRYPTO);Mac mac = Mac.getInstance(CRYPTO);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 truncatedHash;}public static String getkeyBase32() {// 生成一个随机的密钥字节数组SecureRandom random = new SecureRandom();byte[] keyBytes = new byte[20]; // 一般长度为16、20或32字节random.nextBytes(keyBytes);// 将密钥转换成Base32格式以便用户显示或扫描二维码Base32 base32 = new Base32();String secretKeyBase32 = base32.encodeToString(keyBytes);return secretKeyBase32;}public static void main(String[] args) {
//        String secretKeyBase32 = getkeyBase32();String secretKeyBase32 = "YR3TEMNWNWOVMFPFK3BB2SLM2P3IV6MF";System.out.println("加密信息》》》" + secretKeyBase32);System.out.println("拿到这个字符串 二维码工具:去生成二维码图片就可以了" + getQrCodeText(secretKeyBase32, "jxd", "hdjz"));System.out.println(checkCode(secretKeyBase32, Long.parseLong("034944"), System.currentTimeMillis()));}
}

我这个方法,都是基于现成的,不需要额外引入j2totp 等类库 很方便可以拿去用 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/294473.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每天五分钟深度学习:神经网络和深度学习有什么样的关系?

本文重点 神经网络是一种模拟人脑神经元连接方式的计算模型&#xff0c;通过大量神经元之间的连接和权重调整&#xff0c;实现对输入数据的处理和分析。而深度学习则是神经网络的一种特殊形式&#xff0c;它通过构建深层次的神经网络结构&#xff0c;实现对复杂数据的深度学习…

python爬虫----了解爬虫(十一天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

算法打卡day23

今日任务&#xff1a; 1&#xff09;39. 组合总和 2&#xff09;40.组合总和II 3&#xff09;131.分割回文串 39. 组合总和 题目链接&#xff1a;39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;…

NB-IOT——浅谈NB-IOT及模块测试

浅谈NB-IOT及模块基本使用测试 介绍什么是NB-IOT&#xff1f;NB-IOT的特点 使用准备基本使用 总结 介绍 什么是NB-IOT&#xff1f; NB-IoT&#xff0c;即窄带物联网&#xff08;Narrowband Internet of Things&#xff09;&#xff0c;是一种低功耗广域物联网&#xff08;LPW…

第十四届蓝桥杯(八题C++ 题目+代码+注解)

目录 题目一&#xff08;日期统计 纯暴力&#xff09;&#xff1a; 代码&#xff1a; 题目二&#xff08;01串的熵 模拟&#xff09;&#xff1a; 代码&#xff1a; 题目三&#xff08;治炼金属&#xff09;&#xff1a; 代码&#xff1a; 题目四&#xff08;飞机降落 深度…

springcloud基本使用二(远程调用)

创建两个springboot maven子项目 子项目名称分别为order-server和user-server 配置user-server子项目: 所需依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependenc…

【洛谷】P9240 [蓝桥杯 2023 省 B] 冶炼金属

题目链接 P9240 [蓝桥杯 2023 省 B] 冶炼金属 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 这道题可以用数学的方法去做&#xff0c;但是我想不到&#x1f607;有兴趣的可以去看看数学的题解 比较简单的思路就是二分查找&#xff0c;轻松简单不费脑&#xff0c;带你…

Linux中查看文件内容的命令

文章目录 一、七类常见的Linux的文件二、显示命令三、分页显示四、显示文件前后内容五、压缩、解压缩六、补充 一、七类常见的Linux的文件 字符文件类型-普通文件&#xff0c;包括纯文本文件、二进制文件、各种压缩文件等。在find命令中&#xff0c;type 选项中用 f来表示d目录…

共享社会经济路径(SSP1-5)中国及分省人口预估数据库_v2

v1数据集&#xff1a; 在共享社会经济路径&#xff08;SSPs&#xff09;全球框架下&#xff0c;根据本地化人口和经济参数&#xff0c;采用人口-发展-环境&#xff08;PDE&#xff09;模型&#xff0c;构建2020-2100年SSPs人口格点数据&#xff1b;采用柯布-道格拉斯&#xff…

AcWing刷题-游戏

游戏 DP l lambda: [int(x) for x in input().split()]n l()[0] w [0] while len(w) < n:w l()s [0] * (n 1) for i in range(1, n 1): s[i] s[i - 1] w[i]f [[0] * (n 1) for _ in range(n 1)]for i in range(1, n 1): f[i][i] w[i]for length in range(2, …

C,C++——指针详解

目录 1.指针的基本概念 代码示例&#xff1a; 2.指针所占内存空间 代码示例&#xff1a; 3.空指针和野指针 代码示例&#xff1a; 4.const修饰指针 代码示例&#xff1a; 5.指针和数组 代码示例&#xff1a; 6.指针和函数 代码示例&#xff1a; 7.指针&#x…

C++面向对象:C++的垃圾回收

垃圾收集是编程语言中 使用的内存管理技术之一。 它是一种自动内存管理技术&#xff0c;作为许多编程语言的功能添加。垃圾收集器收集或回收分配给变量或对象但不再被程序使用的内存&#xff1b; 这也称为垃圾。 三种基本的垃圾收集算法及其改进算法 1、引用计数算法 引用技…

【算法刷题day10】Leetcode:232.用栈实现队列、225. 用队列实现栈

文章目录 Leetcode 232.用栈实现队列解题思路代码总结 Leetcode 225. 用队列实现栈解题思路代码总结 stack、queue和deque对比 草稿图网站 java的Deque Leetcode 232.用栈实现队列 题目&#xff1a;232.用栈实现队列 解析&#xff1a;代码随想录解析 解题思路 一个栈负责进&a…

Kafka入门到实战-第二弹

Kafka入门到实战 Kafka快速开始官网地址Kafka概述Kafka术语Kafka初体验更新计划 Kafka快速开始 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://kafka.apache.org/Kafka概述 Apache Kafka 是一个开源的分布式事件流…

谷粒商城——通过接口幂等性防止重复提交订单

如果用户向后端服务提交多次相同订单的提交服务&#xff0c;那么后端应该只生成一条订单记录。 有一些操作天然是幂等的&#xff0c;如查询操作和删除操作等。 幂等性实现 1.token机制&#xff08;仅这个方法适用于订单的重复提交&#xff09; 后端先生成1个令牌将其记录在R…

UE4_动画基础_ 瞄准偏移1D(Aim Offset Blend Space 1D)

瞄准偏移1D基本上可以完成角色的向左看向右看或者向上看向下看&#xff0c;像混合空间1D一样只有一个轴向可用。 操作步骤&#xff1a; 1、新建第三人称模板项目。 2、右键——动画——瞄准偏移1D 选取骨骼 双击打开 3、瞄准偏移混合的是姿势&#xff0c;我们需要创建姿势。 …

网络以太网之(1)基础概念

网络以太网之(1)基础概念 Author: Once Day Date: 2024年4月1日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

【python plotly库介绍】从视觉到洞见:桑基图在业务分析中的应用【保姆级教程过于详细珍藏版】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 本文结构&#xff1a;工具介绍python实现库 - 案例 - 分析思路与过程 实战专栏&#xff1a;https://blog.csdn.net/cciehl/category_12615648.html 备注说明&#xff1a; 企业…

2.java openCV4.x 入门-hello OpenCV

专栏简介 &#x1f492;个人主页 &#x1f4f0;专栏目录 点击上方查看更多内容 &#x1f4d6;心灵鸡汤&#x1f4d6;我们唯一拥有的就是今天&#xff0c;唯一能把握的也是今天建议把本文当作笔记来看&#xff0c;据说专栏目录里面有相应视频&#x1f92b; &#x1f9ed;文…

Web日志/招聘网站/电商大数据项目样例【实时/离线】

Web服务器日志分析项目 业务分析 业务背景 ​ 某大型电商公司&#xff0c;产生原始数据日志某小时达4千五万条&#xff0c;一天日志量月4亿两千万条。 主机规划 &#xff08;可略&#xff09;日志格式&#xff1a; 2017-06-1900:26:36101.200.190.54 GET /sys/ashx/ConfigH…