Google身份验证服务端实现

2023-05-16

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;
 
/**
 * google身份验证器,java服务端实现
 */
public class GoogleAuthenticator {
 
	// 生成的key长度( Generate secret key length)
	public static final int SECRET_SIZE = 10;
 
	public static final String SEED = "g8GjEvTbW5oVSV7avL47357438reyhreyuryetredLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx";
	// Java实现随机数算法
	public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG";
	// 最多可偏移的时间
	int window_size = 3; // default 3 - max 17
 
	/**
	 * set the windows size. This is an integer value representing the number of
	 * 30 second windows we allow The bigger the window, the more tolerant of
	 * clock skew we are.
	 * 
	 * @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;
	}
 
	/**
	 * Generate a random secret key. This must be saved by the server and
	 * associated with the users account to verify the code displayed by Google
	 * Authenticator. The user must register this secret on their device.
	 * 生成一个随机秘钥
	 * 
	 * @return secret key
	 */
	public static String generateSecretKey() {
		SecureRandom sr = null;
		try {
			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);
			String encodedKey = new String(bEncodedKey);
			return encodedKey;
		} catch (NoSuchAlgorithmException e) {
			// should never occur... configuration error
		}
		return null;
	}
 
	/**
	 * Return a URL that generates and displays a QR barcode. The user scans
	 * this bar code with the Google Authenticator application on their
	 * smartphone to register the auth code. They can also manually enter the
	 * secret if desired
	 * 
	 * @param user
	 *            user id (e.g. fflinstone)
	 * @param host
	 *            host or system that the code is for (e.g. myapp.com)
	 * @param secret
	 *            the secret that was previously generated for this user
	 * @return the URL for the QR code to scan
	 */
	public static String getQRBarcodeURL(String user, String host, String secret) {
		String format = "http://www.google.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=otpauth://totp/%s@%s?secret=%s";
		return String.format(format, user, host, secret);
	}
 
	/**
	 * 生成一个google身份验证器,识别的字符串,只需要把该方法返回值生成二维码扫描就可以了。
	 * 
	 * @param user
	 *            账号
	 * @param secret
	 *            密钥
	 * @return
	 */
	public static String getQRBarcode(String user, String secret) {
		String format = "otpauth://totp/%s?secret=%s";
		return String.format(format, user, secret);
	}
 
	/**
	 * Check the code entered by the user to see if it is valid 验证code是否合法
	 * 
	 * @param secret
	 *            The users secret.
	 * @param code
	 *            The code displayed on the users device
	 * @param timeMsec
	 *            The time in msec (System.currentTimeMillis() for example)
	 * @return
	 */
	public boolean check_code(String secret, long code, long timeMsec) {
		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 = (timeMsec / 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 org.junit.Test;
import java.util.HashSet;
import java.util.Set;

public class AuthTest {
	//当测试authTest时候,把genSecretTest生成的secret值赋值给它
		private static String secret="BYJBZYGU2AO4ZKK7";
	 
		@Test
		public void genSecretTest() {// 生成密钥
			secret = GoogleAuthenticator.generateSecretKey();
			// 把这个qrcode生成二维码,用google身份验证器扫描二维码就能添加成功
			String qrcode = GoogleAuthenticator.getQRBarcode("2816661736@qq.com", secret);
			System.out.println("qrcode:" + qrcode + ",key:" + secret);
		}
		/**
		 * 对app的随机生成的code,输入并验证
		 */
		 @Test
		public void verifyTest() {
		 	long code = 936171;
			long t = System.currentTimeMillis();
			GoogleAuthenticator ga = new GoogleAuthenticator();
			ga.setWindowSize(2); 
			boolean r = ga.check_code(secret, code, t);
			System.out.println("检查code是否正确?" + r);
		}

}

运行下面链接中下载的demo中的AuthTest的genSecretTest方法,控制台打印的结果如下图:
在这里插入图片描述
在这里插入图片描述
key:为app与服务端约定的秘钥,用于双方的认证。

qrcode:是app扫码能够识别的就是二维码值,把它生成二维码如下图:
在这里插入图片描述
打开google authenticator app软件选择扫描条形码按扭打开相机对二维码扫描加入账号,如下图:
在这里插入图片描述
把app中的数字,在AuthTest的verifyTest进行验证,如下图:
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Google身份验证服务端实现 的相关文章

  • 做网络赚钱成功的诀窍

    作者 芊蓝小编 日期 2010年07月30日 来源 互联网 1 不要把网络看得多么深奥难懂 它只是你挣钱的一个工具而已 2 问10个人 不如你自己动脑和手真正解析一件事情 3 不要试图掌握网络上的每个知识 谁都不可能学得完 学会跟你工作最相
  • 百度无人驾驶apollo项目训练最佳算法模型改进

    百度无人驾驶apollo项目训练最佳算法模型改进 google的无人驾驶的最新算法训练模型 现在已经为外界熟知 使用了较为复杂的训练模型 当然了 google的无人驾驶也没有真正的落地实用化 所以google的算法也不是最终解决方案 百度a
  • PDF 的各种操作,我用 Python 来实现(附网站和操作指导)

    导言 PDF 处理是日常工作中的常见需求 包括 PDF 合并 删除 提取等 更复杂的任务如 将 PDF 转换成 图像 下面通过几个简单的例子和一份代码 帮助大家解决上面的需求 操作非常简单 在文末我会提供一份源码和一个神奇的 PDF 处理网
  • 使用myheritage实现静态照片变成视频

    网址 https www myheritage com 首先 注册 可以使用google账号 其次 上传照片 接下来 生成动画 最后 下载视频
  • document.documentElement.scrollTop(获取滚动条位置)

    document documentElement scrollTop 收集关于scrollTop信息 要获取当前页面的滚动条纵坐标位置 用 document documentElement scrollTop 而不是 document bo
  • 百度tangram框架开发工具小结

    根据在开发流程中出现的顺序 对每个工具简要介绍如下 firebug 几乎所有写html css js代码的人都熟悉的工具 tangram开发调试中用到 官方站点 http getfirebug com closure linter gjsl
  • 大话西游灯谜答案

  • zxing二维码的生成与解码(C#)(附例子)

    二维码的生成 using com google zxing qrcode using com google zxing using com google zxing common using ByteMatrix com google zx
  • ASP.NET系统用户权限设计与实现

    引言 电子商务系统对安全问题有较高的要求 传统的访问控制方法DAC Discretionary Access Control 自主访问控制模型 MAC Mandatory Access Control 强制访问控制模型 难以满足复杂的企业环
  • Python 绝对简明手册

    原文 简述 1 阅读须知 文中使用 gt gt gt 作为会命令行中的输出信息的前缀 对于不清楚用用途的函数可以在解释器下面输入 help 函数名 来获取相关信息 另外 自带的文档和google也是不可少的 2 基本语法 2 1 if el
  • word2vector学习笔记(一)

    word2vector学习笔记 一 最近研究了一下google的开源项目word2vector http code google com p word2vec 其实这玩意算是神经网络在文本挖掘的一项成功应用 本文是看了论文 Distribu
  • 前置++和后置++的区别

    今天在阅读 google c 编程风格 的文档的时候 5 10 前置自增和自减 有一句话引起了我的注意 对于迭代器和其他模板对象使用前缀形式 i 的自增 自减运算符 理由是 前置自增 i 通常要比后置自增 i 效率更高 于是我查了查前置 和
  • 长尾理论(The Long Tail)与Google的成功

    根据wikipedia的解释 长尾 Long Tail 是2004年Chris Anderson在给连线杂志的文章中首次使用的词汇 用以描述某种经济模式如Amazon com或Netflix 长尾术语也普遍使用于统计学中 如 对财富分布或词
  • Google C++风格指南 阅读笔记

    这个Google C 风格指南出得太好了 有很多C 的问题 其实通过阅读这份文档就可以了 相信读完后 可以在简历上加上一句 具有良好的编码风格 哈哈 下面记录一下我的读书笔记吧 整份文档的中文版本我已经上传到了资源里面 1 头文件 1 1头
  • 隐藏Chrome浏览器新增标签页下方的快捷方式缩略图

    作为强迫症患者不喜欢搜索栏下方还有多余的东西 看着8个最近访问的快捷方式缩略图太不舒服了 在网上搜索了一堆方法 最有效的是替换一个PAK文件 但是过程有些繁琐 自己摸索后发现了一个简单的方法 在这记录一下以防自己忘记 查看设置中搜索引擎的地
  • 了解搜索引擎技术

    百度 Google搜索引擎核心技术是怎么实现的 搜索引擎 搜索引擎 search engine 是指根据一定的策略 运用特定的计算机程序搜集互联网上的信息 在对信息进行组织和处理后 并将处理后的信息显示给用户 是为用户提供检索服务的系统 全
  • 信息收集 (一)Google Hack & robots文件

    一 Google Hack 在渗透测试中 信息收集是尤为重要的一部分 甚至可以占到整个渗透的百分之六十至七十 可见掌握好信息收集的方法十分重要 那GoogleHacking作为常用且方便的信息收集搜索引擎工具 它是利用谷歌搜索强大 可以搜出
  • 以一个最简单的例子把OO的JavaScript说明白

    OO的JavaScript并不高深 麻烦就麻烦在google出来的国人介绍文章经常罗罗嗦嗦 而且之间的说法还各有不同 摆在一起就让人看了头大 这里重拾简单主义 以一个最简单的例子把OO Javascript说明白 1 一个颇为精简的例子 只
  • 太不可思议了,我的文章居然有人转载

    今天无意间逛Google 发现有人转载我的垃圾文章 简直不可思议 http www newbooks com cn info 50429 html 本来是写起耍的 算是整理加一点实际经验写成的 让我又高兴又惭愧 惭愧文章写的差 高兴我的文章
  • 众多Android 开源项目推荐,给力工作给力学习

    FBReaderJ FBReaderJ用于Android平台的电子书阅读器 它支持多种电子书籍格式包括 oeb ePub和fb2 此外还支持直接读取zip tar和gzip等压缩文档 项目地址 http www fbreader org F

随机推荐

  • android之 h5调用系统相机和相册并显示

    先上html界面的代码 放在assets里面就可以了 我也不太会html 所以随便写了点 span class hljs doctype lt doctype html gt span span class hljs tag lt span
  • 深坑之Webview,解决H5调用android相机拍照和录像

    最近在开发过程中遇到一个问题 主要是调用第三方的实名认证 需要拍照和录像 办过支付宝大宝卡和腾讯的大王卡的都知道这玩意 办卡的时候就需要进行实名认证 人脸识别 本来第三方平台 xxx流量公司 说的是直接用WebView加载这个H5界面就完事
  • rxjava2定时器每秒请求一次数据

    项目进行的过程中有个需求是在20秒内每秒请求一次数据 xff0c 请求成功的json中有个字段 xff0c 如果有这个字段代表请求成功 xff0c 如果没有则继续请求 xff0c 直到20秒结束 xff0c 20秒结束则失败 本来最开始采用
  • Flutter导航栏实现

    学了几天的flutter 似乎有点感觉了 今天来上手搞一个导航栏 实现类似android里面的ViewPager 43 Fragment的效果 二话不说直接上代码 import 39 package flutter material dar
  • SpringBoot 日志文件

    1 日志的作用2 日志怎么用3 自定义日志打印3 1 得到日志对象3 2 使用日志对象提供的方法打印日志3 3 日志格式说明 4 日志级别4 1 日志级别分类4 2 日志级别的配置 5 日志持久化6 更简单的实现自定义日志的打印6 1 准备
  • Flutter实现滑动头部折叠切换tab

    主要使用到NestedScrollView和SliverAppBar 先看效果 xff1a 代码如下 xff1a import 39 package flutter material dart 39 class ActPage extend
  • ubuntu apt-get 默认下载路径

    使用apt get install 命令时默认下载到 var cache apt archives路径下 xff0c sudo apt get clean命令可以删除该路径下的下载的deb包 例如仅下载ssh xff0c 不安装 xff1a
  • vscode 离线安装ssh

    首先打开官方插件地址 xff1a https marketplace visualstudio com VSCode 然后输入ssh 下载这两个插件 xff1a 安装这两个插件 xff1a 这样便在windows下安装成功了ssh 接下来需
  • windows BDA driver (abstract)

    AVStream is a Microsoft provided multimedia class driver that supports video only streaming and integrated audio video s
  • Ubuntu平台采用Qemu搭建ARM虚拟机环境

    1 Busybox编译 下载代码 xff1a 查看Busybox Source Control网站 xff0c 有代码控制说明 xff0c 我们采用git clone下载代码 xff1a BusyBox git clone git busy
  • 详细解读Python豆瓣电影Top250网页爬取(主要对re的运用&excel保存数据)//包括对库的简介

    python里面有很多操作都类似于c语言 xff0c 这里在爬取时主要需要注意用到的是for循环语句和各种库 个人认为python中主要还是对库的运用比较占大比例 xff08 这里的软件版本是PyCharm 2020 3 2 x64 xff
  • 在android中配置 slf4j + log4j 日志记录框架

    需求 xff1a 在项目开发中 xff0c 需要记录 操作日志 起初自己写了个简单的日志记录文本写入到文本的方法 xff0c 后来随着项目的膨胀 xff0c 需要考虑更多的操作 xff0c 开始考虑性能问题 实现 xff1a 考虑使用 sl
  • ZipInputStream解压远程文件报错,java.lang.IllegalArgumentException: MALFORMED[1]

    我遇到的问题是报的这个错java lang IllegalArgumentException MALFORMED 1 at java util zip ZipCoder toString ZipCoder java 65 不是 java l
  • OAuth2.0接百度平台进行授权

    百度开发文档 xff1a https openauth baidu com doc regdevelopers html 1 注册开发者账号并创建一个应用 2 创建应用后 xff0c 获取API Key和Secret Key 3 创建一个S
  • Spring 中最常用的 11 个扩展点

    1 自定义拦截器 spring mvc拦截器根spring拦截器相比 xff0c 它里面能够获取HttpServletRequest和HttpServletResponse等web对象实例 spring mvc拦截器的顶层接口是 xff1a
  • Lottie源码分析

    简介 我们使用Lottie的时候 xff0c 最关键的类就是LottieAnimationView 继承自ImageView 和LottieDrawable 继承自Drawable xff0c Lottie的描述文件最终会解析成一系列的La
  • 经典排序算法

    https juejin cn post 7198840786766102589
  • SpringBoot项目启动加载时排除某一个类

    在Application启动类上 xff0c 用这个注解就可以指定某个类不加载进容器 64 ComponentScan
  • Android中Okhttp,Volley,Retrofit网络框架优缺点及对比

    Okhttp xff1a Square 公司开源的 OkHttp 是一个专注于连接效率的 HTTP 客户端 OkHttp 提供了对 HTTP 2 和 SPDY 的支持 xff0c 并提供了连接池 xff0c GZIP 压缩和 HTTP 响应
  • Google身份验证服务端实现

    import org apache commons codec binary Base32 import org apache commons codec binary Base64 import javax crypto Mac impo