2011-06-21 13 views
32

मैं .NET-apps में Google Authenticator का उपयोग करने के तरीके पर एक ट्यूटोरियल ढूंढ रहा हूं। क्या यह अस्तित्व में है, और यदि हां, तो मुझे यह कहां मिल सकता है?क्या .NET ऐप्स में Google प्रमाणक को कार्यान्वित करने के तरीके पर कोई ट्यूटोरियल है?

मैं समझता हूं कि इसका उपयोग आपके स्वयं के ऐप्स में दो-कारक-प्रमाणीकरण जोड़ने के लिए किया जा सकता है।

उत्तर

9

कुछ शोध और परीक्षण के बाद मैंने अपनी खुद की "सबूत-ऑफ-अवधारणा" बनाई है कि आप एक क्यूआर-छवि कैसे उत्पन्न कर सकते हैं, इसे अपने फोन से स्कैन करें, और उसके बाद पिन-कोड को सत्यापित करें फोन सही है। यदि कोई भी शामिल होना चाहता है तो शायद इसे लाइब्रेरी के रूप में विकसित किया जा सकता है? कोड यहां पाया जा सकता:

https://github.com/esp0/googleAuthNet

+0

यदि यह है कि वे जाने के लिए रास्ता नहीं था देखते हैं, धन्यवाद होगा! –

2

मुझे एक ट्यूटोरियल नहीं मिला, लेकिन ऐसा लगता है कि एक पोर्ट लिखना इतना कठिन नहीं होगा। यह एक जावा अनुप्रयोग है, और मौजूदा मानकों (एचएमएसी SHA1) पर आधारित है।

गैर जीयूआई हिम्मत पर जानकारी के लिए इस पेज देखें:

और पोर्टिंग पर जानकारी के लिए इन पृष्ठों देखते हैं, और एक मौजूदा (अनौपचारिक) सिल्वरलाइट पोर्ट:

29

जबकि Google प्रमाणक के साथ प्रयोग करना, मैं इस सवाल भर में और विशेष रूप से कोड Espo के योगदान आया था। मैं व्यक्तिगत रूप से जावा से सी # के रूपांतरण से संतुष्ट नहीं था और इसलिए मैंने सोचा कि मैं अपना संस्करण साझा करूंगा। कोड को भारी प्रतिक्रिया देने के अलावा:

  • छोटे-एंडियन बाइट ऑर्डरिंग के लिए परिचय की गई जांच और आवश्यकतानुसार बड़े-एंडियन में परिवर्तित करें।
  • एचएमएसी कुंजी के लिए परिचय पैरामीटर। प्रारंभिक काम के लिए Espo करने के लिए धन्यवाद https://github.com/google/google-authenticator/wiki/Key-Uri-Format

    यदि आप चाहें उपयोग करने के लिए स्वतंत्र महसूस, और:

प्रावधान url स्वरूप के बारे में अधिक जानकारी के लिए, यह भी देखें।

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 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~"; 

      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 
} 
+0

मेरे कोड को बेहतर बनाने के लिए धन्यवाद। जैसा कि आपने देखा, यह बहुत सुंदर नहीं था, क्योंकि मैं सिर्फ पीओसी करने के लिए ज्यादा समय नहीं बिताना चाहता था। – Espo

+0

@ माइकल पेटिटो, क्या आपके पास गिटहब पर है? – devlord

+0

@lorddev, नहीं, मैंने इसे गिटहब पर नहीं रखा है। –

5

सवाल एक ट्यूटोरियल जो अन्य उत्तर मैं कवर नहीं लग रहा है के लिए कहा,

एक में पाया जा सकता:

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

ट्यूटोरियल रिक Bassham द्वारा लिखा गया था और इसमें जानकारी शामिल है:

"दो फैक्टर प्रमाणीकरण क्या है" "Google प्रमाणक क्या है" "यह कैसे काम करता है"

यह तो बताते हैं कि कैसे के लिए कोड लागू करने के लिए:

"काउंटर आधारित वन टाइम पासवर्ड जनरेशन" "समय आधारित वन टाइम पासवर्ड पीढ़ी"

और तहत दृश्य स्टूडियो 2010 का उपयोग कर एक पूर्ण ट्यूटोरियल देता है:

1

का उपयोग कर Google प्रमाणक आप निम्नलिखित

जरूरत गूगल दो फैक्टर प्रमाणीकरण जोड़ने के लिए "मैं इसे कैसे उपयोग करने के लिए डाल दिया है"

Google प्राप्त करने के लिए। प्रमाणीकरणकर्ता; यहां देखें 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); 

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 

आपको लगता है कि आप चाहते हैं किसी भी मूल्य के लिए SuperSecretKeyGoesHere बदलने के लिए, लेकिन यकीन है कि यह 10 से अधिक चरित्र अन्यथा मैनुअल प्रविष्टि महत्वपूर्ण यह है कि उत्पन्न होता है काम नहीं करेगी बना सकते हैं। अब आप पाठ बॉक्स और बटन के साथ उपयोगकर्ता इनपुट की जाँच कर सकते

क्लिक करें इस बिट उपयोगकर्ता प्रविष्टि को देखो और ठीक

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"; 
} 
संबंधित मुद्दे