日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

c# 使用谷歌身份验证GoogleAuthenticator的示例

發布時間:2023/12/16 C# 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c# 使用谷歌身份验证GoogleAuthenticator的示例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

此功能相當于給系統加了個令牌,只有輸入對的一組數字才可以驗證成功。類似于QQ令牌一樣。

一丶創建最核心的一個類GoogleAuthenticator
此類包含了生成密鑰,驗證,將綁定密鑰轉為二維碼。

public class GoogleAuthenticator{private readonly static DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);private TimeSpan DefaultClockDriftTolerance { get; set; }public GoogleAuthenticator(){DefaultClockDriftTolerance = TimeSpan.FromMinutes(5);}/// <summary>/// Generate a setup code for a Google Authenticator user to scan/// </summary>/// <param name="issuer">Issuer ID (the name of the system, i.e. 'MyApp'), can be omitted but not recommended https://github.com/google/google-authenticator/wiki/Key-Uri-Format </param>/// <param name="accountTitleNoSpaces">Account Title (no spaces)</param>/// <param name="accountSecretKey">Account Secret Key</param>/// <param name="QRPixelsPerModule">Number of pixels per QR Module (2 pixels give ~ 100x100px QRCode)</param>/// <returns>SetupCode object</returns>public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey, int QRPixelsPerModule){byte[] key = Encoding.UTF8.GetBytes(accountSecretKey);return GenerateSetupCode(issuer, accountTitleNoSpaces, key, QRPixelsPerModule);}/// <summary>/// Generate a setup code for a Google Authenticator user to scan/// </summary>/// <param name="issuer">Issuer ID (the name of the system, i.e. 'MyApp'), can be omitted but not recommended https://github.com/google/google-authenticator/wiki/Key-Uri-Format </param>/// <param name="accountTitleNoSpaces">Account Title (no spaces)</param>/// <param name="accountSecretKey">Account Secret Key as byte[]</param>/// <param name="QRPixelsPerModule">Number of pixels per QR Module (2 = ~120x120px QRCode)</param>/// <returns>SetupCode object</returns>public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, byte[] accountSecretKey, int QRPixelsPerModule){if (accountTitleNoSpaces == null) { throw new NullReferenceException("Account Title is null"); }accountTitleNoSpaces = RemoveWhitespace(accountTitleNoSpaces);string encodedSecretKey = Base32Encoding.ToString(accountSecretKey);string provisionUrl = null;provisionUrl = String.Format("otpauth://totp/{2}:{0}?secret={1}&issuer={2}", accountTitleNoSpaces, encodedSecretKey.Replace("=",""), UrlEncode(issuer));using (QRCodeGenerator qrGenerator = new QRCodeGenerator())using (QRCodeData qrCodeData = qrGenerator.CreateQrCode(provisionUrl, QRCodeGenerator.ECCLevel.M))using (QRCode qrCode = new QRCode(qrCodeData))using (Bitmap qrCodeImage = qrCode.GetGraphic(QRPixelsPerModule))using (MemoryStream ms = new MemoryStream()){qrCodeImage.Save(ms, System.Drawing.Imaging.ImageFormat.Png);return new SetupCode(accountTitleNoSpaces, encodedSecretKey, String.Format("data:image/png;base64,{0}", Convert.ToBase64String(ms.ToArray())));}}private static string RemoveWhitespace(string str){return new string(str.Where(c => !Char.IsWhiteSpace(c)).ToArray());}private string UrlEncode(string value){StringBuilder result = new StringBuilder();string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";foreach (char symbol in value){if (validChars.IndexOf(symbol) != -1){result.Append(symbol);}else{result.Append('%' + String.Format("{0:X2}", (int)symbol));}}return result.ToString().Replace(" ", "%20");}public string GeneratePINAtInterval(string accountSecretKey, long counter, int digits = 6){return GenerateHashedCode(accountSecretKey, counter, digits);}internal string GenerateHashedCode(string secret, long iterationNumber, int digits = 6){byte[] key = Encoding.UTF8.GetBytes(secret);return GenerateHashedCode(key, iterationNumber, digits);}internal string GenerateHashedCode(byte[] key, long iterationNumber, int digits = 6){byte[] counter = BitConverter.GetBytes(iterationNumber);if (BitConverter.IsLittleEndian){Array.Reverse(counter);}HMACSHA1 hmac = new HMACSHA1(key);byte[] hash = hmac.ComputeHash(counter);int offset = hash[hash.Length - 1] & 0xf;// Convert the 4 bytes into an integer, ignoring the sign.int binary =((hash[offset] & 0x7f) << 24)| (hash[offset + 1] << 16)| (hash[offset + 2] << 8)| (hash[offset + 3]);int password = binary % (int)Math.Pow(10, digits);return password.ToString(new string('0', digits));}private long GetCurrentCounter(){return GetCurrentCounter(DateTime.UtcNow, _epoch, 30);}private long GetCurrentCounter(DateTime now, DateTime epoch, int timeStep){return (long)(now - epoch).TotalSeconds / timeStep;}public bool ValidateTwoFactorPIN(string accountSecretKey, string twoFactorCodeFromClient){return ValidateTwoFactorPIN(accountSecretKey, twoFactorCodeFromClient, DefaultClockDriftTolerance);}public bool ValidateTwoFactorPIN(string accountSecretKey, string twoFactorCodeFromClient, TimeSpan timeTolerance){var codes = GetCurrentPINs(accountSecretKey, timeTolerance);return codes.Any(c => c == twoFactorCodeFromClient);}public string[] GetCurrentPINs(string accountSecretKey, TimeSpan timeTolerance){List<string> codes = new List<string>();long iterationCounter = GetCurrentCounter();int iterationOffset = 0;if (timeTolerance.TotalSeconds > 30){iterationOffset = Convert.ToInt32(timeTolerance.TotalSeconds / 30.00);}long iterationStart = iterationCounter - iterationOffset;long iterationEnd = iterationCounter + iterationOffset;for (long counter = iterationStart; counter <= iterationEnd; counter++){codes.Add(GeneratePINAtInterval(accountSecretKey, counter));}return codes.ToArray();}}

其中GenerateSetupCode 這個方法是用于把綁定的密鑰直接轉成二維碼圖片,然后再轉成base64圖片 輸出再頁面上,這樣在APP上直接用掃一掃即可綁定。

二丶由于生成的密鑰不可以直接使用,需要進行Base32進行編碼。下面是Base32Encoding類

public class Base32Encoding{/// <summary>/// Base32 encoded string to byte[]/// </summary>/// <param name="input">Base32 encoded string</param>/// <returns>byte[]</returns>public static byte[] ToBytes(string input){if (string.IsNullOrEmpty(input)){throw new ArgumentNullException("input");}input = input.TrimEnd('='); //remove padding charactersint byteCount = input.Length * 5 / 8; //this must be TRUNCATEDbyte[] 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 we didn't end with a full byteif (arrayIndex != byteCount){returnArray[arrayIndex] = curByte;}return returnArray;}/// <summary>/// byte[] to Base32 string, if starting from an ordinary string use Encoding.UTF8.GetBytes() to convert it to a byte[]/// </summary>/// <param name="input">byte[] of data to be Base32 encoded</param>/// <returns>Base32 String</returns>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 we didn't end with a full charif (arrayIndex != charCount){returnArray[arrayIndex++] = ValueToChar(nextChar);while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding}return new string(returnArray);}private static int CharToValue(char c){int value = (int)c;//65-90 == uppercase lettersif (value < 91 && value > 64){return value - 65;}//50-55 == numbers 2-7if (value < 56 && value > 49){return value - 24;}//97-122 == lowercase lettersif (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");}} 三丶主程序里面直接調用方法 1 2 3 4 5 private SetupCode Google(string key, string Guids) {GoogleAuthenticator gat = new GoogleAuthenticator();return gat.GenerateSetupCode("Supported Giving", key, Guids, 5); } //key系統的賬號,Guid是進行加密的字符串,要求唯一,不然密鑰會重復,所以這里使用Guid. 2為二維碼的大小約120x120px。

SetupCode結果類為

public class SetupCode{public string Account { get; internal set; }public string AccountSecretKey { get; internal set; }public string ManualEntryKey { get; internal set; }/// <summary>/// Base64-encoded PNG image/// </summary>public string QrCodeSetupImageUrl { get; internal set; } }

ManualEntryKey 是手機綁定的密鑰。如果想手動輸入密鑰綁定就使用此字符串。
QrCodeSetupImageUrl 是將密鑰轉成的二維碼圖片

下載這個APP

進入APP后直接綁定,就會出現一下界面,即c#教程為綁定成功,然后我們就可以使用此令牌驗證了。

驗證方法

//Guids 之前生成密鑰的字符,此時當做唯一鍵來查詢,CheckCode為手機上動態的6位驗證嗎。校驗成功會返回true

GoogleAuthenticator gat = new GoogleAuthenticator(); var result = gat.ValidateTwoFactorPIN(parameters["Guids"].ToString(), parameters["CheckCode"].ToString()); if (result) { return "True"; } else { return "False"; } GoogleAuthenticator gat = new GoogleAuthenticator(); var result = gat.ValidateTwoFactorPIN(parameters["Guids"].ToString(), parameters["CheckCode"].ToString()); if (result) { return "True"; } else { return "False"; }

這樣功能就完成了。

以上就是c# 使用谷歌身份驗證GoogleAuthenticator的示例的詳細內容

總結

以上是生活随笔為你收集整理的c# 使用谷歌身份验证GoogleAuthenticator的示例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 野外做受又硬又粗又大视频√ | 饥渴丰满的少妇喷潮 | 福利片网址 | 毛片天堂| а√在线中文网新版地址在线 | 污视频免费在线 | 性猛交xxxx乱大交孕妇2十 | а√天堂www在线天堂小说 | 成人精品二区 | 中文人妻熟妇乱又伦精品 | 国产色综合视频 | 久久国产精品一区二区三区 | 一本色道综合久久欧美日韩精品 | 91精彩视频在线观看 | 4438五月天 | 水蜜桃色314在线观看 | 在线观看黄色av网站 | 亚洲区中文字幕 | 亚洲最新av | 亚洲AV无码精品黑人黑人 | 亚洲欧美在线一区二区 | av55 | 免费高清av在线看 | 久久这里只有精品23 | 在线观看网站 | 红桃视频隐藏入口 | 成人做爰www免费看视频网站 | 色版视频在线观看 | 日本xxxx裸体xxxx | 五月天黄色网址 | 国产午夜精品一区二区理论影院 | 久艹在线| 国产免费看黄 | 一区二区精品在线 | 麻豆视频网站 | 亚洲色图视频网站 | 天天舔天天操天天干 | 久久一二三四区 | 制服下的诱惑暮生 | v8888av| 国产精品av久久久久久无 | av最新地址 | 91在线无精精品白丝 | 91亚洲一线产区二线产区 | 欧美性猛交xxxx黑人 | av最新版天堂资源在线 | 99精品欧美一区二区蜜桃免费 | 亚洲麻豆精品 | 久久久久久欧美精品se一二三四 | 国产高潮国产高潮久久久 | 国产热 | 中国特级黄色大片 | 在线三级av| 国产嫩bbwbbw高潮 | 久久久久成人精品无码 | 男人操女人下面 | av在线成人 | 久久精品性爱视频 | 97精品人人妻人人 | 亚洲av首页在线 | 亚洲天堂精品视频 | 国模私拍av| 天天操天天操天天操 | 久久婷婷成人综合色 | 欧美性久久久 | 丁香婷婷视频 | 黄网在线观看免费 | av色图片| 成年人视频免费在线观看 | 美女高潮网站 | 天堂av2021| 国产亚洲欧美一区二区 | 日本十大三级艳星 | 真人毛片视频 | 亚洲一级在线观看 | 最近中文字幕mv | 日日夜夜网站 | 嫩草在线观看 | 国产伦精品一区二区三区照片91 | 亚洲午夜精品久久久 | www操操操 | 亚洲一区二区三区精品视频 | 最近中文字幕在线观看视频 | 亚洲欧美乱日韩乱国产 | 国产一级黄色 | 亚洲av永久无码精品放毛片 | 你懂的在线观看视频 | 先锋av资源| 淫片一级国产 | 夜夜添无码一区二区三区 | 亚洲高清在线 | 天天艹av | 尤物精品在线观看 | 91大神精品在线 | 99精品视频在线播放免费 | 校园春色亚洲色图 | 六月激情网 | 麻豆av在线看 | 国产亚洲精品精品国产亚洲综合 | av免费国产 |