Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Asp.NET Core – Google & Microsoft Authenticator İle Two Factor Authentication

Merhaba,

Bir önceki Two Factor Authentication Nedir? başlıklı makalemizin akabinde artık Google & Microsoft Authenticator ile iki adımlı kimlik doğrulama yöntemi üzerine detaylı durabilir ve pratiksel açıdan tüm inşa sürecini irdeleyebiliriz.

Microsoft & Google Authenticator Nedir?

One Factor Authenticator Two Factor Authenticator
Asp.NET Core Identity - Two Factor Authentication Nedir? Asp.NET Core Identity - Two Factor Authentication Nedir.
Uygulama üzerinden yetkileri doğrultusunda faaliyetlerde bulunabilmek için kullanıcı tarafından gerçekleştirilen kimlik doğrulama sürecinde iki adımlı doğrulama yapabilmek için Microsoft, Google ile birlikte esasında birçok sağlayıcı tarafından geliştirilen uygulamadır.

Peki teoride nasıl çalışmaktadır?
Kullanıcıya özel olarak üretilen Shared Key isimli bir değer ile birlikte Zaman Damgası(Timestamp/Counter) ismi verilen bir değeri kullanarak (HTOP) Hmac – Based One Time Password(Zaman Bazlı Tek Kullanımlık Şifre) – RFC 6238 algoritması ile 30 saniyede bir yenilenen ve tek seferlik kullanım hakkı olan doğrulama kodunu üretmektëdir. Bu şekilde tüm authenticator uygulamaları aynı algoritmayı kullandıklarında dolayı kullanıcıya özel shared key değeri ile eşleşme sonrası aynı anda aynı kodu üretecektirler. Dolayısıyla Google yahut Microsoft hangisi olursa olsun farketmeksizin aynı işi görecektir…

Kodun üretilmesinde kullanılan Unix Time Stamp(Zaman Damgası) değerinin başlangıç tarihi 01.01.1970 00:00:00 olarak kabul edilmiştir ve o andan şu ana kadar geçen toplam saniyeyi ifade etmektedir. Authenticator uygulamasında counter doğrulama kodu üretildiği ana kadar olan toplam saniye değeri olan o anki timestamp değerini tutuyor ve bu kod 30 saniye geçene kadar aktifliğini sürdürebiliyor. Bir sonraki kodda aynı şekilde üretildiği andaki toplam saniye değerini countera veriyor ve aradaki farkı 30 saniye olana kadar aktifliğini koruyor. Vee bu süreç aynen bu döngüyle devam ediyor. Burada dikkat edilmesi gereken nokta şudur ki, bu toplam saniye verisini baz alırken ilgili telefon yahut tabletinde bu başlangıç tarihiyle birebir tutarlı olması gerekmekte ve bunun için Zaman Dilimi kavramının doğru şekilde ayarlanması gerekmektedir. Aksi taktirde zaman dilimi Afrika’da olan bir telefon ya da tabletten üretilen doğrulama kodu Kanada zaman dilimini benimsemiş bir uygulamayla unix time stamp olarak tutarlılık göstermeyeceğinden dolayı geçersiz olacaktır.

Şimdi gelin Google & Microsoft Authenticator stratejisinin pratik olarak nasıl uygulandığını örnek bir proje üzerinden inceleyelim. Bunun için temel Identity yapılanması One Factor Authentication kullanılacak şekilde hazır olan herhangi bir Asp.NET Core projesinde Two Factor Authentication yönteminin nasıl inşa edildiğini irdeleyelim…

Two Factor Authentication İnşası

Adım 1 – Kullanıcıya Özel Shared Key Üretimi
Adım 2 – QR Code İçin Path Hazırlama
Adım 3 – QR Code’un Basılması ve Temel Ayarların Yapımı
Adım 4 – Barkodun Okunması ve Doğrulanması
Adım 5 – İki Adımlı Doğrulamanın Onaylanması
Adım 6 – Login Esnasında İkinci Doğrulama Sayfasına Yönlendirme
Adım 7 – Test Etme

Adım 1 – Kullanıcıya Özel Shared Key Üretimi

İlk olarak uygulamamızda iki adımlı doğrulamayı gerçekleştirebilmek için kullanıcıya özel Shared Key üretmemiz gerekmektedir. Bunun için ‘AuthenticatorService’ ismini verdiğim bir servis oluşturarak içeriğini aşağıdaki gibi geliştiriyorum.

    public class AuthenticatorService
    {
        UserManager<AppUser> _userManager;
        public AuthenticatorService(UserManager<AppUser> userManager)
        {
            _userManager = userManager;
        }
        public async Task<string> GenerateSharedKey(AppUser user)
        {
            string sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);
            if (string.IsNullOrEmpty(sharedKey))
            {
                IdentityResult result = await _userManager.ResetAuthenticatorKeyAsync(user);
                if (result.Succeeded)
                    sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);
            }
            return sharedKey;
        }
    }

Burada 10. satırda parametreden gelen kullanıcıya ait varsa shared key değerini “GetAuthenticatorKeyAsync” metodu ile elde ediyoruz. Eğer yoksa 13. satırda “ResetAuthenticatorKeyAsync” metodu ile oluşturuyoruz.

Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication
Oluşturulan bu shared key değeri yukarıdaki görselde de görüldüğü üzere “AspNetUserTokens” tablosunda kullanıcıyla ilişkisel bir şekilde tutulmaktadır.

Adım 2 – QR Code İçin Path Hazırlama

Google & Microsoft authenticator uygulamaları ile ilgili kullanıcı hesabının eşleşebilmesi için bir barkod okuma operasyonu gerçekleştirilecektir. Oluşturulacak barkod içerisinde aşağıda izahatini gerçekleştirdiğimiz path formatının değeri basılmalıdır.

otpauth://totp/title:email?secret=sharedKey&issuer=who
  • title : Eşleştirilen authenticator uygulamasında yazacak başlık. Genellikle uygulama adı yahut adresi belirtilmektedir.
  • email : Uygulamaya dair yetkili bir e-posta adresi.
  • sharedKey : ‘GenerateSharedKey’ metodu ile üretilen shared key değeri.
  • who : Uygulamaya dair yetkili olan bir kişinin adı yahut yayıncı bilgisi.

Path değerini inşa etme sorumluluğunu yukarıda oluşturduğumuz ‘AuthenticatorService’ sınıfı içerisinde tanımlanan ‘GenerateQrCodeUri’ metodu üstlenmektedir.

    public class AuthenticatorService
    {
        UserManager<AppUser> _userManager;
        UrlEncoder _urlEncoder;
        public AuthenticatorService(UserManager<AppUser> userManager, UrlEncoder urlEncoder)
        {
            _userManager = userManager;
            _urlEncoder = urlEncoder;
        }
        public async Task<string> GenerateSharedKey(AppUser user)
        {
            string sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);
            if (string.IsNullOrEmpty(sharedKey))
            {
                IdentityResult result = await _userManager.ResetAuthenticatorKeyAsync(user);
                if (result.Succeeded)
                    sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);
            }
            return sharedKey;
        }
        public async Task<string> GenerateQrCodeUri(string sharedKey, string title, AppUser user) =>
            $"otpauth://totp/{_urlEncoder.Encode(title)}:{_urlEncoder.Encode(user.Email)}?secret={sharedKey}&issuer={_urlEncoder.Encode(title)}";
    }

En nihayetinde oluşturulan bu ‘AuthenticatorService’ isimli sınıfı “Startup.cs” dosyasındaki “ConfigureServices” metodu içerisinden uygulama providerına dahil ediyorum.

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            .
            .
            .
            services.AddScoped<AuthenticatorService, AuthenticatorService>();
            .
            .
            .
        }
        .
        .
        .
    }
Adım 3 – QR Code’un Basılması ve Temel Ayarların Yapımı

Kullanıcı kendi hesabında iki adımlı kullanıcı doğrulama yöntemini iradesiyle aktifleştirmeli ve ardından ekrana QrCode değerini tutan barkod oluşturularak okutulmaya hazır hale getirilmelidir. Bunun için “AppUser” entitysinde ilgili kullanıcının hangi 2FA yöntemini kullandığına dair veri tutan property eklenmektedir.

    public enum TwoFactorType
    {
        [Display(Name = "Microsoft & Google Authenticator İle Doğrulama")]
        Authenticator,
        [Display(Name = "SMS İle Doğrulama")]
        SMS,
        [Display(Name = "E-Posta İle Doğrulama")]
        Email
    }
    public class AppUser : IdentityUser<int>
    {
        public TwoFactorType TwoFactorType { get; set; }
    }

Ardından “TwoAuthentication(Controller).cs” isimli controller sınıfı oluşturuyoruz ve içerisini aşağıdaki gibi kodluyoruz.

    public class TwoAuthenticationController : Controller
    {
        AuthenticatorService _authenticatorService;
        UserManager<AppUser> _userManager;
        public TwoAuthenticationController(AuthenticatorService authenticatorService, UserManager<AppUser> userManager)
        {
            _authenticatorService = authenticatorService;
            _userManager = userManager;
        }
        public async Task<IActionResult> SelectTwoFactorAuthentication()
        {
            return View();
        }
        [HttpPost]
        public async Task<IActionResult> SelectTwoFactorAuthentication(TwoFactorTypeSelectVM model)
        {
            switch (model.TwoFactorType)
            {
                case Models.Enums.TwoFactorType.Authenticator:
                    return RedirectToAction("AuthenticatorVerify");
                case Models.Enums.TwoFactorType.SMS:
                    return RedirectToAction("SMSVerify");
                case Models.Enums.TwoFactorType.Email:
                    return RedirectToAction("EmailVerify");
            }
            return View();
        }
        public async Task<IActionResult> AuthenticatorVerify()
        {
            AppUser user = await _userManager.FindByNameAsync(User.Identity.Name);
            string sharedKey = await _authenticatorService.GenerateSharedKey(user);
            string qrcodeUri = await _authenticatorService.GenerateQrCodeUri(sharedKey, "www.gencayyildiz.com", user);

            return View(new AuthenticatorVM
            {
                SharedKey = sharedKey,
                QrCodeUri = qrcodeUri
            });
        }
        public async Task<IActionResult> SMSVerify()
        {
            //İlgili makalede kodlanacaktır...
            return View();
        }
        public async Task<IActionResult> EmailVerify()
        {
            //İlgili makalede kodlanacaktır...
            return View();
        }
    }

Yukarıdaki kod bloğunu incelerseniz eğer 10 ile 27. satırlar arasındaki ‘SelectTwoFactorAuthentication’ metodu ile uygulamada iki adımlı doğrulamada kullanılacak yöntem seçilmektedir. Görseli aşağıdaki gibidir;

@model TwoFactorTypeSelectVM

<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4">
        <form method="post">
            <div class="form-group">
                <label for="exampleFormControlSelect1">İki adımlı doğrulama yöntemi seçiniz</label>
                <select class="form-control" asp-for="TwoFactorType" asp-items="Html.GetEnumSelectList<TwoFactorType>()">
                </select>
            </div>
            <button type="submit" class="btn btn-danger">Seç</button>
        </form>
    </div>
    <div class="col-md-4"></div>
</div>

Kullanılan ‘TwoFactorTypeSelectVM’ viewmodel’ının içeriği ise aşağıdaki gibidir;

    public class TwoFactorTypeSelectVM
    {
        public TwoFactorType TwoFactorType { get; set; }
    }

Tekrardan ilgili kod bloğuna göz atarsak eğer kullanıcının ‘Microsoft & Google Authenticator’ seçeneğini seçmesi neticesinde 28. satırdaki ‘AuthenticatorVerify’ actionına yönlendirilecek ve içeriğinde gerekli shared key ile qr code uri değerleri oluşturularak view’ine gönderilecektir.
Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication


Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication

Qr Code Uri değerine karşılık barkodu basabilmek için davidshimjs.github.io/qrcodejs adresindeki JavaScript kütüphanesini indirerek uygulamanıza dahil ediniz. Gerekli script include işlemlerinden sonra aşağıdaki gibi ilgili actionın view görüntüsünde olduğu gibi barkodu oluşturabilirsiniz.

@model AuthenticatorVM
<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4">
        <div class="alert alert-success" role="alert">
            Aşağıdaki barkodu telefonunuzdaki Google ya da Microsoft authenticator uygulaması ile okutunuz veya yandaki kodu ilgili uygulamaya giriniz.
        </div>
    </div>
    <div class="col-md-4">
        <div class="alert alert-light" role="alert">
            @Model.SharedKey
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4">
        <div id="qrcode"></div>
        <script type="text/javascript">
            new QRCode(document.getElementById("qrcode"), {
                text:'@Model.QrCodeUri',
                width: 250,
                height: 250,
                correctLevel: QRCode.CorrectLevel.H
            });
        </script>
    </div>
    <div class="col-md-4"></div>
</div>
<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4">
        <form method="post">
            <div class="form-group">
                <label>Doğrulama Kodu</label>
                <input type="hidden" asp-for="QrCodeUri" />
                <input type="hidden" asp-for="SharedKey" />
                <input type="hidden" />
                <input type="text" class="form-control" asp-for="VerificationCode">
            </div>
            <button type="submit" class="btn btn-primary">Doğrula</button>
        </form>
    </div>
    <div class="col-md-4"></div>
</div>
@if (TempData["message2"] != null)
{
    <div class="row">
        <div class="col-md-4"></div>
        <div class="col-md-4">
            @TempData["message2"]
        </div>
        <div class="col-md-4">
            <div class="alert alert-info" role="alert">
                Kurtarma Kodları
            </div>
            <ul class="list-group">
                @foreach (var code in TempData["message3"] as IEnumerable<string>)
                {
                    <li class="list-group-item">@code</li>
                }
            </ul>
        </div>
    </div>
}

@section Scripts { @{await Html.RenderPartialAsync("_ScriptPartial");} }

Barkodu oluşturan JavaScript kodumuz 19 ile 26. satırlar arasındadır. Ayrıca bu actionda kullanılan ‘AuthenticatorVM’ isimli viewmodel nesnesinin içeriğini ele alırsak;

    public class AuthenticatorVM
    {
        public string SharedKey { get; set; }
        public string QrCodeUri { get; set; }
        public string VerificationCode { get; set; }
    }

şeklinde olacaktır. Bu içeriğimizde sadece Microsoft & Google authenticator yöntemini inceliyor olacağımızdan dolayı 40 ile 49. satırlar arasındaki action metotları şimdilik inşa etmeden o yöntemleri kaleme alacağımız ilgili yazılara bırakıyorum.

Adım 4 – Barkodun Okunması ve Doğrulanması

Oluşturulan barkodun okunması için öncelikle akıllı telefonunuza ya da tabletinize Microsoft Authenticator yahut Google Authenticator uygulamalarını yüklemeniz ve ardından aşağıdaki işlemleri gerçekleştirmeniz gerekmektedir.

Microsoft Authenticator Google Authenticator
Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication
Görüldüğü üzere her iki doğrulayıcıda barkodu okumakta ve başarıyla doğrulama kodu üretebilmektedir. Eğer ki farklı authenticator uygulamalarını aynı barkod değerini okuttuğunuz taktirde aynı anda açarsanız ortak algoritmayı kullanmalarından dolayı birebir aynı doğrulama kodu ürettiklerini göreceksiniz.

Ayriyetten barkod yerine her iki uygulamada da shared key değeri direkt olarak manuel verilerek devreye sokulabilmektedir.

Şimdi sıra authenticator tarafında üretilen kodun doğrulamasına gelmiştir. Bunun için tekrardan oluşturduğumuz ‘AuthenticatorService’ isimli servisimize gelerek aşağıdaki ‘Verify’ isimli metodu ekleyelim.

    public class AuthenticatorService
    {
        UserManager<AppUser> _userManager;
        UrlEncoder _urlEncoder;
        public AuthenticatorService(UserManager<AppUser> userManager, UrlEncoder urlEncoder)
        {
            _userManager = userManager;
            _urlEncoder = urlEncoder;
        }
        .
        .
        .
        public async Task<VerifyState> Verify(AuthenticatorVM model, AppUser user)
        {
            VerifyState verifyState = new VerifyState();
            verifyState.State = await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, model.VerificationCode);
            if (verifyState.State)
            {
                user.TwoFactorEnabled = true;
                verifyState.RecoveryCode = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 5);
            }
            return verifyState;
        }
    }

Bu metot sayesinde kullanıcıdan alınan doğrulama kodu onaylanarak ilgili hesapta iki adımlı doğrulama süreci aktifleştirilmektedir. Metodun detayına göz atarsak eğer 16. satırda ‘VerifyTwoFactorTokenAsync’ metodu sayesinde doğrulama kodu ilgili user’a özel kontrol edilmekte ve sonucu bool olarak döndürmektedir. Burada dikkat etmeniz gereken husus telefon ile uygulama sunucusunun bulunduğu yahut kullandığı Zaman Dilimlerinin birebir aynı yahut paralel bir eşdeğerlikte olmaları gerektiğidir. Aksi taktirde farklı zaman dilimlerinde unix time stamp değerlerinin farklı olma ihtimali oldukça yüksek olacağından dolayı doğrulama kodu onaylanmayacaktır. Eğer ki bu hususta tüm ayarlamalara rağmen localhost üzerinde hata yaşayanlarınız varsa bilgisayarınızın zaman dilimini ‘(UTC+03:00) Istanbul‘, akıllı telefon yahut tabletinizin zaman dilimini ise ‘GMT +03:00 Arabistan‘ olarak ayarlamanızı tavsiye ederim.

Ayriyetten ilgili metodun ikinci parametresine verdiğimiz “_userManager.Options.Tokens.AuthenticatorTokenProvider” komutu değerini uygulamada kullanılan varsayılan token providerdan almaya çalışacak ve biz eğer ki default token provider ayarlarını set etmediysek bu haliyle aşağıdaki olası hatayı verecektir.

An unhandled exception occurred while processing the request.
NotSupportedException: No IUserTwoFactorTokenProvider named ‘Authenticator’ is registered.

Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication
Bu hatayı almamak için uygulamaya default token değerini aşağıdaki gibi ‘Startup’ dosyasındaki ‘ConfigurationServices’ metodu içerisinde eklenen identity modülünün akabinde ‘AddDefaultTokenProviders’ metodunu kullanarak verebilirsiniz.

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            .
            .
            .
            services.AddIdentity<AppUser, AppRole>(options =>
            {
                options.Password.RequireDigit = false;
                options.Password.RequireLowercase = false;
                options.Password.RequiredLength = 3;
                options.Password.RequireLowercase = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = false;
            }).AddEntityFrameworkStores<TwoFactorAuthenticationContext>().AddDefaultTokenProviders();
            .
            .
            .
        }
        .
        .
        .
    }

Tekrardan servis kodlarına dönerek 19. satıra göz atarsanız eğer doğrulama kodu onaylandıktan sonra ilgili kullanıcıya dair “TwoFactorEnabled” kolonunu true yaparak iki adımlı kimlik doğrulama sürecini aktifleştirmekteyiz. Böylece ilgili kullanıcı login olmaya çalışırken direkt olarak sign in olamayacak yazımızın ileriki satırlarında göreceğimiz üzere bizden bir ikinci adım doğrulama gerektirdiğine dair bilgilendirmede bulunacaktır.

20. satırda ise ‘GenerateNewTwoFactorRecoveryCodesAsync’ metodu ile ne olurrr ne olmazz durumlarına istinaden önlem olması için 5 adet kurtarma kodu üretilmektedir 🙂

Tüm bu süreçte kullanılan “AuthenticatorVM” isimli viewmodel nesnesininde modeli aşağıdaki gibi olacaktır;

    public class AuthenticatorVM
    {
        public string SharedKey { get; set; }
        public string QrCodeUri { get; set; }
        public string VerificationCode { get; set; }
    }
Adım 5 – İki Adımlı Doğrulamanın Onaylanması

Sırada ‘AuthenticatorService’ içerisinde oluşturduğumuz ‘Verify’ metodunu ‘TwoAuthenticationController’ isimli controller sınıfında kullanmaya geldi.

    public class TwoAuthenticationController : Controller
    {
        AuthenticatorService _authenticatorService;
        UserManager<AppUser> _userManager;
        public TwoAuthenticationController(AuthenticatorService authenticatorService, UserManager<AppUser> userManager)
        {
            _authenticatorService = authenticatorService;
            _userManager = userManager;
        }
        .
        .
        .
        public async Task<IActionResult> AuthenticatorVerify()
        {
            AppUser user = await _userManager.FindByNameAsync(User.Identity.Name);
            string sharedKey = await _authenticatorService.GenerateSharedKey(user);
            string qrcodeUri = await _authenticatorService.GenerateQrCodeUri(sharedKey, "www.gencayyildiz.com", user);

            return View(new AuthenticatorVM
            {
                SharedKey = sharedKey,
                QrCodeUri = qrcodeUri
            });
        }
        [HttpPost]
        public async Task<IActionResult> AuthenticatorVerify(AuthenticatorVM model)
        {
            AppUser user = await _userManager.FindByNameAsync(User.Identity.Name);
            VerifyState verifyState = await _authenticatorService.Verify(model, user);
            if (verifyState.State)
            {
                TempData["message2"] = "İki adımlı doğrulama hesaba tanımlanmıştır.";
                TempData["message3"] = verifyState.RecoveryCode;
            }
            return View(model);
        }
    }

Bunun için 26. satırda görüldüğü üzere action metodunun post türünden ‘AuthenticatorVerify’ overload’ını oluşturuyoruz ve parametreden gelen post edilmiş veriyi metot içerisinde ilgili servisi kullanarak ‘Verify’ ediyoruz.

Bu işlemden sonra artık ilgili kullanıcı hesabı için iki adımlı doğrulamayı aktifleştirebiliriz;
Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication

Adım 6 – Login Esnasında İkinci Doğrulama Sayfasına Yönlendirme

Artık, bir önceki adımda ‘VerifyTwoFactorTokenAsync’ metodu ile girilen kod doğrulandıktan ve ilgili kullanıcının ‘TwoFactorEnabled’ değeri true yapıldıktan sonra login esnasında ikinci adımda doğrulama yapılması gerekmektedir.
Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication
Aksi taktirde soldaki görselde görüldüğü gibi giriş yapmaya çalışıldığı halde ikinci doğrulama olmaksızın authorize olunmayacaktır.

Bunun için ‘Login(Controller).cs’ de aşağıdaki gibi bir inşanın yapılması gerekmektedir.

    public class LoginController : Controller
    {
        private readonly SignInManager<AppUser> _signInManager;
        private readonly UserManager<AppUser> _userManager;
        public LoginController(SignInManager<AppUser> signInManager, UserManager<AppUser> userManager)
        {
            _signInManager = signInManager;
            _userManager = userManager;
        }
        public IActionResult Index(string ReturnUrl = "")
        {
            return View();
        }
        [HttpPost]
        public async Task<IActionResult> Index(string ReturnUrl, UserSignVM model)
        {
            if (ModelState.IsValid)
            {
                AppUser user = await _userManager.FindByEmailAsync(model.Email);
                if (user != null)
                {
                    Microsoft.AspNetCore.Identity.SignInResult result = await _signInManager.PasswordSignInAsync(user, model.Password, true, true);
                    if (result.Succeeded)
                    {
                        if (string.IsNullOrEmpty(ReturnUrl))
                            return RedirectToAction("Index", "Home");
                        return Redirect(ReturnUrl);
                    }
                    else if (result.RequiresTwoFactor)
                        return RedirectToAction("twofactorauthenticate", new { ReturnUrl = ReturnUrl });
                }
            }
            return View(model);
        }
        public async Task<IActionResult> TwoFactorAuthenticate(string ReturnUrl) => View();
        [HttpPost]
        public async Task<IActionResult> TwoFactorAuthenticate(string ReturnUrl, TwoFactorLoginVM model)
        {
            AppUser user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
            Microsoft.AspNetCore.Identity.SignInResult result = null;
            if (model.Recovery)
                result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(model.VerifyCode);
            else
                result = await _signInManager.TwoFactorAuthenticatorSignInAsync(model.VerifyCode, true, false);

            if (result.Succeeded)
                return Redirect(string.IsNullOrEmpty(ReturnUrl) ? "/home/index" : ReturnUrl);
            else
                ModelState.AddModelError("verifycode", "Doğrulama kodu yanlış girilmiştir!");

            return View(model);
        }
        public async Task<IActionResult> Logout()
        {
            await _signInManager.SignOutAsync();
            return RedirectToAction("Index", "Login");
        }
    }

Yukarıdaki ‘Login(Controller).cs’ içeriğini incelersek eğer ‘Index’ actionının post metoduna göz atarsanız eğer kullanıcı sign in olmaya çalıştığında ‘TwoFactorEnabled’ kolonu true olacağından dolayı 29. satırdaki result nesnesinin ‘RequiresTwoFactor’ propertysi true olarak gelecektir ve ikinci bir kimlik doğrulama yapılacağını bize bildirecektir. Dolayısıyla bizde bu durumda kullanıcıyı ‘TwoFactorAuthenticate’ isimli bir actiona yönlendirmekte ve burada ikinci doğrulamayı gerçekleştirmekteyiz. Birazdan view içeriğini göreceğimiz ilgili metodun 37. satırda tanımlanmış post türüne göz atarsak eğer modelden gelen ‘Recovery’ bilgisine göre kullanıcının girdiği kodun authenticator tarafından üretilmiş doğrulama kodu mu yoksa kurtarma kodu mu olup olmadığı ayırt ederek müdahalede bulunmaktayız. Eğer kurtarma kodu ile oturum açılmasını istiyorsak ‘TwoFactorRecoveryCodeSignInAsync’ metodunu yok eğer normal doğrulama kodu ile oturum açacaksak ‘TwoFactorAuthenticatorSignInAsync’ metodunu kullanmalıyız.

Ayrıca ikinci doğrulama sayfasına gelindiğinde hangi kullanıcıya doğrulama yapıldığını nereden anlıyoruz? sorunuzu duyar gibiyim… Bunun için mimarimiz kullanıcının bilgisini “Identity.TwoFactorUserId” anahtarında bir cookie değeri olarak tutmakta ve 39. satırda olduğu gibi ‘GetTwoFactorAuthenticationUserAsync’ metodu ile ikinci sayfadaki cookie değerlerini okuyarak ilgili kullanıcı nesnesini tekrar elde etmektedir.
Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication

Tüm bu yapılanma üzerine ikinci doğrulama sayfasının görüntüsünüde aşağıdaki gibi oluşturuyoruz;

@model TwoFactorLoginVM

<div class="row">
    <div class="col-md-4"></div>
    <div class="col-md-4">
        <form asp-action="TwoFactorAuthenticate" method="post">
            <div asp-validation-summary="All">
            </div>
            <div class="form-group">
                <label asp-for="VerifyCode"></label>
                <input type="text" class="form-control" asp-for="VerifyCode">
                <span asp-validation-for="VerifyCode"></span>
            </div>
            <div class="form-group form-check">
                <input type="checkbox" class="form-check-input" asp-for="Recovery">
                <label class="form-check-label" for="exampleCheck1">Kurtarma kodu ile giriş yapabilmek için bu kutucuğu işaretleyiniz.</label>
            </div>
            <button type="submit" class="btn btn-primary">Giriş Yap</button>
        </form>
    </div>
    <div class="col-md-4"></div>
</div>
Adım 7 – Test Etme

Tüm bu yapılanmayı derleyip çalıştıralım ve aşağıdaki gibi test edelim.
Asp.NET Core - Google & Microsoft Authenticator İle Two Factor Authentication
Görüldüğü üzere gayet başarılı bir şekilde çalışmakta ve iki adımlı doğrulamayı gerçekleştirmektedir.

Vee böylece blog hayatım boyunca şu ana kadar olan en uzun makaleyi kaleme almış bulunmaktayım 🙂 Eee böyle bir konuyu anlatabilmek zor; okuyabilmek, okurken anlayabilmek ap ayrı bir zor… O yüzden bu satırlara erişebilenlerin nezdinde okumaya cüret eden lakin sonunu getiremeyenlerde dahil hepinize sonsuz teşekkür ediyorum…

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek projeyi indirebilmek için buraya tıklayınız.

Bunlar da hoşunuza gidebilir...

3 Cevaplar

  1. oğuzhan dedi ki:

    Merhaba hocam sms doğrulamayı makalelerinizde bulamadım projeme eklemek istiyorum. Acaba kaynak varmı bildiğiniz.

    • Gençay dedi ki:

      Merhaba,

      SMS doğrulama işlemi için operatörlerin ücretsiz bir sağlayıcısı olmadığından dolayı konuya dair bir içerik oluşturamadım.

  1. 12 Mart 2020

    […] Asp.NET Core – Google & Microsoft Authenticator İle Two Factor Authentication […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*