我正在寻找有关如何在.NET应用程序中使用Google Authenticator的教程。这个教程存在吗?如果存在,我该在哪里找到它?
我了解这可以用于为自己的应用程序添加双因素认证。
我正在寻找有关如何在.NET应用程序中使用Google Authenticator的教程。这个教程存在吗?如果存在,我该在哪里找到它?
我了解这可以用于为自己的应用程序添加双因素认证。
有关配置URL格式的更多信息,请参见:https://github.com/google/google-authenticator/wiki/Key-Uri-Format
如果您喜欢,请随意使用,并感谢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
}
key
和identifier
参数的参数吗?听起来“标识符”是出现在Google Authenticator应用程序中代码旁边的名称。但我不确定如何创建密钥。 - Nick WilliamsSystem.Security.Cryptography
的 RandomNumberGenerator
生成每个用户帐户的唯一密钥。 - Michael Petitokey
字节数组的最大长度为10。 - Nick Williamsusing 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;
获取Google.Authenticator; 请查看此处 https://www.nuget.org/packages/GoogleAuthenticator
现在设置Google身份验证。
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
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";
}
System.Drawing
,在 Linux 上已知会有问题,并且将在 .NET 6 中被标记为“仅限 Windows”。https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only - Alex from Jitbithttp://www.codeproject.com/Articles/403355/Implementing-Two-Factor-Authentication-in-ASP-NET
这篇教程由Rick Bassham撰写,涵盖了以下信息:您可以运行这个简单的控制台应用程序来了解如何验证一次性令牌码。请注意,我们需要先从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!");
}
}
}
我没有找到教程,但是似乎编写一个端口并不那么困难。它是一个Java应用程序,并基于现有标准(HMAC SHA1)。
请参阅此页面了解非GUI核心的详细信息:
并查看这些页面以获取有关端口和现有(非官方)Silverlight端口的信息: