﻿
{"id":14039,"date":"2020-03-12T20:51:31","date_gmt":"2020-03-12T20:51:31","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=14039"},"modified":"2020-03-12T21:08:19","modified_gmt":"2020-03-12T21:08:19","slug":"asp-net-core-google-microsoft-authenticator-ile-two-factor-authentication","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-google-microsoft-authenticator-ile-two-factor-authentication\/","title":{"rendered":"Asp.NET Core &#8211; Google &#038; Microsoft Authenticator \u0130le Two Factor Authentication"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Bir \u00f6nceki <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-identity-two-factor-authentication-nedir\/\" rel=\"noopener noreferrer\" target=\"_blank\">Two Factor Authentication Nedir?<\/a> ba\u015fl\u0131kl\u0131 makalemizin akabinde art\u0131k Google &#038; Microsoft Authenticator ile iki ad\u0131ml\u0131 kimlik do\u011frulama y\u00f6ntemi \u00fczerine detayl\u0131 durabilir ve pratiksel a\u00e7\u0131dan t\u00fcm in\u015fa s\u00fcrecini irdeleyebiliriz.<\/p>\n<h3>Microsoft &#038; Google Authenticator Nedir?<\/h3>\n<table>\n<thead>\n<tr>\n<th>One Factor Authenticator<\/th>\n<th>Two Factor Authenticator<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir..jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir..jpg\" alt=\"Asp.NET Core Identity - Two Factor Authentication Nedir?\" width=\"1145\" height=\"358\" class=\"alignnone size-full wp-image-14009\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir..jpg 1145w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-300x94.jpg 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1024x320.jpg 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-768x240.jpg 768w\" sizes=\"auto, (max-width: 1145px) 100vw, 1145px\" \/><\/a><\/td>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1.jpg\" alt=\"Asp.NET Core Identity - Two Factor Authentication Nedir.\" width=\"1087\" height=\"262\" class=\"alignnone size-full wp-image-14013\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1.jpg 1087w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1-300x72.jpg 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1-1024x247.jpg 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Identity-Two-Factor-Authentication-Nedir.-1-768x185.jpg 768w\" sizes=\"auto, (max-width: 1087px) 100vw, 1087px\" \/><\/a><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\">\nUygulama \u00fczerinden yetkileri do\u011frultusunda faaliyetlerde bulunabilmek i\u00e7in kullan\u0131c\u0131 taraf\u0131ndan ger\u00e7ekle\u015ftirilen kimlik do\u011frulama s\u00fcrecinde iki ad\u0131ml\u0131 do\u011frulama yapabilmek i\u00e7in Microsoft, Google ile birlikte esas\u0131nda bir\u00e7ok sa\u011flay\u0131c\u0131 taraf\u0131ndan geli\u015ftirilen uygulamad\u0131r.\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Peki teoride nas\u0131l \u00e7al\u0131\u015fmaktad\u0131r?<\/strong><br \/>\nKullan\u0131c\u0131ya \u00f6zel olarak \u00fcretilen <em>Shared Key<\/em> isimli bir de\u011fer ile birlikte <em>Zaman Damgas\u0131(Timestamp\/Counter)<\/em> ismi verilen bir de\u011feri kullanarak <em style=\"color:purple\">(HTOP) Hmac &#8211; Based One Time Password(Zaman Bazl\u0131 Tek Kullan\u0131ml\u0131k \u015eifre) &#8211; RFC 6238<\/em> algoritmas\u0131 ile 30 saniyede bir yenilenen ve tek seferlik kullan\u0131m hakk\u0131 olan do\u011frulama kodunu \u00fcretmekt\u00ebdir. Bu \u015fekilde t\u00fcm authenticator uygulamalar\u0131 ayn\u0131 algoritmay\u0131 kulland\u0131klar\u0131nda dolay\u0131 kullan\u0131c\u0131ya \u00f6zel shared key de\u011feri ile e\u015fle\u015fme sonras\u0131 ayn\u0131 anda ayn\u0131 kodu \u00fcretecektirler. Dolay\u0131s\u0131yla Google yahut Microsoft hangisi olursa olsun farketmeksizin ayn\u0131 i\u015fi g\u00f6recektir&#8230;<\/p>\n<p>Kodun \u00fcretilmesinde kullan\u0131lan Unix Time Stamp(Zaman Damgas\u0131) de\u011ferinin ba\u015flang\u0131\u00e7 tarihi 01.01.1970 00:00:00 olarak kabul edilmi\u015ftir ve o andan \u015fu ana kadar ge\u00e7en toplam saniyeyi ifade etmektedir. Authenticator uygulamas\u0131nda counter do\u011frulama kodu \u00fcretildi\u011fi ana kadar olan toplam saniye de\u011feri olan o anki timestamp de\u011ferini tutuyor ve bu kod 30 saniye ge\u00e7ene kadar aktifli\u011fini s\u00fcrd\u00fcrebiliyor. Bir sonraki kodda ayn\u0131 \u015fekilde \u00fcretildi\u011fi andaki toplam saniye de\u011ferini countera veriyor ve aradaki fark\u0131 30 saniye olana kadar aktifli\u011fini koruyor. Vee bu s\u00fcre\u00e7 aynen bu d\u00f6ng\u00fcyle devam ediyor. Burada dikkat edilmesi gereken nokta \u015fudur ki, bu toplam saniye verisini baz al\u0131rken ilgili telefon yahut tabletinde bu ba\u015flang\u0131\u00e7 tarihiyle birebir tutarl\u0131 olmas\u0131 gerekmekte ve bunun i\u00e7in Zaman Dilimi kavram\u0131n\u0131n do\u011fru \u015fekilde ayarlanmas\u0131 gerekmektedir. Aksi taktirde zaman dilimi Afrika&#8217;da olan bir telefon ya da tabletten \u00fcretilen do\u011frulama kodu Kanada zaman dilimini benimsemi\u015f bir uygulamayla unix time stamp olarak tutarl\u0131l\u0131k g\u00f6stermeyece\u011finden dolay\u0131 ge\u00e7ersiz olacakt\u0131r.<\/p>\n<p>\u015eimdi gelin Google &#038; Microsoft Authenticator stratejisinin pratik olarak nas\u0131l uyguland\u0131\u011f\u0131n\u0131 \u00f6rnek bir proje \u00fczerinden inceleyelim. Bunun i\u00e7in temel <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-identity-yazi-dizisi\/\" rel=\"noopener noreferrer\" target=\"_blank\">Identity<\/a> yap\u0131lanmas\u0131 One Factor Authentication kullan\u0131lacak \u015fekilde haz\u0131r olan herhangi bir Asp.NET Core projesinde Two Factor Authentication y\u00f6nteminin nas\u0131l in\u015fa edildi\u011fini irdeleyelim&#8230; <\/p>\n<h3>Two Factor Authentication \u0130n\u015fas\u0131<\/h3>\n<p><a href=\"#adim1\">Ad\u0131m 1 &#8211; Kullan\u0131c\u0131ya \u00d6zel Shared Key \u00dcretimi<a href=\"#adim7\"><br \/>\n<a href=\"#adim2\">Ad\u0131m 2 \u2013 QR Code \u0130\u00e7in Path Haz\u0131rlama<a href=\"#adim7\"><br \/>\n<a href=\"#adim3\">Ad\u0131m 3 \u2013 QR Code\u2019un Bas\u0131lmas\u0131 ve Temel Ayarlar\u0131n Yap\u0131m\u0131<a href=\"#adim7\"><br \/>\n<a href=\"#adim4\">Ad\u0131m 4 \u2013 Barkodun Okunmas\u0131 ve Do\u011frulanmas\u0131<a href=\"#adim7\"><br \/>\n<a href=\"#adim5\">Ad\u0131m 5 &#8211; \u0130ki Ad\u0131ml\u0131 Do\u011frulaman\u0131n Onaylanmas\u0131<a href=\"#adim7\"><br \/>\n<a href=\"#adim6\">Ad\u0131m 6 &#8211; Login Esnas\u0131nda \u0130kinci Do\u011frulama Sayfas\u0131na Y\u00f6nlendirme<a href=\"#adim7\"><br \/>\n<a href=\"#adim7\">Ad\u0131m 7 &#8211; Test Etme<\/a><\/p>\n<h5 style=\"color:green;\" id=\"adim1\">Ad\u0131m 1 &#8211; Kullan\u0131c\u0131ya \u00d6zel Shared Key \u00dcretimi<\/h5>\n<p>\u0130lk olarak uygulamam\u0131zda iki ad\u0131ml\u0131 do\u011frulamay\u0131 ger\u00e7ekle\u015ftirebilmek i\u00e7in kullan\u0131c\u0131ya \u00f6zel Shared Key \u00fcretmemiz gerekmektedir. Bunun i\u00e7in &#8216;AuthenticatorService&#8217; ismini verdi\u011fim bir servis olu\u015fturarak i\u00e7eri\u011fini a\u015fa\u011f\u0131daki gibi geli\u015ftiriyorum.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthenticatorService\r\n    {\r\n        UserManager&lt;AppUser&gt; _userManager;\r\n        public AuthenticatorService(UserManager&lt;AppUser&gt; userManager)\r\n        {\r\n            _userManager = userManager;\r\n        }\r\n        public async Task&lt;string&gt; GenerateSharedKey(AppUser user)\r\n        {\r\n            string sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);\r\n            if (string.IsNullOrEmpty(sharedKey))\r\n            {\r\n                IdentityResult result = await _userManager.ResetAuthenticatorKeyAsync(user);\r\n                if (result.Succeeded)\r\n                    sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);\r\n            }\r\n            return sharedKey;\r\n        }\r\n    }\r\n<\/pre>\n<p>Burada 10. sat\u0131rda parametreden gelen kullan\u0131c\u0131ya ait varsa shared key de\u011ferini &#8220;GetAuthenticatorKeyAsync&#8221; metodu ile elde ediyoruz. E\u011fer yoksa 13. sat\u0131rda &#8220;ResetAuthenticatorKeyAsync&#8221; metodu ile olu\u015fturuyoruz.<\/p>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication.jpg\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"835\" height=\"275\" class=\"alignnone size-full wp-image-14072\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication.jpg 835w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-300x99.jpg 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-768x253.jpg 768w\" sizes=\"auto, (max-width: 835px) 100vw, 835px\" \/><\/a><br \/>\nOlu\u015fturulan bu shared key de\u011feri yukar\u0131daki g\u00f6rselde de g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere &#8220;AspNetUserTokens&#8221; tablosunda kullan\u0131c\u0131yla ili\u015fkisel bir \u015fekilde tutulmaktad\u0131r.<\/p>\n<h5 style=\"color:green;\" id=\"adim2\">Ad\u0131m 2 &#8211; QR Code \u0130\u00e7in Path Haz\u0131rlama<\/h5>\n<p>Google &#038; Microsoft authenticator uygulamalar\u0131 ile ilgili kullan\u0131c\u0131 hesab\u0131n\u0131n e\u015fle\u015febilmesi i\u00e7in bir barkod okuma operasyonu ger\u00e7ekle\u015ftirilecektir. Olu\u015fturulacak barkod i\u00e7erisinde a\u015fa\u011f\u0131da izahatini ger\u00e7ekle\u015ftirdi\u011fimiz path format\u0131n\u0131n de\u011feri bas\u0131lmal\u0131d\u0131r.<\/p>\n<div style=\"text-align:center;\">\notpauth:\/\/totp\/<span style=\"color:red\">title<\/span>:<span style=\"color:red\">email<\/span>?secret=<span style=\"color:red\">sharedKey<\/span>&#038;issuer=<span style=\"color:red\">who<\/span>\n<\/div>\n<ul>\n<li><strong style=\"color:red\">title<\/strong> : E\u015fle\u015ftirilen authenticator uygulamas\u0131nda yazacak ba\u015fl\u0131k. Genellikle uygulama ad\u0131 yahut adresi belirtilmektedir.<\/li>\n<li><strong style=\"color:red\">email<\/strong> : Uygulamaya dair yetkili bir e-posta adresi.<\/li>\n<li><strong style=\"color:red\">sharedKey<\/strong> : &#8216;GenerateSharedKey&#8217; metodu ile \u00fcretilen shared key de\u011feri.<\/li>\n<li><strong style=\"color:red\">who<\/strong> : Uygulamaya dair yetkili olan bir ki\u015finin ad\u0131 yahut yay\u0131nc\u0131 bilgisi.<\/li>\n<\/ul>\n<p>Path de\u011ferini in\u015fa etme sorumlulu\u011funu yukar\u0131da olu\u015fturdu\u011fumuz &#8216;AuthenticatorService&#8217; s\u0131n\u0131f\u0131 i\u00e7erisinde tan\u0131mlanan &#8216;GenerateQrCodeUri&#8217; metodu \u00fcstlenmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthenticatorService\r\n    {\r\n        UserManager&lt;AppUser&gt; _userManager;\r\n        UrlEncoder _urlEncoder;\r\n        public AuthenticatorService(UserManager&lt;AppUser&gt; userManager, UrlEncoder urlEncoder)\r\n        {\r\n            _userManager = userManager;\r\n            _urlEncoder = urlEncoder;\r\n        }\r\n        public async Task&lt;string&gt; GenerateSharedKey(AppUser user)\r\n        {\r\n            string sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);\r\n            if (string.IsNullOrEmpty(sharedKey))\r\n            {\r\n                IdentityResult result = await _userManager.ResetAuthenticatorKeyAsync(user);\r\n                if (result.Succeeded)\r\n                    sharedKey = await _userManager.GetAuthenticatorKeyAsync(user);\r\n            }\r\n            return sharedKey;\r\n        }\r\n        public async Task&lt;string&gt; GenerateQrCodeUri(string sharedKey, string title, AppUser user) =&gt;\r\n            $&quot;otpauth:\/\/totp\/{_urlEncoder.Encode(title)}:{_urlEncoder.Encode(user.Email)}?secret={sharedKey}&amp;issuer={_urlEncoder.Encode(title)}&quot;;\r\n    }\r\n<\/pre>\n<p>En nihayetinde olu\u015fturulan bu &#8216;AuthenticatorService&#8217; isimli s\u0131n\u0131f\u0131 &#8220;Startup.cs&#8221; dosyas\u0131ndaki &#8220;ConfigureServices&#8221; metodu i\u00e7erisinden uygulama provider\u0131na dahil ediyorum.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Startup\r\n    {\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            services.AddScoped&lt;AuthenticatorService, AuthenticatorService&gt;();\r\n            .\r\n            .\r\n            .\r\n        }\r\n        .\r\n        .\r\n        .\r\n    }\r\n<\/pre>\n<h5 style=\"color:green;\" id=\"adim3\">Ad\u0131m 3 &#8211; QR Code&#8217;un Bas\u0131lmas\u0131 ve Temel Ayarlar\u0131n Yap\u0131m\u0131<\/h5>\n<p>Kullan\u0131c\u0131 kendi hesab\u0131nda iki ad\u0131ml\u0131 kullan\u0131c\u0131 do\u011frulama y\u00f6ntemini iradesiyle aktifle\u015ftirmeli ve ard\u0131ndan ekrana QrCode de\u011ferini tutan barkod olu\u015fturularak okutulmaya haz\u0131r hale getirilmelidir. Bunun i\u00e7in &#8220;AppUser&#8221; entitysinde ilgili kullan\u0131c\u0131n\u0131n hangi 2FA y\u00f6ntemini kulland\u0131\u011f\u0131na dair veri tutan property eklenmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public enum TwoFactorType\r\n    {\r\n        &#x5B;Display(Name = &quot;Microsoft &amp; Google Authenticator \u0130le Do\u011frulama&quot;)]\r\n        Authenticator,\r\n        &#x5B;Display(Name = &quot;SMS \u0130le Do\u011frulama&quot;)]\r\n        SMS,\r\n        &#x5B;Display(Name = &quot;E-Posta \u0130le Do\u011frulama&quot;)]\r\n        Email\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AppUser : IdentityUser&lt;int&gt;\r\n    {\r\n        public TwoFactorType TwoFactorType { get; set; }\r\n    }\r\n<\/pre>\n<p>Ard\u0131ndan &#8220;TwoAuthentication(Controller).cs&#8221; isimli controller s\u0131n\u0131f\u0131 olu\u015fturuyoruz ve i\u00e7erisini a\u015fa\u011f\u0131daki gibi kodluyoruz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class TwoAuthenticationController : Controller\r\n    {\r\n        AuthenticatorService _authenticatorService;\r\n        UserManager&lt;AppUser&gt; _userManager;\r\n        public TwoAuthenticationController(AuthenticatorService authenticatorService, UserManager&lt;AppUser&gt; userManager)\r\n        {\r\n            _authenticatorService = authenticatorService;\r\n            _userManager = userManager;\r\n        }\r\n        public async Task&lt;IActionResult&gt; SelectTwoFactorAuthentication()\r\n        {\r\n            return View();\r\n        }\r\n        &#x5B;HttpPost]\r\n        public async Task&lt;IActionResult&gt; SelectTwoFactorAuthentication(TwoFactorTypeSelectVM model)\r\n        {\r\n            switch (model.TwoFactorType)\r\n            {\r\n                case Models.Enums.TwoFactorType.Authenticator:\r\n                    return RedirectToAction(&quot;AuthenticatorVerify&quot;);\r\n                case Models.Enums.TwoFactorType.SMS:\r\n                    return RedirectToAction(&quot;SMSVerify&quot;);\r\n                case Models.Enums.TwoFactorType.Email:\r\n                    return RedirectToAction(&quot;EmailVerify&quot;);\r\n            }\r\n            return View();\r\n        }\r\n        public async Task&lt;IActionResult&gt; AuthenticatorVerify()\r\n        {\r\n            AppUser user = await _userManager.FindByNameAsync(User.Identity.Name);\r\n            string sharedKey = await _authenticatorService.GenerateSharedKey(user);\r\n            string qrcodeUri = await _authenticatorService.GenerateQrCodeUri(sharedKey, &quot;www.gencayyildiz.com&quot;, user);\r\n\r\n            return View(new AuthenticatorVM\r\n            {\r\n                SharedKey = sharedKey,\r\n                QrCodeUri = qrcodeUri\r\n            });\r\n        }\r\n        public async Task&lt;IActionResult&gt; SMSVerify()\r\n        {\r\n            \/\/\u0130lgili makalede kodlanacakt\u0131r...\r\n            return View();\r\n        }\r\n        public async Task&lt;IActionResult&gt; EmailVerify()\r\n        {\r\n            \/\/\u0130lgili makalede kodlanacakt\u0131r...\r\n            return View();\r\n        }\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer 10 ile 27. sat\u0131rlar aras\u0131ndaki &#8216;SelectTwoFactorAuthentication&#8217; metodu ile uygulamada iki ad\u0131ml\u0131 do\u011frulamada kullan\u0131lacak y\u00f6ntem se\u00e7ilmektedir. G\u00f6rseli a\u015fa\u011f\u0131daki gibidir;<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n@model TwoFactorTypeSelectVM\r\n\r\n&lt;div class=&quot;row&quot;&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;form method=&quot;post&quot;&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;label for=&quot;exampleFormControlSelect1&quot;&gt;\u0130ki ad\u0131ml\u0131 do\u011frulama y\u00f6ntemi se\u00e7iniz&lt;\/label&gt;\r\n                &lt;select class=&quot;form-control&quot; asp-for=&quot;TwoFactorType&quot; asp-items=&quot;Html.GetEnumSelectList&lt;TwoFactorType&gt;()&quot;&gt;\r\n                &lt;\/select&gt;\r\n            &lt;\/div&gt;\r\n            &lt;button type=&quot;submit&quot; class=&quot;btn btn-danger&quot;&gt;Se\u00e7&lt;\/button&gt;\r\n        &lt;\/form&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>Kullan\u0131lan &#8216;TwoFactorTypeSelectVM&#8217; viewmodel&#8217;\u0131n\u0131n i\u00e7eri\u011fi ise a\u015fa\u011f\u0131daki gibidir;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class TwoFactorTypeSelectVM\r\n    {\r\n        public TwoFactorType TwoFactorType { get; set; }\r\n    }\r\n<\/pre>\n<p>Tekrardan ilgili kod blo\u011funa g\u00f6z atarsak e\u011fer kullan\u0131c\u0131n\u0131n &#8216;Microsoft &#038; Google Authenticator&#8217; se\u00e7ene\u011fini se\u00e7mesi neticesinde 28. sat\u0131rdaki &#8216;AuthenticatorVerify&#8217; action\u0131na y\u00f6nlendirilecek ve i\u00e7eri\u011finde gerekli shared key ile qr code uri de\u011ferleri olu\u015fturularak view&#8217;ine g\u00f6nderilecektir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-1.jpg\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"617\" height=\"143\" class=\"alignnone size-full wp-image-14088\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-1.jpg 617w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-1-300x70.jpg 300w\" sizes=\"auto, (max-width: 617px) 100vw, 617px\" \/><\/a><\/p>\n<hr>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2.jpg\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"969\" height=\"477\" class=\"alignnone size-full wp-image-14090\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2.jpg 969w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2-300x148.jpg 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2-768x378.jpg 768w\" sizes=\"auto, (max-width: 969px) 100vw, 969px\" \/><\/a><\/p>\n<p>Qr Code Uri de\u011ferine kar\u015f\u0131l\u0131k barkodu basabilmek i\u00e7in <a href=\"https:\/\/davidshimjs.github.io\/qrcodejs\/\" rel=\"noopener noreferrer\" target=\"_blank\">davidshimjs.github.io\/qrcodejs<\/a> adresindeki JavaScript k\u00fct\u00fcphanesini indirerek uygulaman\u0131za dahil ediniz. Gerekli script include i\u015flemlerinden sonra a\u015fa\u011f\u0131daki gibi ilgili action\u0131n view g\u00f6r\u00fcnt\u00fcs\u00fcnde oldu\u011fu gibi barkodu olu\u015fturabilirsiniz.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n@model AuthenticatorVM\r\n&lt;div class=&quot;row&quot;&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;div class=&quot;alert alert-success&quot; role=&quot;alert&quot;&gt;\r\n            A\u015fa\u011f\u0131daki barkodu telefonunuzdaki Google ya da Microsoft authenticator uygulamas\u0131 ile okutunuz veya yandaki kodu ilgili uygulamaya giriniz.\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;div class=&quot;alert alert-light&quot; role=&quot;alert&quot;&gt;\r\n            @Model.SharedKey\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=&quot;row&quot;&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;div id=&quot;qrcode&quot;&gt;&lt;\/div&gt;\r\n        &lt;script type=&quot;text\/javascript&quot;&gt;\r\n            new QRCode(document.getElementById(&quot;qrcode&quot;), {\r\n                text:'@Model.QrCodeUri',\r\n                width: 250,\r\n                height: 250,\r\n                correctLevel: QRCode.CorrectLevel.H\r\n            });\r\n        &lt;\/script&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=&quot;row&quot;&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;form method=&quot;post&quot;&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;label&gt;Do\u011frulama Kodu&lt;\/label&gt;\r\n                &lt;input type=&quot;hidden&quot; asp-for=&quot;QrCodeUri&quot; \/&gt;\r\n                &lt;input type=&quot;hidden&quot; asp-for=&quot;SharedKey&quot; \/&gt;\r\n                &lt;input type=&quot;hidden&quot; \/&gt;\r\n                &lt;input type=&quot;text&quot; class=&quot;form-control&quot; asp-for=&quot;VerificationCode&quot;&gt;\r\n            &lt;\/div&gt;\r\n            &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;Do\u011frula&lt;\/button&gt;\r\n        &lt;\/form&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n&lt;\/div&gt;\r\n@if (TempData&#x5B;&quot;message2&quot;] != null)\r\n{\r\n    &lt;div class=&quot;row&quot;&gt;\r\n        &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n        &lt;div class=&quot;col-md-4&quot;&gt;\r\n            @TempData&#x5B;&quot;message2&quot;]\r\n        &lt;\/div&gt;\r\n        &lt;div class=&quot;col-md-4&quot;&gt;\r\n            &lt;div class=&quot;alert alert-info&quot; role=&quot;alert&quot;&gt;\r\n                Kurtarma Kodlar\u0131\r\n            &lt;\/div&gt;\r\n            &lt;ul class=&quot;list-group&quot;&gt;\r\n                @foreach (var code in TempData&#x5B;&quot;message3&quot;] as IEnumerable&lt;string&gt;)\r\n                {\r\n                    &lt;li class=&quot;list-group-item&quot;&gt;@code&lt;\/li&gt;\r\n                }\r\n            &lt;\/ul&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n}\r\n\r\n@section Scripts { @{await Html.RenderPartialAsync(&quot;_ScriptPartial&quot;);} }\r\n<\/pre>\n<p>Barkodu olu\u015fturan JavaScript kodumuz 19 ile 26. sat\u0131rlar aras\u0131ndad\u0131r. Ayr\u0131ca bu actionda kullan\u0131lan &#8216;AuthenticatorVM&#8217; isimli viewmodel nesnesinin i\u00e7eri\u011fini ele al\u0131rsak;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthenticatorVM\r\n    {\r\n        public string SharedKey { get; set; }\r\n        public string QrCodeUri { get; set; }\r\n        public string VerificationCode { get; set; }\r\n    }\r\n<\/pre>\n<p>\u015feklinde olacakt\u0131r. Bu i\u00e7eri\u011fimizde sadece Microsoft &#038; Google authenticator y\u00f6ntemini inceliyor olaca\u011f\u0131m\u0131zdan dolay\u0131 40 ile 49. sat\u0131rlar aras\u0131ndaki action metotlar\u0131 \u015fimdilik in\u015fa etmeden o y\u00f6ntemleri kaleme alaca\u011f\u0131m\u0131z ilgili yaz\u0131lara b\u0131rak\u0131yorum.<\/p>\n<h5 style=\"color:green;\" id=\"adim4\">Ad\u0131m 4 &#8211; Barkodun Okunmas\u0131 ve Do\u011frulanmas\u0131<\/h5>\n<p>Olu\u015fturulan barkodun okunmas\u0131 i\u00e7in \u00f6ncelikle ak\u0131ll\u0131 telefonunuza ya da tabletinize <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.azure.authenticator&#038;hl=tr\" rel=\"noopener noreferrer\" target=\"_blank\">Microsoft Authenticator<\/a> yahut <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.google.android.apps.authenticator2&#038;hl=tr\" rel=\"noopener noreferrer\" target=\"_blank\">Google Authenticator<\/a> uygulamalar\u0131n\u0131 y\u00fcklemeniz ve ard\u0131ndan a\u015fa\u011f\u0131daki i\u015flemleri ger\u00e7ekle\u015ftirmeniz gerekmektedir.<\/p>\n<table>\n<thead>\n<tr>\n<th>Microsoft Authenticator<\/th>\n<th>Google Authenticator<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication.gif\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"500\" height=\"988\" class=\"alignnone size-full wp-image-14105\" \/><\/a><\/td>\n<td>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-1.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-1.gif\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"500\" height=\"988\" class=\"alignnone size-full wp-image-14106\" \/><\/a>\n<\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\">G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere her iki do\u011frulay\u0131c\u0131da barkodu okumakta ve ba\u015far\u0131yla do\u011frulama kodu \u00fcretebilmektedir. E\u011fer ki farkl\u0131 authenticator uygulamalar\u0131n\u0131 ayn\u0131 barkod de\u011ferini okuttu\u011funuz taktirde ayn\u0131 anda a\u00e7arsan\u0131z ortak algoritmay\u0131 kullanmalar\u0131ndan dolay\u0131 birebir ayn\u0131 do\u011frulama kodu \u00fcrettiklerini g\u00f6receksiniz.<\/p>\n<p>Ayriyetten barkod yerine her iki uygulamada da shared key de\u011feri direkt olarak manuel verilerek devreye sokulabilmektedir.\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u015eimdi s\u0131ra authenticator taraf\u0131nda \u00fcretilen kodun do\u011frulamas\u0131na gelmi\u015ftir. Bunun i\u00e7in tekrardan olu\u015fturdu\u011fumuz &#8216;AuthenticatorService&#8217; isimli servisimize gelerek a\u015fa\u011f\u0131daki &#8216;Verify&#8217; isimli metodu ekleyelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthenticatorService\r\n    {\r\n        UserManager&lt;AppUser&gt; _userManager;\r\n        UrlEncoder _urlEncoder;\r\n        public AuthenticatorService(UserManager&lt;AppUser&gt; userManager, UrlEncoder urlEncoder)\r\n        {\r\n            _userManager = userManager;\r\n            _urlEncoder = urlEncoder;\r\n        }\r\n        .\r\n        .\r\n        .\r\n        public async Task&lt;VerifyState&gt; Verify(AuthenticatorVM model, AppUser user)\r\n        {\r\n            VerifyState verifyState = new VerifyState();\r\n            verifyState.State = await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, model.VerificationCode);\r\n            if (verifyState.State)\r\n            {\r\n                user.TwoFactorEnabled = true;\r\n                verifyState.RecoveryCode = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 5);\r\n            }\r\n            return verifyState;\r\n        }\r\n    }\r\n<\/pre>\n<p>Bu metot sayesinde kullan\u0131c\u0131dan al\u0131nan do\u011frulama kodu onaylanarak ilgili hesapta iki ad\u0131ml\u0131 do\u011frulama s\u00fcreci aktifle\u015ftirilmektedir. Metodun detay\u0131na g\u00f6z atarsak e\u011fer 16. sat\u0131rda &#8216;VerifyTwoFactorTokenAsync&#8217; metodu sayesinde do\u011frulama kodu ilgili user&#8217;a \u00f6zel kontrol edilmekte ve sonucu bool olarak d\u00f6nd\u00fcrmektedir. Burada dikkat etmeniz gereken husus telefon ile uygulama sunucusunun bulundu\u011fu yahut kulland\u0131\u011f\u0131 Zaman Dilimlerinin birebir ayn\u0131 yahut paralel bir e\u015fde\u011ferlikte olmalar\u0131 gerekti\u011fidir. Aksi taktirde farkl\u0131 zaman dilimlerinde unix time stamp de\u011ferlerinin farkl\u0131 olma ihtimali olduk\u00e7a y\u00fcksek olaca\u011f\u0131ndan dolay\u0131 do\u011frulama kodu onaylanmayacakt\u0131r. E\u011fer ki bu hususta t\u00fcm ayarlamalara ra\u011fmen localhost \u00fczerinde hata ya\u015fayanlar\u0131n\u0131z varsa bilgisayar\u0131n\u0131z\u0131n zaman dilimini &#8216;<em>(UTC+03:00) Istanbul<\/em>&#8216;, ak\u0131ll\u0131 telefon yahut tabletinizin zaman dilimini ise &#8216;<em>GMT +03:00 Arabistan<\/em>&#8216; olarak ayarlaman\u0131z\u0131 tavsiye ederim.<\/p>\n<p>Ayriyetten ilgili metodun ikinci parametresine verdi\u011fimiz &#8220;<em>_userManager.Options.Tokens.AuthenticatorTokenProvider<\/em>&#8221; komutu de\u011ferini uygulamada kullan\u0131lan varsay\u0131lan token providerdan almaya \u00e7al\u0131\u015facak ve biz e\u011fer ki default token provider ayarlar\u0131n\u0131 set etmediysek bu haliyle a\u015fa\u011f\u0131daki olas\u0131 hatay\u0131 verecektir.<\/p>\n<blockquote style=\"color:red\"><p><em>An unhandled exception occurred while processing the request.<br \/>\nNotSupportedException: No IUserTwoFactorTokenProvider<TUser> named &#8216;Authenticator&#8217; is registered.<\/em><\/p><\/blockquote>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-3.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-3.jpg\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"619\" height=\"284\" class=\"alignnone size-full wp-image-14126\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-3.jpg 619w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-3-300x138.jpg 300w\" sizes=\"auto, (max-width: 619px) 100vw, 619px\" \/><\/a><br \/>\nBu hatay\u0131 almamak i\u00e7in uygulamaya default token de\u011ferini a\u015fa\u011f\u0131daki gibi &#8216;Startup&#8217; dosyas\u0131ndaki &#8216;ConfigurationServices&#8217; metodu i\u00e7erisinde eklenen identity mod\u00fcl\u00fcn\u00fcn akabinde &#8216;AddDefaultTokenProviders&#8217; metodunu kullanarak verebilirsiniz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Startup\r\n    {\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            services.AddIdentity&lt;AppUser, AppRole&gt;(options =&gt;\r\n            {\r\n                options.Password.RequireDigit = false;\r\n                options.Password.RequireLowercase = false;\r\n                options.Password.RequiredLength = 3;\r\n                options.Password.RequireLowercase = false;\r\n                options.Password.RequireNonAlphanumeric = false;\r\n                options.Password.RequireUppercase = false;\r\n            }).AddEntityFrameworkStores&lt;TwoFactorAuthenticationContext&gt;().AddDefaultTokenProviders();\r\n            .\r\n            .\r\n            .\r\n        }\r\n        .\r\n        .\r\n        .\r\n    }\r\n<\/pre>\n<p>Tekrardan servis kodlar\u0131na d\u00f6nerek 19. sat\u0131ra g\u00f6z atarsan\u0131z e\u011fer do\u011frulama kodu onayland\u0131ktan sonra ilgili kullan\u0131c\u0131ya dair &#8220;TwoFactorEnabled&#8221; kolonunu true yaparak iki ad\u0131ml\u0131 kimlik do\u011frulama s\u00fcrecini aktifle\u015ftirmekteyiz. B\u00f6ylece ilgili kullan\u0131c\u0131 login olmaya \u00e7al\u0131\u015f\u0131rken direkt olarak sign in olamayacak yaz\u0131m\u0131z\u0131n ileriki sat\u0131rlar\u0131nda g\u00f6rece\u011fimiz \u00fczere bizden bir ikinci ad\u0131m do\u011frulama gerektirdi\u011fine dair bilgilendirmede bulunacakt\u0131r.<\/p>\n<p>20. sat\u0131rda ise &#8216;GenerateNewTwoFactorRecoveryCodesAsync&#8217; metodu ile ne olurrr ne olmazz durumlar\u0131na istinaden \u00f6nlem olmas\u0131 i\u00e7in 5 adet kurtarma kodu \u00fcretilmektedir \ud83d\ude42<\/p>\n<p>T\u00fcm bu s\u00fcre\u00e7te kullan\u0131lan &#8220;AuthenticatorVM&#8221; isimli viewmodel nesnesininde modeli a\u015fa\u011f\u0131daki gibi olacakt\u0131r;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthenticatorVM\r\n    {\r\n        public string SharedKey { get; set; }\r\n        public string QrCodeUri { get; set; }\r\n        public string VerificationCode { get; set; }\r\n    }\r\n<\/pre>\n<h5 style=\"color:green;\" id=\"adim5\">Ad\u0131m 5 &#8211; \u0130ki Ad\u0131ml\u0131 Do\u011frulaman\u0131n Onaylanmas\u0131<\/h5>\n<p>S\u0131rada &#8216;AuthenticatorService&#8217; i\u00e7erisinde olu\u015fturdu\u011fumuz &#8216;Verify&#8217; metodunu &#8216;TwoAuthenticationController&#8217; isimli controller s\u0131n\u0131f\u0131nda kullanmaya geldi.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class TwoAuthenticationController : Controller\r\n    {\r\n        AuthenticatorService _authenticatorService;\r\n        UserManager&lt;AppUser&gt; _userManager;\r\n        public TwoAuthenticationController(AuthenticatorService authenticatorService, UserManager&lt;AppUser&gt; userManager)\r\n        {\r\n            _authenticatorService = authenticatorService;\r\n            _userManager = userManager;\r\n        }\r\n        .\r\n        .\r\n        .\r\n        public async Task&lt;IActionResult&gt; AuthenticatorVerify()\r\n        {\r\n            AppUser user = await _userManager.FindByNameAsync(User.Identity.Name);\r\n            string sharedKey = await _authenticatorService.GenerateSharedKey(user);\r\n            string qrcodeUri = await _authenticatorService.GenerateQrCodeUri(sharedKey, &quot;www.gencayyildiz.com&quot;, user);\r\n\r\n            return View(new AuthenticatorVM\r\n            {\r\n                SharedKey = sharedKey,\r\n                QrCodeUri = qrcodeUri\r\n            });\r\n        }\r\n        &#x5B;HttpPost]\r\n        public async Task&lt;IActionResult&gt; AuthenticatorVerify(AuthenticatorVM model)\r\n        {\r\n            AppUser user = await _userManager.FindByNameAsync(User.Identity.Name);\r\n            VerifyState verifyState = await _authenticatorService.Verify(model, user);\r\n            if (verifyState.State)\r\n            {\r\n                TempData&#x5B;&quot;message2&quot;] = &quot;\u0130ki ad\u0131ml\u0131 do\u011frulama hesaba tan\u0131mlanm\u0131\u015ft\u0131r.&quot;;\r\n                TempData&#x5B;&quot;message3&quot;] = verifyState.RecoveryCode;\r\n            }\r\n            return View(model);\r\n        }\r\n    }\r\n<\/pre>\n<p>Bunun i\u00e7in 26. sat\u0131rda g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere action metodunun post t\u00fcr\u00fcnden &#8216;AuthenticatorVerify&#8217; overload&#8217;\u0131n\u0131 olu\u015fturuyoruz ve parametreden gelen post edilmi\u015f veriyi metot i\u00e7erisinde ilgili servisi kullanarak &#8216;Verify&#8217; ediyoruz.<\/p>\n<p>Bu i\u015flemden sonra art\u0131k ilgili kullan\u0131c\u0131 hesab\u0131 i\u00e7in iki ad\u0131ml\u0131 do\u011frulamay\u0131 aktifle\u015ftirebiliriz;<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-2.gif\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"800\" height=\"461\" class=\"alignnone size-full wp-image-14134\" \/><\/a><\/p>\n<h5 style=\"color:green;\" id=\"adim6\">Ad\u0131m 6 &#8211; Login Esnas\u0131nda \u0130kinci Do\u011frulama Sayfas\u0131na Y\u00f6nlendirme<\/h5>\n<p>Art\u0131k, bir \u00f6nceki ad\u0131mda &#8216;VerifyTwoFactorTokenAsync&#8217; metodu ile girilen kod do\u011fruland\u0131ktan ve ilgili kullan\u0131c\u0131n\u0131n &#8216;TwoFactorEnabled&#8217; de\u011feri true yap\u0131ld\u0131ktan sonra login esnas\u0131nda ikinci ad\u0131mda do\u011frulama yap\u0131lmas\u0131 gerekmektedir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-3.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-3-300x205.gif\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"300\" height=\"205\" class=\"alignleft size-medium wp-image-14136\" \/><\/a><br \/>\nAksi taktirde soldaki g\u00f6rselde g\u00f6r\u00fcld\u00fc\u011f\u00fc gibi giri\u015f yapmaya \u00e7al\u0131\u015f\u0131ld\u0131\u011f\u0131 halde ikinci do\u011frulama olmaks\u0131z\u0131n authorize olunmayacakt\u0131r.<\/p>\n<p>Bunun i\u00e7in &#8216;Login(Controller).cs&#8217; de a\u015fa\u011f\u0131daki gibi bir in\u015fan\u0131n yap\u0131lmas\u0131 gerekmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class LoginController : Controller\r\n    {\r\n        private readonly SignInManager&lt;AppUser&gt; _signInManager;\r\n        private readonly UserManager&lt;AppUser&gt; _userManager;\r\n        public LoginController(SignInManager&lt;AppUser&gt; signInManager, UserManager&lt;AppUser&gt; userManager)\r\n        {\r\n            _signInManager = signInManager;\r\n            _userManager = userManager;\r\n        }\r\n        public IActionResult Index(string ReturnUrl = &quot;&quot;)\r\n        {\r\n            return View();\r\n        }\r\n        &#x5B;HttpPost]\r\n        public async Task&lt;IActionResult&gt; Index(string ReturnUrl, UserSignVM model)\r\n        {\r\n            if (ModelState.IsValid)\r\n            {\r\n                AppUser user = await _userManager.FindByEmailAsync(model.Email);\r\n                if (user != null)\r\n                {\r\n                    Microsoft.AspNetCore.Identity.SignInResult result = await _signInManager.PasswordSignInAsync(user, model.Password, true, true);\r\n                    if (result.Succeeded)\r\n                    {\r\n                        if (string.IsNullOrEmpty(ReturnUrl))\r\n                            return RedirectToAction(&quot;Index&quot;, &quot;Home&quot;);\r\n                        return Redirect(ReturnUrl);\r\n                    }\r\n                    else if (result.RequiresTwoFactor)\r\n                        return RedirectToAction(&quot;twofactorauthenticate&quot;, new { ReturnUrl = ReturnUrl });\r\n                }\r\n            }\r\n            return View(model);\r\n        }\r\n        public async Task&lt;IActionResult&gt; TwoFactorAuthenticate(string ReturnUrl) =&gt; View();\r\n        &#x5B;HttpPost]\r\n        public async Task&lt;IActionResult&gt; TwoFactorAuthenticate(string ReturnUrl, TwoFactorLoginVM model)\r\n        {\r\n            AppUser user = await _signInManager.GetTwoFactorAuthenticationUserAsync();\r\n            Microsoft.AspNetCore.Identity.SignInResult result = null;\r\n            if (model.Recovery)\r\n                result = await _signInManager.TwoFactorRecoveryCodeSignInAsync(model.VerifyCode);\r\n            else\r\n                result = await _signInManager.TwoFactorAuthenticatorSignInAsync(model.VerifyCode, true, false);\r\n\r\n            if (result.Succeeded)\r\n                return Redirect(string.IsNullOrEmpty(ReturnUrl) ? &quot;\/home\/index&quot; : ReturnUrl);\r\n            else\r\n                ModelState.AddModelError(&quot;verifycode&quot;, &quot;Do\u011frulama kodu yanl\u0131\u015f girilmi\u015ftir!&quot;);\r\n\r\n            return View(model);\r\n        }\r\n        public async Task&lt;IActionResult&gt; Logout()\r\n        {\r\n            await _signInManager.SignOutAsync();\r\n            return RedirectToAction(&quot;Index&quot;, &quot;Login&quot;);\r\n        }\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki &#8216;Login(Controller).cs&#8217; i\u00e7eri\u011fini incelersek e\u011fer &#8216;Index&#8217; action\u0131n\u0131n post metoduna g\u00f6z atarsan\u0131z e\u011fer kullan\u0131c\u0131 sign in olmaya \u00e7al\u0131\u015ft\u0131\u011f\u0131nda &#8216;TwoFactorEnabled&#8217; kolonu true olaca\u011f\u0131ndan dolay\u0131 29. sat\u0131rdaki result nesnesinin &#8216;RequiresTwoFactor&#8217; propertysi true olarak gelecektir ve ikinci bir kimlik do\u011frulama yap\u0131laca\u011f\u0131n\u0131 bize bildirecektir. Dolay\u0131s\u0131yla bizde bu durumda kullan\u0131c\u0131y\u0131 &#8216;TwoFactorAuthenticate&#8217; isimli bir actiona y\u00f6nlendirmekte ve burada ikinci do\u011frulamay\u0131 ger\u00e7ekle\u015ftirmekteyiz. Birazdan view i\u00e7eri\u011fini g\u00f6rece\u011fimiz ilgili metodun 37. sat\u0131rda tan\u0131mlanm\u0131\u015f post t\u00fcr\u00fcne g\u00f6z atarsak e\u011fer modelden gelen &#8216;Recovery&#8217; bilgisine g\u00f6re kullan\u0131c\u0131n\u0131n girdi\u011fi kodun authenticator taraf\u0131ndan \u00fcretilmi\u015f do\u011frulama kodu mu yoksa kurtarma kodu mu olup olmad\u0131\u011f\u0131 ay\u0131rt ederek m\u00fcdahalede bulunmaktay\u0131z. E\u011fer kurtarma kodu ile oturum a\u00e7\u0131lmas\u0131n\u0131 istiyorsak &#8216;TwoFactorRecoveryCodeSignInAsync&#8217; metodunu yok e\u011fer normal do\u011frulama kodu ile oturum a\u00e7acaksak &#8216;TwoFactorAuthenticatorSignInAsync&#8217; metodunu kullanmal\u0131y\u0131z.<\/p>\n<p>Ayr\u0131ca <strong>ikinci do\u011frulama sayfas\u0131na gelindi\u011finde hangi kullan\u0131c\u0131ya do\u011frulama yap\u0131ld\u0131\u011f\u0131n\u0131 nereden anl\u0131yoruz?<\/strong> sorunuzu duyar gibiyim&#8230; Bunun i\u00e7in mimarimiz kullan\u0131c\u0131n\u0131n bilgisini &#8220;Identity.TwoFactorUserId&#8221; anahtar\u0131nda bir cookie de\u011feri olarak tutmakta ve 39. sat\u0131rda oldu\u011fu gibi &#8216;GetTwoFactorAuthenticationUserAsync&#8217; metodu ile ikinci sayfadaki cookie de\u011ferlerini okuyarak ilgili kullan\u0131c\u0131 nesnesini tekrar elde etmektedir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4.jpg\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"1042\" height=\"349\" class=\"alignnone size-full wp-image-14160\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4.jpg 1042w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4-300x100.jpg 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4-1024x343.jpg 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4-768x257.jpg 768w\" sizes=\"auto, (max-width: 1042px) 100vw, 1042px\" \/><\/a><\/p>\n<p>T\u00fcm bu yap\u0131lanma \u00fczerine ikinci do\u011frulama sayfas\u0131n\u0131n g\u00f6r\u00fcnt\u00fcs\u00fcn\u00fcde a\u015fa\u011f\u0131daki gibi olu\u015fturuyoruz;<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n@model TwoFactorLoginVM\r\n\r\n&lt;div class=&quot;row&quot;&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;form asp-action=&quot;TwoFactorAuthenticate&quot; method=&quot;post&quot;&gt;\r\n            &lt;div asp-validation-summary=&quot;All&quot;&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;label asp-for=&quot;VerifyCode&quot;&gt;&lt;\/label&gt;\r\n                &lt;input type=&quot;text&quot; class=&quot;form-control&quot; asp-for=&quot;VerifyCode&quot;&gt;\r\n                &lt;span asp-validation-for=&quot;VerifyCode&quot;&gt;&lt;\/span&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=&quot;form-group form-check&quot;&gt;\r\n                &lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; asp-for=&quot;Recovery&quot;&gt;\r\n                &lt;label class=&quot;form-check-label&quot; for=&quot;exampleCheck1&quot;&gt;Kurtarma kodu ile giri\u015f yapabilmek i\u00e7in bu kutucu\u011fu i\u015faretleyiniz.&lt;\/label&gt;\r\n            &lt;\/div&gt;\r\n            &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;Giri\u015f Yap&lt;\/button&gt;\r\n        &lt;\/form&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;&lt;\/div&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<h5 style=\"color:green;\" id=\"adim7\">Ad\u0131m 7 &#8211; Test Etme<\/h5>\n<p>T\u00fcm bu yap\u0131lanmay\u0131 derleyip \u00e7al\u0131\u015ft\u0131ral\u0131m ve a\u015fa\u011f\u0131daki gibi test edelim.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/Asp.NET-Core-Google-Microsoft-Authenticator-\u0130le-Two-Factor-Authentication-4.gif\" alt=\"Asp.NET Core - Google &amp; Microsoft Authenticator \u0130le Two Factor Authentication\" width=\"800\" height=\"435\" class=\"alignnone size-full wp-image-14154\" \/><\/a><br \/>\nG\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere gayet ba\u015far\u0131l\u0131 bir \u015fekilde \u00e7al\u0131\u015fmakta ve iki ad\u0131ml\u0131 do\u011frulamay\u0131 ger\u00e7ekle\u015ftirmektedir.<\/p>\n<p>Vee b\u00f6ylece blog hayat\u0131m boyunca \u015fu ana kadar olan en uzun makaleyi kaleme alm\u0131\u015f bulunmaktay\u0131m \ud83d\ude42 Eee b\u00f6yle bir konuyu anlatabilmek zor; okuyabilmek, okurken anlayabilmek ap ayr\u0131 bir zor&#8230; O y\u00fczden bu sat\u0131rlara eri\u015febilenlerin nezdinde okumaya c\u00fcret eden lakin sonunu getiremeyenlerde dahil hepinize sonsuz te\u015fekk\u00fcr ediyorum&#8230;<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek projeyi indirebilmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/03\/TwoFactorAuthentication.zip\">buraya<\/a> t\u0131klay\u0131n\u0131z.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Bir \u00f6nceki Two Factor Authentication Nedir? ba\u015fl\u0131kl\u0131 makalemizin akabinde art\u0131k Google &#038; Microsoft Authenticator ile iki ad\u0131ml\u0131 kimlik do\u011frulama y\u00f6ntemi \u00fczerine detayl\u0131 durabilir ve pratiksel a\u00e7\u0131dan t\u00fcm in\u015fa s\u00fcrecini irdeleyebiliriz. Microsoft &#038; Google&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":14035,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3102,2668,2656,2811,2832,2898,3103],"tags":[3252,3249,3254,3255,3256,3240,3250,3260,3253,2935,3237,3261,3258,3259],"class_list":["post-14039","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-net-core","category-asp-net-core-2","category-asp-net-core-2-mvc","category-asp-net-core-2-1","category-asp-net-core-2-2","category-asp-net-core-3-0","category-asp-net-core-3-1","tag-google-microsoft-authenticator","tag-google-authenticator","tag-hmac-based-one-time-password","tag-htop","tag-htop-algoritmasi","tag-iki-adimli-kimlik-dogrulama","tag-microsoft-authenticator","tag-rfc-6238","tag-shared-key","tag-timestamp","tag-two-factor-authentication","tag-unix-time-stamp","tag-zaman-bazli-tek-kullanimlik-sifre","tag-zaman-damgasi"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/14039","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=14039"}],"version-history":[{"count":108,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/14039\/revisions"}],"predecessor-version":[{"id":14161,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/14039\/revisions\/14161"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/14035"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=14039"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=14039"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=14039"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}