是否有关于如何在 .NET 应用程序中实现 Google Authenticator 的教程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6421950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 15:39:51  来源:igfitidea点击:

Is there a tutorial on how to implement Google Authenticator in .NET apps?

.netgoogle-authenticatortwo-factor-authentication

提问by Espo

I'm looking for a tutorial on how to use Google Authenticatorin .NET-apps. Does this exist, and if so, where can I find it?

我正在寻找有关如何在 .NET 应用程序中使用Google 身份验证器的教程。这是否存在,如果存在,我在哪里可以找到它?

I understand that this can be used to add two-factor-authentication to your own apps.

我知道这可用于向您自己的应用程序添加两因素身份验证。

采纳答案by Espo

After a bit of researching and testing I created my own "proof-of-concept" on how to you can generate a QR-image, scan it from your phone, and then verify that the pin-code on the phone is correct. Maybe this could be developed further as a library if anyone wants to join? The code can be found here:

经过一些研究和测试,我创建了自己的“概念验证”,了解如何生成 QR 图像,从手机扫描它,然后验证手机上的密码是否正确。如果有人想加入,也许这可以进一步发展为图书馆?代码可以在这里找到:

https://github.com/esp0/googleAuthNet

https://github.com/esp0/googleAuthNet

回答by Michael Petito

While playing around with Google Authenticator, I came across this question and in particular the code contributed by Espo. I personally wasn't satisfied with the conversion from Java to C# and so I thought I would share my version. Aside from heavily refactoring the code:

在使用 Google Authenticator 时,我遇到了这个问题,尤其是 Espo 贡献的代码。我个人对从 Java 到 C# 的转换并不满意,所以我想我会分享我的版本。除了大量重构代码:

  • Introduced check for little-endian byte ordering and convert to big-endian as necessary.
  • Introduced parameter for the HMAC key.
  • 引入了对 little-endian 字节顺序的检查,并根据需要转换为 big-endian。
  • HMAC 密钥的引入参数。

For more information on the provisioning url format, see also: https://github.com/google/google-authenticator/wiki/Key-Uri-Format

有关供应 url 格式的更多信息,另请参阅:https: //github.com/google/google-authenticator/wiki/Key-Uri-Format

Feel free to use if you like, and thanks to Espo for the initial work.

如果您愿意,请随意使用,并感谢 Espo 的初步工作。

using System;
using System.Globalization;
using System.Net;
using System.Security.Cryptography;
using System.Text;

public class GoogleAuthenticator
{
    const int IntervalLength = 30;
    const int PinLength = 6;
    static readonly int PinModulo = (int)Math.Pow(10, PinLength);
    static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    /// <summary>
    ///   Number of intervals that have elapsed.
    /// </summary>
    static long CurrentInterval
    {
        get
        {
            var ElapsedSeconds = (long)Math.Floor((DateTime.UtcNow - UnixEpoch).TotalSeconds);

            return ElapsedSeconds/IntervalLength;
        }
    }

    /// <summary>
    ///   Generates a QR code bitmap for provisioning.
    /// </summary>
    public byte[] GenerateProvisioningImage(string identifier, byte[] key, int width, int height)
    {
        var KeyString = Encoder.Base32Encode(key);
        var ProvisionUrl = Encoder.UrlEncode(string.Format("otpauth://totp/{0}?secret={1}&issuer=MyCompany", identifier, KeyString));

        var ChartUrl = string.Format("https://chart.apis.google.com/chart?cht=qr&chs={0}x{1}&chl={2}", width, height, ProvisionUrl);
        using (var Client = new WebClient())
        {
            return Client.DownloadData(ChartUrl);
        }
    }

    /// <summary>
    ///   Generates a pin for the given key.
    /// </summary>
    public string GeneratePin(byte[] key)
    {
        return GeneratePin(key, CurrentInterval);
    }

    /// <summary>
    ///   Generates a pin by hashing a key and counter.
    /// </summary>
    static string GeneratePin(byte[] key, long counter)
    {
        const int SizeOfInt32 = 4;

        var CounterBytes = BitConverter.GetBytes(counter);

        if (BitConverter.IsLittleEndian)
        {
            //spec requires bytes in big-endian order
            Array.Reverse(CounterBytes);
        }

        var Hash = new HMACSHA1(key).ComputeHash(CounterBytes);
        var Offset = Hash[Hash.Length - 1] & 0xF;

        var SelectedBytes = new byte[SizeOfInt32];
        Buffer.BlockCopy(Hash, Offset, SelectedBytes, 0, SizeOfInt32);

        if (BitConverter.IsLittleEndian)
        {
            //spec interprets bytes in big-endian order
            Array.Reverse(SelectedBytes);
        }

        var SelectedInteger = BitConverter.ToInt32(SelectedBytes, 0);

        //remove the most significant bit for interoperability per spec
        var TruncatedHash = SelectedInteger & 0x7FFFFFFF;

        //generate number of digits for given pin length
        var Pin = TruncatedHash%PinModulo;

        return Pin.ToString(CultureInfo.InvariantCulture).PadLeft(PinLength, '0');
    }

    #region Nested type: Encoder

    static class Encoder
    {
        /// <summary>
        ///   Url Encoding (with upper-case hexadecimal per OATH specification)
        /// </summary>
        public static string UrlEncode(string value)
        {
            const string UrlEncodeAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

            var Builder = new StringBuilder();

            for (var i = 0; i < value.Length; i++)
            {
                var Symbol = value[i];

                if (UrlEncodeAlphabet.IndexOf(Symbol) != -1)
                {
                    Builder.Append(Symbol);
                }
                else
                {
                    Builder.Append('%');
                    Builder.Append(((int)Symbol).ToString("X2"));
                }
            }

            return Builder.ToString();
        }

        /// <summary>
        ///   Base-32 Encoding
        /// </summary>
        public static string Base32Encode(byte[] data)
        {
            const int InByteSize = 8;
            const int OutByteSize = 5;
            const string Base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

            int i = 0, index = 0;
            var Builder = new StringBuilder((data.Length + 7)*InByteSize/OutByteSize);

            while (i < data.Length)
            {
                int CurrentByte = data[i];
                int Digit;

                //Is the current digit going to span a byte boundary?
                if (index > (InByteSize - OutByteSize))
                {
                    int NextByte;

                    if ((i + 1) < data.Length)
                    {
                        NextByte = data[i + 1];
                    }
                    else
                    {
                        NextByte = 0;
                    }

                    Digit = CurrentByte & (0xFF >> index);
                    index = (index + OutByteSize)%InByteSize;
                    Digit <<= index;
                    Digit |= NextByte >> (InByteSize - index);
                    i++;
                }
                else
                {
                    Digit = (CurrentByte >> (InByteSize - (index + OutByteSize))) & 0x1F;
                    index = (index + OutByteSize)%InByteSize;

                    if (index == 0)
                    {
                        i++;
                    }
                }

                Builder.Append(Base32Alphabet[Digit]);
            }

            return Builder.ToString();
        }
    }

    #endregion
}

回答by Reza Del

To Add Google Two Factor Authentication using Google Authenticator you need the following

要使用 Google Authenticator 添加 Google 双重身份验证,您需要以下内容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Cryptography;
using System.Text;
using System.Web.Profile;
using System.Web.Security;
using Google.Authenticator;

To get the Google.Authenticator; check here https://www.nuget.org/packages/GoogleAuthenticator

获取 Google.Authenticator; 在这里查看https://www.nuget.org/packages/GoogleAuthenticator

now setting up the Google authentication.

现在设置谷歌身份验证。

TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();
var setupInfo = tfa.GenerateSetupCode("Name of the app", "More info ABout the App", "SuperSecretKeyGoesHere", 300 , 300); //the width and height of the Qr Code in pixels

string qrCodeImageUrl = setupInfo.QrCodeSetupImageUrl; //  assigning the Qr code information + URL to string
string manualEntrySetupCode = setupInfo.ManualEntryKey; // show the Manual Entry Key for the users that don't have app or phone
Image1.ImageUrl = qrCodeImageUrl;// showing the qr code on the page "linking the string to image element"
Label1.Text = manualEntrySetupCode; // showing the manual Entry setup code for the users that can not use their phone

you can change the SuperSecretKeyGoesHere to any value that you want, but make sure it has more than 10 character otherwise the manual entry key that is generated will not work. Now you can check the user input with text box and button click

您可以将 SuperSecretKeyGoesHere 更改为您想要的任何值,但请确保它超过 10 个字符,否则生成的手动输入密钥将不起作用。现在您可以使用文本框和按钮单击检查用户输入

this bit will look at the user entry and see if its ok

此位将查看用户条目并查看是否正常

string user_enter=TextBox1.Text;
TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();
bool isCorrectPIN = tfa.ValidateTwoFactorPIN("SuperSecretKeyGoesHere", user_enter);
if (isCorrectPIN == true)
{
Label2.Text = "i am cool";

}
else
{

Label2.Text = "i am Fool";
}

回答by Ben Close

The question asked for a tutorial which the other answers I don't feel cover,

这个问题要求一个教程,我觉得其他答案没有涵盖,

one can be found at:

可以在以下位置找到:

http://www.codeproject.com/Articles/403355/Implementing-Two-Factor-Authentication-in-ASP-NET

http://www.codeproject.com/Articles/403355/Implementing-Two-Factor-Authentication-in-ASP-NET

The tutorial was written by Rick Bassham and covers information on:

本教程由 Rick Bassham 编写,涵盖以下信息:

"What is Two Factor Authentication" "What is Google Authenticator" "How does it work"

“什么是双重身份验证”“什么是 Google 身份验证器”“它是如何工作的”

It then explains how to implement code for:

然后解释了如何实现代码:

"Counter Based One Time Password Generation" "Time Based One Time Password Generation"

“基于计数器的一次性密码生成”“基于时间的一次性密码生成”

And gives a full tutorial using Visual Studio 2010 under:

并在下面提供了使用 Visual Studio 2010 的完整教程:

"How do I put it to use"

“我如何使用它”

回答by Minh Nguyen

You could run this simple Console App to understand how to verify the one time token code. Note that we need to install library Otp.Netfrom Nuget package first.

您可以运行这个简单的控制台应用程序来了解如何验证一次性令牌代码。请注意,我们需要先从Nuget 包安装库Otp.Net

static string secretKey = "JBSWY3DPEHPK3PXP"; //add this key to your Google Authenticator app  

private static void Main(string[] args)
{
        var bytes = Base32Encoding.ToBytes(secretKey);

        var totp = new Totp(bytes);

        while (true)
        {
            Console.Write("Enter your code from Google Authenticator app: ");
            string userCode = Console.ReadLine();

            //Generate one time token code
            string tokenInApp = totp.ComputeTotp();
            int remainingSeconds = totp.RemainingSeconds();

            if (userCode.Equals(tokenInApp)
                && remainingSeconds > 0)
            {
                Console.WriteLine("Success!");
            }
            else
            {
                Console.WriteLine("Failed. Try again!");
            }
        }
}

回答by Merlyn Morgan-Graham

I didn't find a tutorial, but it seems like writing a port wouldn't be so hard. It is a Java application, and is based off existing standards (HMAC SHA1).

我没有找到教程,但似乎编写端口不会那么难。它是一个 Java 应用程序,基于现有标准 (HMAC SHA1)。

See this page for details on the non-GUI guts:

有关非 GUI 内容的详细信息,请参阅此页面:

And see these pages for info on porting, and an existing (unofficial) Silverlight port:

并查看这些页面以获取有关移植和现有(非官方)Silverlight 移植的信息: