c# 谷歌动态口令对接
https://www.cnblogs.com/easyauthor/p/11054869.html
Google 身份验证器与两步验证功能配合,可在您登录 Google 帐户时为您平添一重安全保障。
启用两步验证之后,当您登录帐户时,需要提供密码和此应用生成的验证码。配置完成后,无需网络连接或蜂窝连接即可获得验证码。
功能包括:
- 通过 QR 码自动设置
- 支持多帐户登录
- 支持基于时间和基于计数器生成验证码
要使用 Google 身份验证器,需要先为您的 Google 帐户启用两步验证。访问 http://www.google.com/2step 即可立即启用。
demo:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace GoogleAuthenticator
{
class Program
{
static void Main(string[] args)
{
long duration = ;
string key = "xeon997@foxmail.com";
GoogleAuthenticator authenticator = new GoogleAuthenticator(duration, key);
var mobileKey = authenticator.GetMobilePhoneKey(); while (true)
{ Console.WriteLine("手机端秘钥为:" + mobileKey); var code = authenticator.GenerateCode();
Console.WriteLine("动态验证码为:" + code); Console.WriteLine("刷新倒计时:" + authenticator.EXPIRE_SECONDS); System.Threading.Thread.Sleep();
Console.Clear();
}
}
}
}
认证器:
using GoogleAuthorization;
using System;
using System.Security.Cryptography;
using System.Text;
namespace GoogleAuthenticator
{
public class GoogleAuthenticator
{
/// <summary>
/// 初始化验证码生成规则
/// </summary>
/// <param name="key">秘钥(手机使用Base32码)</param>
/// <param name="duration">验证码间隔多久刷新一次(默认30秒和google同步)</param>
public GoogleAuthenticator(long duration = , string key = "xeon997@foxmail.com")
{
this.SERECT_KEY = key;
this.SERECT_KEY_MOBILE = Base32.ToString(Encoding.UTF8.GetBytes(key));
this.DURATION_TIME = duration;
} /// <summary>
/// 间隔时间
/// </summary>
private long DURATION_TIME { get; set; } /// <summary>
/// 迭代次数
/// </summary>
private long COUNTER
{
get
{
return (long)(DateTime.UtcNow - new DateTime(, , , , , , DateTimeKind.Utc)).TotalSeconds / DURATION_TIME;
}
} /// <summary>
/// 秘钥
/// </summary>
private string SERECT_KEY { get; set; } /// <summary>
/// 手机端输入的秘钥
/// </summary>
private string SERECT_KEY_MOBILE { get; set; } /// <summary>
/// 到期秒数
/// </summary>
public long EXPIRE_SECONDS
{
get
{
return (DURATION_TIME - (long)(DateTime.UtcNow - new DateTime(, , , , , , DateTimeKind.Utc)).TotalSeconds % DURATION_TIME);
}
} /// <summary>
/// 获取手机端秘钥
/// </summary>
/// <returns></returns>
public string GetMobilePhoneKey()
{
if (SERECT_KEY_MOBILE == null)
throw new ArgumentNullException("SERECT_KEY_MOBILE");
return SERECT_KEY_MOBILE;
} /// <summary>
/// 生成认证码
/// </summary>
/// <returns>返回验证码</returns>
public string GenerateCode()
{
return GenerateHashedCode(SERECT_KEY, COUNTER);
} /// <summary>
/// 按照次数生成哈希编码
/// </summary>
/// <param name="secret">秘钥</param>
/// <param name="iterationNumber">迭代次数</param>
/// <param name="digits">生成位数</param>
/// <returns>返回验证码</returns>
private string GenerateHashedCode(string secret, long iterationNumber, int digits = )
{
byte[] counter = BitConverter.GetBytes(iterationNumber); if (BitConverter.IsLittleEndian)
Array.Reverse(counter); byte[] key = Encoding.ASCII.GetBytes(secret); HMACSHA1 hmac = new HMACSHA1(key, true); byte[] hash = hmac.ComputeHash(counter); int offset = hash[hash.Length - ] & 0xf; int binary =
((hash[offset] & 0x7f) << )
| ((hash[offset + ] & 0xff) << )
| ((hash[offset + ] & 0xff) << )
| (hash[offset + ] & 0xff); int password = binary % (int)Math.Pow(, digits); // 6 digits return password.ToString(new string('', digits));
}
}
}
using System;
namespace GoogleAuthorization
{
public static class Base32
{
public static byte[] ToBytes(string input)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException("input");
} input = input.TrimEnd('=');
int byteCount = input.Length * / ;
byte[] returnArray = new byte[byteCount]; byte curByte = , bitsRemaining = ;
int mask = , arrayIndex = ; foreach (char c in input)
{
int cValue = CharToValue(c); if (bitsRemaining > )
{
mask = cValue << (bitsRemaining - );
curByte = (byte)(curByte | mask);
bitsRemaining -= ;
}
else
{
mask = cValue >> ( - bitsRemaining);
curByte = (byte)(curByte | mask);
returnArray[arrayIndex++] = curByte;
curByte = (byte)(cValue << ( + bitsRemaining));
bitsRemaining += ;
}
} if (arrayIndex != byteCount)
{
returnArray[arrayIndex] = curByte;
} return returnArray;
} public static string ToString(byte[] input)
{
if (input == null || input.Length == )
{
throw new ArgumentNullException("input");
} int charCount = (int)Math.Ceiling(input.Length / 5d) * ;
char[] returnArray = new char[charCount]; byte nextChar = , bitsRemaining = ;
int arrayIndex = ; foreach (byte b in input)
{
nextChar = (byte)(nextChar | (b >> ( - bitsRemaining)));
returnArray[arrayIndex++] = ValueToChar(nextChar); if (bitsRemaining < )
{
nextChar = (byte)((b >> ( - bitsRemaining)) & );
returnArray[arrayIndex++] = ValueToChar(nextChar);
bitsRemaining += ;
} bitsRemaining -= ;
nextChar = (byte)((b << bitsRemaining) & );
} if (arrayIndex != charCount)
{
returnArray[arrayIndex++] = ValueToChar(nextChar);
while (arrayIndex != charCount) returnArray[arrayIndex++] = '=';
} return new string(returnArray);
} private static int CharToValue(char c)
{
var value = (int)c; if (value < && value > )
{
return value - ;
}
if (value < && value > )
{
return value - ;
}
if (value < && value > )
{
return value - ;
} throw new ArgumentException("Character is not a Base32 character.", "c");
} private static char ValueToChar(byte b)
{
if (b < )
{
return (char)(b + );
} if (b < )
{
return (char)(b + );
} throw new ArgumentException("Byte is not a value Base32 value.", "b");
}
}
}
关于二维码的内容:
String format = "otpauth://totp/帐号?secret=密钥";
生成二维码就可以了。 有用的请点赞下 谢谢。
c# 谷歌动态口令对接的更多相关文章
- Google authenticator 谷歌身份验证,实现动态口令
Google authenticator 谷歌身份验证,实现动态口令 google authenticator php 服务端 使用PHP类 require_once '../PHPGangsta/G ...
- php集成动态口令认证
这篇文章主要为大家详细介绍了php集成动态口令认证,动态口令采用一次一密.用过密码作废的方式来提高安全性能,感兴趣的小伙伴们可以参考一下 大多数系统目前均使用的静态密码进行身份认证登录,但由于静态密码 ...
- poptest老李谈动态口令原理
poptest老李谈动态口令原理 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908 ...
- 使用OTP动态口令(每分钟变一次)进行登录认证
GIT地址:https://github.com/suyin58/otp-demo 在对外网开放的后台管理系统中,使用静态口令进行身份验证可能会存在如下问题: (1) 为了便于记忆,用户多选择有特征作 ...
- FreeRadius+GoogleAuthenticator实现linux动态口令认证
简介 在运维管理中,服务器的密码管理十分重要.服务器数量少的时候还好说,可以定时来改密码.一旦数量多了,再来改密码就不现实了. 前提 我们假定运维访问服务器是这样的: 创建一个普通用户用于登录服务器, ...
- [Python学习笔记-003] 使用PyOTP获取基于OTOP算法的动态口令
建立安全的VPN连接,不仅需要输入用户名和密码,还需要输入动态口令(token).作为一个懒人,我更喜欢什么手工输入都不需要,既不需要输入password,也不需要输入token.也就是说,只需一个命 ...
- YS动态口令系统接入流程
动态口令是保护用户账户的一种常见有效手段,即用户进行敏感操作(比如登录)时,需要用户提供此动态生成的口令做二次身份验证,假设用户的口令被盗,如果没有动态口令,也无法进行登录或进行敏感操作,保护了用户的 ...
- 使用google身份验证器实现动态口令验证
最近有用户反应我们现有的短信+邮件验证,不安全及短信条数限制和邮件收验证码比较慢的问题,希望我们 也能做一个类似银行动态口令的验证方式.经过对可行性的分析及慎重考虑,可以实现一个这样的功能. 怎么实现 ...
- asp.net mvc 使用 Autocomplete 实现类似百度,谷歌动态搜索条提示框。
Autocomplete是一个Jquery的控件,用法比较简单. 大家先看下效果: 当文本框中输入内容,自动检索数据库给出下拉框进行提示功能. 需要用此控件大家先到它的官方网站进行下载最新版本: ht ...
随机推荐
- LeetCode.989-数组形式的整数做加法(Add to Array-Form of Integer)
这是悦乐书的第371次更新,第399篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第233题(顺位题号是989).对于非负整数X,X的数组形式是从左到右顺序的数字数组.例 ...
- CountDownLatch与CyclicBarrier的对比
CountDownLatch: CountDownLatch通过计数器来实现,计数器表示线程的数量.每当一个线程执行结束后,计数器的值就会减1,并在await方法处阻塞.一旦计数器为0,所有阻塞的线程 ...
- 小程序图片预览 wx.previewImage
list: [ 'http://img5.imgtn.bdimg.com/it/u=3300305952,1328708913&fm=26&gp=0.jpg', 'http://i ...
- HDU 1024 Max Sum Plus Plus (动态规划、最大m子段和)
Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.
MySQL版本5.6.35 在一个长度为512字符的字段上创建unique key报错 CREATE DATABASE dpcs_metadata DEFAULT CHARACTER SET utf8 ...
- git 版本回退方法
ORIG_HEAD 某些操作,例如 merage / reset 会把 merge 之前的 HEAD 保存到 ORIG_HEAD 中,以便在 merge 之后可以使用 ORIG_HEAD 来回滚到合并 ...
- 关于echarts 重绘/图表切换/数据清空
容器id 为main var myChart=document.getElementById("main") myChart.removeAttribute("_echa ...
- html获取摄像头和相册
<input type="file" accept="video/*";capture="camcorder"> <inp ...
- Delphi 逻辑运算符与布尔表达式
- wordpress的固定链接问题
在安装完wordpress后,按照其方法在/etc/apache2/sites-available/000-default.conf文件中添加了下述代码中的加重部分: [...] ServerAdmi ...