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));
}
}
}
 Base32转码类

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# 谷歌动态口令对接的更多相关文章

  1. Google authenticator 谷歌身份验证,实现动态口令

    Google authenticator 谷歌身份验证,实现动态口令 google authenticator php 服务端 使用PHP类 require_once '../PHPGangsta/G ...

  2. php集成动态口令认证

    这篇文章主要为大家详细介绍了php集成动态口令认证,动态口令采用一次一密.用过密码作废的方式来提高安全性能,感兴趣的小伙伴们可以参考一下 大多数系统目前均使用的静态密码进行身份认证登录,但由于静态密码 ...

  3. poptest老李谈动态口令原理

    poptest老李谈动态口令原理     poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908 ...

  4. 使用OTP动态口令(每分钟变一次)进行登录认证

    GIT地址:https://github.com/suyin58/otp-demo 在对外网开放的后台管理系统中,使用静态口令进行身份验证可能会存在如下问题: (1) 为了便于记忆,用户多选择有特征作 ...

  5. FreeRadius+GoogleAuthenticator实现linux动态口令认证

    简介 在运维管理中,服务器的密码管理十分重要.服务器数量少的时候还好说,可以定时来改密码.一旦数量多了,再来改密码就不现实了. 前提 我们假定运维访问服务器是这样的: 创建一个普通用户用于登录服务器, ...

  6. [Python学习笔记-003] 使用PyOTP获取基于OTOP算法的动态口令

    建立安全的VPN连接,不仅需要输入用户名和密码,还需要输入动态口令(token).作为一个懒人,我更喜欢什么手工输入都不需要,既不需要输入password,也不需要输入token.也就是说,只需一个命 ...

  7. YS动态口令系统接入流程

    动态口令是保护用户账户的一种常见有效手段,即用户进行敏感操作(比如登录)时,需要用户提供此动态生成的口令做二次身份验证,假设用户的口令被盗,如果没有动态口令,也无法进行登录或进行敏感操作,保护了用户的 ...

  8. 使用google身份验证器实现动态口令验证

    最近有用户反应我们现有的短信+邮件验证,不安全及短信条数限制和邮件收验证码比较慢的问题,希望我们 也能做一个类似银行动态口令的验证方式.经过对可行性的分析及慎重考虑,可以实现一个这样的功能. 怎么实现 ...

  9. asp.net mvc 使用 Autocomplete 实现类似百度,谷歌动态搜索条提示框。

    Autocomplete是一个Jquery的控件,用法比较简单. 大家先看下效果: 当文本框中输入内容,自动检索数据库给出下拉框进行提示功能. 需要用此控件大家先到它的官方网站进行下载最新版本: ht ...

随机推荐

  1. April.Util更新之权限

    目录 前言 权限 中间层 小结 前言 在之前已经提到过,公用类库Util已经开源,目的一是为了简化开发的工作量,毕竟有些常规的功能类库重复率还是挺高的,二是为了一起探讨学习软件开发,用的人越多问题也就 ...

  2. leaflet的入门开发(一)

    2016年9月27日—1.0leaflet,最快的,最稳定和严谨的leaflet,终于出来了! leaflet是领先的开源JavaScript库为移动设备设计的互动地图.重33 KB的JS,所有映射大 ...

  3. 【LeetCode】123、买卖股票的最佳时机 III

    Best Time to Buy and Sell Stock III 题目等级:Hard 题目描述: Say you have an array for which the ith element ...

  4. Mysql 字段类型与查询类型不一致导致索引使用失败

    今天优化数据库的慢查询,有一条Sql让我百思不得其jie,就是他了. SELECT * FROM test WHERE user_id=1; 用explain 去分析一下 索引都有了,为什么还要扫描全 ...

  5. 第六周&Java实验报告四(类的继承)

    一.实验目的 (1)掌握类的继承 (2)变量的继承和覆盖,方法的继承,重载和覆盖的实现: 二.实验的内容 (1)根据下面的要求实现圆类Circle. 1.圆类Circle的成员变量:radius表示圆 ...

  6. System.InsufficientMemoryException:无法分配536870912字节的托管内存缓冲区。可用内存量可能不足

    一个病人住院太久,一次性打印护理表单超过3000条时报如标题所示的错误, 个人查阅分析应该可以从如下几方面入手: 一:查看程序客户端和服务端的配置文件相关属性是否限制了缓存最大值 (应该不是这个问题, ...

  7. layer弹出框的简易封装和使用

    1. 封装layer 下载layer绿色版和jquery引入页面 <!DOCTYPE html> <html lang="zh-CN"> . . . < ...

  8. javaweb:关于HttpServletRequest介绍 (转)

    出处:https://www.cnblogs.com/xdp-gacl/p/3798347.html 一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的 ...

  9. Codeforces6E_Exposition

    题意 给定一个序列,求有多少个最长连续子序列满足最大值减最小值之差不超过\(k\). 分析 跟序列最大值最小值有关的可以想到单调栈,先预处理出每个数作为最大值能延伸的区间,然后枚举每个数作为最大值. ...

  10. 用SQL存储过程生成唯一单据号

    用SQL存储过程生成唯一单据号     在一些系统中,经理要生成单据号,为了不使多台客户端生成的单据号重复,一般要在服务端生成这种流水号,本文是在数据库中生成流水号,并且可以生成多种类型的单据号(比如 ...