zoukankan      html  css  js  c++  java
  • 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 = 30;
                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(1000);
                    Console.Clear();
                }
            }
        }
    }
    View Code

    认证器:

    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 = 30, 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(1970, 1, 1, 0, 0, 0, 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(1970, 1, 1, 0, 0, 0, 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 = 6)
            {
                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 - 1] & 0xf;
    
                int binary =
                    ((hash[offset] & 0x7f) << 24)
                    | ((hash[offset + 1] & 0xff) << 16)
                    | ((hash[offset + 2] & 0xff) << 8)
                    | (hash[offset + 3] & 0xff);
    
                int password = binary % (int)Math.Pow(10, digits); // 6 digits
    
                return password.ToString(new string('0', digits));
            }
        }
    }
    View Code

     

     

     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 * 5 / 8; 
                byte[] returnArray = new byte[byteCount];
    
                byte curByte = 0, bitsRemaining = 8;
                int mask = 0, arrayIndex = 0;
    
                foreach (char c in input)
                {
                    int cValue = CharToValue(c);
    
                    if (bitsRemaining > 5)
                    {
                        mask = cValue << (bitsRemaining - 5);
                        curByte = (byte)(curByte | mask);
                        bitsRemaining -= 5;
                    }
                    else
                    {
                        mask = cValue >> (5 - bitsRemaining);
                        curByte = (byte)(curByte | mask);
                        returnArray[arrayIndex++] = curByte;
                        curByte = (byte)(cValue << (3 + bitsRemaining));
                        bitsRemaining += 3;
                    }
                }
    
                if (arrayIndex != byteCount)
                {
                    returnArray[arrayIndex] = curByte;
                }
    
                return returnArray;
            }
    
            public static string ToString(byte[] input)
            {
                if (input == null || input.Length == 0)
                {
                    throw new ArgumentNullException("input");
                }
    
                int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
                char[] returnArray = new char[charCount];
    
                byte nextChar = 0, bitsRemaining = 5;
                int arrayIndex = 0;
    
                foreach (byte b in input)
                {
                    nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
                    returnArray[arrayIndex++] = ValueToChar(nextChar);
    
                    if (bitsRemaining < 4)
                    {
                        nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
                        returnArray[arrayIndex++] = ValueToChar(nextChar);
                        bitsRemaining += 5;
                    }
    
                    bitsRemaining -= 3;
                    nextChar = (byte)((b << bitsRemaining) & 31);
                }
    
                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 < 91 && value > 64)
                {
                    return value - 65;
                }
                if (value < 56 && value > 49)
                {
                    return value - 24;
                }
                if (value < 123 && value > 96)
                {
                    return value - 97;
                }
    
                throw new ArgumentException("Character is not a Base32 character.", "c");
            }
    
            private static char ValueToChar(byte b)
            {
                if (b < 26)
                {
                    return (char)(b + 65);
                }
    
                if (b < 32)
                {
                    return (char)(b + 24);
                }
    
                throw new ArgumentException("Byte is not a value Base32 value.", "b");
            }
        }
    }
    View Code

    关于二维码的内容:

     String format = "otpauth://totp/帐号?secret=密钥";
    生成二维码就可以了。

    有用的请点赞下 谢谢。
  • 相关阅读:
    呵呵,今天偶然看到了我最早期的商业网站作品
    轻量级的Ajax解决方案——DynAjax:直接在客户端调用C#类的方法
    RegexDesigner.NET 正则表达式开源工具
    Asp.net页面的生命周期之通俗理解
    我设计的公司网站主页 截图
    没想到裴勇俊留了一头长发。
    一个very好的Javascript ajax库,jQuery!
    JQuery资源收集
    收藏:悟透JavaScript
    VS2008 F5不能调试情况一例
  • 原文地址:https://www.cnblogs.com/zxs-onestar/p/11505297.html
Copyright © 2011-2022 走看看