Aracılığıyla paylaş


ASP.NET Identity ile SMS ve e-posta kullanılan iki öğeli kimlik doğrulaması

Tarafından Hao Kung, Pranav Rastogi, Rick Anderson, Suhas Joshi

Bu öğreticide, SMS ve e-posta kullanarak İki öğeli kimlik doğrulamasını (2FA) nasıl ayarlayacağınız gösterilir.

Bu makale Rick Anderson (@RickAndMSFT), Pranav Rastogi (@rustd), Hao Kung ve Suhas Joshi tarafından yazılmıştır. NuGet örneği öncelikle Hao Kung tarafından yazılmıştır.

Bu konu aşağıdaki konuları kapsar:

Kimlik örneğini oluşturma

Bu bölümde, birlikte çalışacağımız bir örneği indirmek için NuGet kullanacaksınız. Web veya Visual Studio 2013 için Visual Studio Express 2013'i yükleyip çalıştırarak başlayın. Visual Studio 2013 Güncelleştirme 2 veya üzerini yükleyin.

Not

Uyarı: Bu öğreticiyi tamamlamak için Visual Studio 2013 Güncelleştirme 2'yi yüklemeniz gerekir.

  1. Yeni bir boş ASP.NET Web projesi oluşturun.

  2. Paket Yöneticisi Konsolu'nda aşağıdaki komutları girin:

    Install-Package SendGrid
    Install-Package -Prerelease Microsoft.AspNet.Identity.Samples

    Bu öğreticide, e-posta göndermek için SendGrid'i ve sms mesajları için Twilio veya ASPSMS'yi kullanacağız. Paket Identity.Samples , üzerinde çalışacağımız kodu yükler.

  3. Projeyi SSL kullanacak şekilde ayarlayın.

  4. İsteğe bağlı: SendGrid'i bağlayıp uygulamayı çalıştırıp bir e-posta hesabı kaydetmek için Email onay öğreticimdeki yönergeleri izleyin.

  5. Isteğe bağlı: Örnekten tanıtım e-posta bağlantısı onay kodunu kaldırın (ViewBag.LinkHesap denetleyicisindeki kod. ve ForgotPasswordConfirmation eylem yöntemlerine DisplayEmail ve razor görünümlerine bakın.

  6. Isteğe bağlı:ViewBag.Status Kodu Yönet ve Hesap denetleyicilerinden ve Views\Account\VerifyCode.cshtml ve Views\Manage\VerifyPhoneNumber.cshtml razor görünümlerinden kaldırın. Alternatif olarak, bu uygulamanın yerel olarak nasıl çalıştığını test etmek için e-posta ve SMS mesajları göndermek zorunda kalmadan ekranı koruyabilirsiniz ViewBag.Status .

Not

Uyarı: Bu örnekteki güvenlik ayarlarından herhangi birini değiştirirseniz, üretim uygulamalarının yapılan değişiklikleri açıkça çağıran bir güvenlik denetiminden geçmesi gerekir.

İki öğeli kimlik doğrulaması için SMS'i ayarlama

Bu öğreticide Twilio veya ASPSMS kullanma yönergeleri sağlanır, ancak başka herhangi bir SMS sağlayıcısını kullanabilirsiniz.

  1. SMS sağlayıcısı ile Kullanıcı Hesabı Oluşturma

    Twilio veya ASPSMS hesabı oluşturun.

  2. Ek paketleri yükleme veya hizmet başvuruları ekleme

    Twilio:
    Paket Yöneticisi Konsolu'nda aşağıdaki komutu girin:
    Install-Package Twilio

    ASPSMS:
    Aşağıdaki hizmet başvurusunun eklenmesi gerekir:

    Hizmet başvurusu ekleme penceresinin görüntüsü

    Adres:
    https://webservice.aspsms.com/aspsmsx2.asmx?WSDL

    Ad alanı:
    ASPSMSX2

  3. SMS Sağlayıcısı Kullanıcı kimlik bilgilerini anlama

    Twilio:
    Twilio hesabınızın Pano sekmesinde Hesap SID'sini ve Kimlik Doğrulama belirtecini kopyalayın.

    ASPSMS:
    Hesap ayarlarınızdan Userkey'e gidin ve kendi tanımladığınız Parola ile birlikte kopyalayın.

    Bu değerleri daha sonra ve SMSAccountPassword değişkenlerinde SMSAccountIdentification depolayacağız.

  4. SenderID / Kaynak Belirtme

    Twilio:
    Numaralar sekmesinden Twilio telefon numaranızı kopyalayın.

    ASPSMS:
    Başlatanların Kilidini Aç Menüsünde bir veya daha fazla Kaynakçının kilidini açın veya alfasayısal bir Kaynak (Tüm ağlar tarafından desteklenmez) seçin.

    Daha sonra bu değeri değişkeninde SMSAccountFrom depolayacağız.

  5. SMS sağlayıcısı kimlik bilgilerini uygulamaya aktarma

    Kimlik bilgilerini ve gönderen telefon numarasını uygulamanın kullanımına açın:

    public static class Keys
    {
       public static string SMSAccountIdentification = "My Idenfitication";
       public static string SMSAccountPassword = "My Password";
       public static string SMSAccountFrom = "+15555551234";
    }
    

    Uyarı

    Güvenlik - Hassas verileri hiçbir zaman kaynak kodunuzda depolamayın. Hesap ve kimlik bilgileri, örneği basit tutmak için yukarıdaki koda eklenir. Bkz. Jon Atten'in ASP.NET MVC: Özel Ayarları Kaynak Denetiminin Dışında Tut.

  6. SMS sağlayıcısına veri aktarımının uygulanması

    sınıfını SmsServiceApp_Start\IdentityConfig.cs dosyasında yapılandırın.

    Kullanılan SMS sağlayıcısına bağlı olarak Twilio veya ASPSMS bölümünü etkinleştirin:

    public class SmsService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
            // Twilio Begin
            // var Twilio = new TwilioRestClient(
            //   Keys.SMSAccountIdentification,
            //   Keys.SMSAccountPassword);
            // var result = Twilio.SendMessage(
            //   Keys.SMSAccountFrom,
            //   message.Destination, message.Body
            // );
            // Status is one of Queued, Sending, Sent, Failed or null if the number is not valid
            // Trace.TraceInformation(result.Status);
            // Twilio doesn't currently have an async API, so return success.
            // return Task.FromResult(0);
            // Twilio End
    
            // ASPSMS Begin 
            // var soapSms = new WebApplication1.ASPSMSX2.ASPSMSX2SoapClient("ASPSMSX2Soap");
            // soapSms.SendSimpleTextSMS(
            //   Keys.SMSAccountIdentification,
            //   Keys.SMSAccountPassword,
            //   message.Destination,
            //   Keys.SMSAccountFrom,
            //   message.Body);
            // soapSms.Close();
            // return Task.FromResult(0);
            // ASPSMS End
        }
    }
    
  7. Uygulamayı çalıştırın ve daha önce kaydettiğiniz hesapla oturum açın.

  8. Denetleyicide eylem yöntemini etkinleştiren Index Kullanıcı Kimliğinize Manage tıklayın.

    Uygulamada oturum açmış kayıtlı hesabın resmi

  9. Ekle’ye tıklayın.

    Telefon numarası ekleme bağlantısının resmi

  10. Birkaç saniye içinde doğrulama kodunu içeren bir kısa mesaj alırsınız. Girin ve Gönder'e basın.

    Telefon doğrulama kodu girişini gösteren görüntü

  11. Yönet görünümü, telefon numaranızın eklendiğini gösterir.

    Telefon numarasını gösteren görünümü yönet penceresinin resmi

Kodu inceleme

// GET: /Account/Index
public async Task<ActionResult> Index(ManageMessageId? message)
{
    ViewBag.StatusMessage =
        message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
        : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
        : message == ManageMessageId.SetTwoFactorSuccess ? "Your two factor provider has been set."
        : message == ManageMessageId.Error ? "An error has occurred."
        : message == ManageMessageId.AddPhoneSuccess ? "The phone number was added."
        : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
        : "";

    var model = new IndexViewModel
    {
        HasPassword = HasPassword(),
        PhoneNumber = await UserManager.GetPhoneNumberAsync(User.Identity.GetUserId()),
        TwoFactor = await UserManager.GetTwoFactorEnabledAsync(User.Identity.GetUserId()),
        Logins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()),
        BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(User.Identity.GetUserId())
    };
    return View(model);
}

Index Denetleyicideki Manage eylem yöntemi, durum iletisini önceki eyleminize göre ayarlar ve yerel parolanızı değiştirmek veya yerel hesap eklemek için bağlantılar sağlar. Index Yöntemi ayrıca bu tarayıcı için durumunuzu veya 2FA telefon numaranızı, harici oturum açma bilgilerinizi, 2FA'yı etkinleştirmiş ve 2FA yöntemini anımsayın (daha sonra açıklanmıştır) görüntüler. Başlık çubuğunda kullanıcı kimliğinize (e-posta) tıklanması ileti iletmez. Telefon Numarası : bağlantı geçişlerini Message=RemovePhoneSuccess sorgu dizesi olarak kaldır'a tıklayın.

https://localhost:44300/Manage?Message=RemovePhoneSuccess

[Telefon numarasının görüntüsü kaldırıldı]

Eylem yöntemi, AddPhoneNumber SMS mesajları alabilen bir telefon numarası girmek için bir iletişim kutusu görüntüler.

// GET: /Account/AddPhoneNumber
public ActionResult AddPhoneNumber()
{
   return View();
}

Telefon numarası ekle eylem iletişim kutusunun resmi

Doğrulama kodunu gönder düğmesine tıklanması, telefon numarasını HTTP POST AddPhoneNumber eylem yöntemine gönderir.

// POST: /Account/AddPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    // Generate the token 
    var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
                               User.Identity.GetUserId(), model.Number);
    if (UserManager.SmsService != null)
    {
        var message = new IdentityMessage
        {
            Destination = model.Number,
            Body = "Your security code is: " + code
        };
        // Send token
        await UserManager.SmsService.SendAsync(message);
    }
    return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}

yöntemi, GenerateChangePhoneNumberTokenAsync SMS iletisinde ayarlanacak güvenlik belirtecini oluşturur. SMS hizmeti yapılandırıldıysa, belirteç "Güvenlik kodunuz belirteçtir<>" dizesi olarak gönderilir. SmsService.SendAsync yöntemi zaman uyumsuz olarak çağrılır, ardından uygulama doğrulama kodunu girebileceğiniz eylem yöntemine VerifyPhoneNumber (aşağıdaki iletişim kutusunu görüntüler) yönlendirilir.

Telefon numarasını doğrulama eylem yöntemi iletişim kutusunun resmi

Kodu girip gönder'e tıkladıktan sonra kod HTTP POST VerifyPhoneNumber eylem yöntemine gönderilir.

// POST: /Account/VerifyPhoneNumber
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
    if (result.Succeeded)
    {
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user != null)
        {
            await SignInAsync(user, isPersistent: false);
        }
        return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
    }
    // If we got this far, something failed, redisplay form
    ModelState.AddModelError("", "Failed to verify phone");
    return View(model);
}

yöntemi, ChangePhoneNumberAsync gönderilen güvenlik kodunu denetler. Kod doğruysa, telefon numarası tablonun alanına AspNetUsers eklenirPhoneNumber. Bu çağrı başarılı SignInAsync olursa yöntemi çağrılır:

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
   // Clear the temporary cookies used for external and two factor sign ins
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, 
       DefaultAuthenticationTypes.TwoFactorCookie);
    AuthenticationManager.SignIn(new AuthenticationProperties
    {
       IsPersistent = isPersistent 
    }, 
       await user.GenerateUserIdentityAsync(UserManager));
}

parametresi, isPersistent kimlik doğrulama oturumunun birden çok istekte kalıcı olup olmadığını ayarlar.

Güvenlik profilinizi değiştirdiğinizde yeni bir güvenlik damgası oluşturulur ve AspNetUsers tablosunun alanında depolanırSecurityStamp. SecurityStamp Alanın güvenlik tanımlama bilgisinden farklı olduğunu unutmayın. Güvenlik tanımlama bilgisi tabloda (veya Kimlik Veritabanı'nda AspNetUsers başka bir yerde) depolanmaz. Güvenlik tanımlama bilgisi belirteci DPAPI kullanılarak otomatik olarak imzalanır ve ve süre sonu bilgileriyle UserId, SecurityStamp oluşturulur.

Tanımlama bilgisi ara yazılımı her istekte tanımlama bilgisini denetler. SecurityStampValidator sınıfındaki Startup yöntemi db'ye isabet eder ve ile belirtildiği gibi güvenlik damgasını validateIntervaldüzenli aralıklarla denetler. Güvenlik profilinizi değiştirmediğiniz sürece bu yalnızca 30 dakikada bir (örneğimizde) gerçekleşir. Veritabanına yapılan yolculukları en aza indirmek için 30 dakikalık aralık seçildi.

Güvenlik profilinde SignInAsync herhangi bir değişiklik yapıldığında yönteminin çağrılması gerekir. Güvenlik profili değiştiğinde veritabanı alanı güncelleştirir SecurityStamp ve yöntemini çağırmadan SignInAsyncyalnızca OWIN işlem hattının veritabanına bir sonraki isabetinde ( validateIntervalthe ) kadar oturumunuz açık kalır. Yöntemini hemen döndürülecek şekilde değiştirerek SignInAsync ve tanımlama bilgisi validateInterval özelliğini 30 dakikadan 5 saniyeye ayarlayarak bunu test edebilirsiniz:

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
   return;

   // Clear any partial cookies from external or two factor partial sign ins
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, 
       DefaultAuthenticationTypes.TwoFactorCookie);
    AuthenticationManager.SignIn(new AuthenticationProperties
    {
       IsPersistent = isPersistent 
    }, 
       await user.GenerateUserIdentityAsync(UserManager));
}
public void ConfigureAuth(IAppBuilder app) {
    // Configure the db context, user manager and role manager to use a single instance per request
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
    app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

    // Enable the application to use a cookie to store information for the signed in user
    // and to use a cookie to temporarily store information about a user logging in with a 
    // third party login provider
    // Configure the sign in cookie
    app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider {
            // Enables the application to validate the security stamp when the user logs in.
            // This is a security feature which is used when you change a password or add 
            // an external login to your account.  
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                //validateInterval: TimeSpan.FromMinutes(30),
                validateInterval: TimeSpan.FromSeconds(5),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        }
    });
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

Yukarıdaki kod değişiklikleriyle, güvenlik profilinizi değiştirebilirsiniz (örneğin, İki Faktör Etkin durumunu değiştirerek) ve yöntem başarısız olduğunda SecurityStampValidator.OnValidateIdentity 5 saniye içinde oturumunuz kapatılır. yöntemindeki SignInAsync dönüş satırını kaldırın, başka bir güvenlik profili değişikliği yapın ve oturumunuz kapatılmaz. SignInAsync yöntemi yeni bir güvenlik tanımlama bilgisi oluşturur.

İki öğeli kimlik doğrulamayı etkinleştirme

Örnek uygulamada, iki öğeli kimlik doğrulamasını (2FA) etkinleştirmek için kullanıcı arabirimini kullanmanız gerekir. 2FA'yı etkinleştirmek için gezinti çubuğunda kullanıcı kimliğinize (e-posta diğer adı) tıklayın. İki öğeli kimlik doğrulamasını etkinleştirmek için U I görüntüsü
2FA'yı etkinleştir'e tıklayın. İki öğeli kimlik doğrulama etkinleştirme bağlantısını gösteren kullanıcı I D'ye tıkladıktan sonraki görüntü Oturumu kapatın, sonra yeniden oturum açın. E-postayı etkinleştirdiyseniz ( önceki öğreticime bakın), 2FA için SMS veya e-postayı seçebilirsiniz. Doğrulama gönderme seçeneklerini gösteren görüntü Kodu girebileceğiniz Kodu Doğrula sayfası görüntülenir (SMS veya e-postadan). Kodu doğrulama sayfasının resmi Bu tarayıcıyı anımsa onay kutusuna tıkladığınızda, bu bilgisayar ve tarayıcıyla oturum açmak için 2FA kullanmanız gerekmeyecektir. 2FA'yı etkinleştirmek ve Bu tarayıcıyı anımsa seçeneğine tıklamak, bilgisayarınıza erişimi olmadığı sürece hesabınıza erişmeye çalışan kötü amaçlı kullanıcılara karşı güçlü 2FA koruması sağlar. Bunu düzenli olarak kullandığınız herhangi bir özel makinede yapabilirsiniz. Bu tarayıcıyı anımsa'yı ayarlayarak, düzenli olarak kullanmadığınız bilgisayarlardan 2FA'nın ek güvenliğini elde edersiniz ve kendi bilgisayarlarınızda 2FA'dan geçmek zorunda kalmadan kolaylık elde edersiniz.

İki öğeli kimlik doğrulama sağlayıcısını kaydetme

Yeni bir MVC projesi oluşturduğunuzda , IdentityConfig.cs dosyası bir İki öğeli kimlik doğrulama sağlayıcısını kaydetmek için aşağıdaki kodu içerir:

public static ApplicationUserManager Create(
   IdentityFactoryOptions<ApplicationUserManager> options, 
   IOwinContext context) 
{
    var manager = new ApplicationUserManager(
       new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
    // Configure validation logic for usernames
    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
    {
        AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = true
    };
    // Configure validation logic for passwords
    manager.PasswordValidator = new PasswordValidator
    {
        RequiredLength = 6,
        RequireNonLetterOrDigit = true,
        RequireDigit = true,
        RequireLowercase = true,
        RequireUppercase = true,
    };
    // Register two factor authentication providers. This application uses Phone and Emails as a 
    // step of receiving a code for verifying the user
    // You can write your own provider and plug it in here.
    manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
    {
        MessageFormat = "Your security code is: {0}"
    });
    manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
    {
        Subject = "Security Code",
        BodyFormat = "Your security code is: {0}"
    });
    manager.EmailService = new EmailService();
    manager.SmsService = new SmsService();

    var dataProtectionProvider = options.DataProtectionProvider;
    if (dataProtectionProvider != null)
    {
        manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>
           (dataProtectionProvider.Create("ASP.NET Identity"));
    }
    return manager;
}

2FA için telefon numarası ekleme

Denetleyicideki AddPhoneNumberManage eylem yöntemi bir güvenlik belirteci oluşturur ve bunu sağladığınız telefon numarasına gönderir.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
    // Generate the token and send it
    var code = await UserManager.GenerateChangePhoneNumberTokenAsync(
       User.Identity.GetUserId(), model.Number);
    if (UserManager.SmsService != null)
    {
        var message = new IdentityMessage
        {
            Destination = model.Number,
            Body = "Your security code is: " + code
        };
        await UserManager.SmsService.SendAsync(message);
    }
    return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
}

Belirteci gönderdikten sonra eylem yöntemine VerifyPhoneNumber yönlendirilir ve burada 2FA için SMS kaydetmek için kodu girebilirsiniz. Telefon numarasını doğrulayana kadar SMS 2FA kullanılmaz.

2FA'yi etkinleştirme

Eylem EnableTFA yöntemi 2FA'yi etkinleştirir:

// POST: /Manage/EnableTFA
[HttpPost]
public async Task<ActionResult> EnableTFA()
{
    await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
    var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
    if (user != null)
    {
        await SignInAsync(user, isPersistent: false);
    }
    return RedirectToAction("Index", "Manage");
}

2FA'yı SignInAsync etkinleştirme güvenlik profilinde yapılan bir değişiklik olduğundan çağrılmalıdır. 2FA etkinleştirildiğinde, kullanıcının kaydettiği 2FA yaklaşımlarını (örnekte SMS ve e-posta) kullanarak oturum açmak için 2FA kullanması gerekir.

QR kod oluşturucuları gibi daha fazla 2FA sağlayıcısı ekleyebilir veya kendi sağlayıcınızı yazabilirsiniz.

Not

2FA kodları Zamana Dayalı Tek Seferlik Parola Algoritması kullanılarak oluşturulur ve kodlar altı dakika boyunca geçerlidir. Kodu girmeniz altı dakikadan uzun sürerse Geçersiz kod hata iletisi alırsınız.

Sosyal ve yerel oturum açma hesaplarını birleştirme

E-posta bağlantınıza tıklayarak yerel ve sosyal hesapları birleştirebilirsiniz. Aşağıdaki "RickAndMSFT@gmail.com" dizisinde ilk olarak yerel oturum açma olarak oluşturulur, ancak hesabı önce sosyal oturum açma günlüğü olarak oluşturabilir, ardından yerel oturum açma bilgisi ekleyebilirsiniz.

E-posta bağlantısını seçme resmi

Yönet bağlantısına tıklayın. Bu hesapla ilişkili 0 harici (sosyal oturum açma) not edin.

Sonraki sayfayı görüntüleyen ve yönet'i seçen resim

Başka bir oturum açma hizmetinin bağlantısına tıklayın ve uygulama isteklerini kabul edin. İki hesap birleştirildi, her iki hesapla da oturum açabileceksiniz. Kimlik doğrulama hizmetindeki sosyal günlüklerinin kapalı olması veya daha çok sosyal hesaplarına erişimin kaybedilmiş olması durumunda kullanıcılarınızın yerel hesaplar eklemesini isteyebilirsiniz.

Aşağıdaki görüntüde, Tom bir sosyal oturum açma işlemidir ( Dış Oturum Açma bilgileri: 1 sayfada gösterilmiştir).

Dış oturum açma bilgilerini ve parola seçme konumunu gösteren resim

Parola seç'e tıklanması, aynı hesapla ilişkili yerel bir oturum açma eklemenize olanak tanır.

Parola seçme sayfasının resmi

Deneme yanılma saldırılarından hesap kilitlenmesi

Kullanıcı kilitlemeyi etkinleştirerek uygulamanızdaki hesapları sözlük saldırılarına karşı koruyabilirsiniz. yönteminde ApplicationUserManager Create aşağıdaki kod kilitlemeyi yapılandırıyor:

// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;

Yukarıdaki kod yalnızca iki faktörlü kimlik doğrulaması için kilitlemeyi etkinleştirir. Hesap denetleyicisinin yönteminde Login true olarak değiştirerek shouldLockout oturum açma işlemleri için kilitlemeyi etkinleştirebilirsiniz ancak hesabı DOS oturum açma saldırılarına açık hale getirdiğinden oturum açma işlemleri için kilitlemeyi etkinleştirmemenizi öneririz. Örnek kodda, yönteminde ApplicationDbInitializer Seed oluşturulan yönetici hesabı için kilitleme devre dışı bırakılır:

public static void InitializeIdentityForEF(ApplicationDbContext db)
{
    var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
    var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
    const string name = "admin@example.com";
    const string roleName = "Admin";

    //Create Role Admin if it does not exist
    var role = roleManager.FindByName(roleName);
    if (role == null)
    {
        role = new IdentityRole(roleName);
        var roleresult = roleManager.Create(role);
    }

    var user = userManager.FindByName(name);
    if (user == null)
    {
        user = new ApplicationUser { UserName = name, Email = name };
        var result = userManager.Create(user, GetSecurePassword());
        result = userManager.SetLockoutEnabled(user.Id, false);
    }

    // Add user admin to Role Admin if not already added
    var rolesForUser = userManager.GetRoles(user.Id);
    if (!rolesForUser.Contains(role.Name))
    {
        var result = userManager.AddToRole(user.Id, role.Name);
    }
}

Kullanıcının doğrulanmış bir e-posta hesabına sahip olmasını gerektirme

Aşağıdaki kod, kullanıcının oturum açabilmesi için doğrulanmış bir e-posta hesabına sahip olmasını gerektirir:

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

   // Require the user to have a confirmed email before they can log on.
    var user = await UserManager.FindByNameAsync(model.Email);
    if (user != null)
    {
       if (!await UserManager.IsEmailConfirmedAsync(user.Id))
       {
          ViewBag.errorMessage = "You must have a confirmed email to log on.";
          return View("Error");
       }         
    }
    // This doen't count login failures towards lockout only two factor authentication
    // To enable password failures to trigger lockout, change to shouldLockout: true
    var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, 
       model.RememberMe, shouldLockout: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}

SignInManager 2FA gereksinimini nasıl denetler?

2FA'nın etkinleştirilip etkinleştirilmediğini görmek için hem yerel oturum açma hem de sosyal oturum açma denetimi. 2FA etkinleştirilirse, SignInManager oturum açma yöntemi döndürür SignInStatus.RequiresVerificationve kullanıcı eylem yöntemine SendCode yönlendirilir ve burada günlüğü sırayla tamamlamak için kodu girmesi gerekir. Kullanıcının yerel kullanıcı tanımlama bilgisinde RememberMe ayarlanmışsa, SignInManager işlevi döndürülecek SignInStatus.Success ve 2FA üzerinden geçmesi gerekmeyecektir.

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

   // Require the user to have a confirmed email before they can log on.
    var user = await UserManager.FindByNameAsync(model.Email);
    if (user != null)
    {
       if (!await UserManager.IsEmailConfirmedAsync(user.Id))
       {
          ViewBag.errorMessage = "You must have a confirmed email to log on.";
          return View("Error");
       }         
    }
    // This doen't count login failures towards lockout only two factor authentication
    // To enable password failures to trigger lockout, change to shouldLockout: true
    var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, 
       model.RememberMe, shouldLockout: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
    {
        return RedirectToAction("Login");
    }

    // Sign in the user with this external login provider if the user already has a login
    var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
        case SignInStatus.Failure:
        default:
            // If the user does not have an account, then prompt the user to create an account
            ViewBag.ReturnUrl = returnUrl;
            ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
            return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
    }
}

Aşağıdaki kod eylem SendCode yöntemini gösterir. Kullanıcı için etkinleştirilmiş tüm 2FA yöntemleriyle bir SelectListItem oluşturulur. SelectListItem, kullanıcının 2FA yaklaşımını (genellikle e-posta ve SMS) seçmesini sağlayan DropDownListFor yardımcısına geçirilir.

public async Task<ActionResult> SendCode(string returnUrl)
{
    var userId = await SignInManager.GetVerifiedUserIdAsync();
    if (userId == null)
    {
        return View("Error");
    }
    var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId);
    var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
    return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl });
}

Kullanıcı 2FA yaklaşımını HTTP POST SendCode gönderdikten sonra eylem yöntemi çağrılır, SignInManager 2FA kodunu gönderir ve kullanıcı, oturum açma işlemini tamamlamak için VerifyCode kodu girebileceği eylem yöntemine yönlendirilir.

//
// POST: /Account/SendCode
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SendCode(SendCodeViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View();
    }

    // Generate the token and send it
    if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
    {
        return View("Error");
    }
    return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl });
}

2FA Kilitleme

Oturum açma parolası denemesi hatalarında hesap kilitleme ayarlayabilirsiniz, ancak bu yaklaşım oturum açma bilgilerinizi DOS kilitlemelerine duyarlı hale getirir. Hesap kilitlemeyi yalnızca 2FA ile kullanmanızı öneririz. ApplicationUserManager oluşturulduğunda, örnek kod 2FA kilitlemesini ve MaxFailedAccessAttemptsBeforeLockout beş olarak ayarlar. Bir kullanıcı oturum açtığında (yerel hesap veya sosyal hesap aracılığıyla), 2FA'daki başarısız girişimlerin her biri depolanır ve maksimum denemeye ulaşılırsa, kullanıcı beş dakika boyunca kilitlenir (kilitleme süresini ile DefaultAccountLockoutTimeSpanayarlayabilirsiniz).

Ek Kaynaklar