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

Asp.NET Core Identity – Şifremi Unuttum – XI

Merhaba,

Asp.NET Core Identity yazı dizimizin 11. makalesinde web sitemize üye olan kullanıcılar tarafından belirtilen şifrelerin -insanlık hali- unutulması durumunda kullanıcının nasıl yeni şifre talep edeceğini Identity mekanizması üzerinden inceleyeceğiz.

Süreçte bütünlüğü sağlayabilmek adına yazı dizimizde kullandığımız projemiz üzerinde geliştirme yapacağız.

Herşeyden önce uygulamada şifremi unuttum mekanizmasını inşa edebilmek için token provider yapılanmasını servis olarak dahil etmemiz gerekmektedir. Bunun için “Startup.cs” dosyasına giderek 21. satırda olduğu gibi “AddDefaultTokenProviders” metodunu eklememiz yeterlidir.

    public class Startup
    {
        public IConfiguration Configuration { get; set; }
        public Startup(IConfiguration configuration) => Configuration = configuration;
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(_ => _.UseSqlServer(Configuration["ConnectionStrings:SqlServerConnectionString"]));
            services.AddIdentity<AppUser, AppRole>(_ =>
            {
                _.Password.RequiredLength = 5; //En az kaç karakterli olması gerektiğini belirtiyoruz.
                _.Password.RequireNonAlphanumeric = false; //Alfanumerik zorunluluğunu kaldırıyoruz.
                _.Password.RequireLowercase = false; //Küçük harf zorunluluğunu kaldırıyoruz.
                _.Password.RequireUppercase = false; //Büyük harf zorunluluğunu kaldırıyoruz.
                _.Password.RequireDigit = false; //0-9 arası sayısal karakter zorunluluğunu kaldırıyoruz.

                _.User.RequireUniqueEmail = true; //Email adreslerini tekilleştiriyoruz.
                _.User.AllowedUserNameCharacters = "abcçdefghiıjklmnoöpqrsştuüvwxyzABCÇDEFGHIİJKLMNOÖPQRSŞTUÜVWXYZ0123456789-._@+"; //Kullanıcı adında geçerli olan karakterleri belirtiyoruz.
            }).AddPasswordValidator<CustomPasswordValidation>()
              .AddUserValidator<CustomUserValidation>()
              .AddErrorDescriber<CustomIdentityErrorDescriber>().AddEntityFrameworkStores<AppDbContext>()
              .AddDefaultTokenProviders(); 

            services.ConfigureApplicationCookie(_ =>
            {
                _.LoginPath = new PathString("/User/Login");
                _.Cookie = new CookieBuilder
                {
                    Name = "AspNetCoreIdentityExampleCookie", //Oluşturulacak Cookie'yi isimlendiriyoruz.
                    HttpOnly = false, //Kötü niyetli insanların client-side tarafından Cookie'ye erişmesini engelliyoruz.
                    Expiration = TimeSpan.FromMinutes(2), //Oluşturulacak Cookie'nin vadesini belirliyoruz.
                    SameSite = SameSiteMode.Lax, //Top level navigasyonlara sebep olmayan requestlere Cookie'nin gönderilmemesini belirtiyoruz.
                    SecurePolicy = CookieSecurePolicy.Always //HTTPS üzerinden erişilebilir yapıyoruz.
                };
                _.SlidingExpiration = true; //Expiration süresinin yarısı kadar süre zarfında istekte bulunulursa eğer geri kalan yarısını tekrar sıfırlayarak ilk ayarlanan süreyi tazeleyecektir.
                _.ExpireTimeSpan = TimeSpan.FromMinutes(2); //CookieBuilder nesnesinde tanımlanan Expiration değerinin varsayılan değerlerle ezilme ihtimaline karşın tekrardan Cookie vadesi burada da belirtiliyor.
            });

            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseStatusCodePages();
            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseMvc(_ => _.MapRoute("Default", "{controller=Home}/{action=Index}/{id?}"));
        }
    }

Bu temel konfigürasyondan sonra kullanıcının ihtiyaca binaen yeniden şifre talep edebilmesi için “Şifremi Unuttum” sayfasını tasarlayalım.

Şifremi Unuttum Sayfasının Tasarlanması

İlk olarak uygulamamızın “Models” -> “ViewModels” klasörü altında yeni şifre talebi esnasında veriyi karşılayabilmek için “ResetPasswordViewModel” isminde bir viewmodel tasarlıyoruz.

    public class ResetPasswordViewModel
    {
        [Display(Name = "E-Posta Adresiniz")]
        [Required(ErrorMessage = "Lütfen e-posta adresinizi boş geçmeyiniz.")]
        [EmailAddress(ErrorMessage = "Lütfen uygun formatta e-posta giriniz.")]
        public string Email { get; set; }
    }

Ardından “User(Controller).cs” controller sınıfı içerisinde ilgili talebi yöneteceğimiz “PasswordReset” isimli bir action oluşturuyoruz ve aşağıdaki gibi geliştiriyoruz.

    public class UserController : Controller
    {
        readonly UserManager<AppUser> _userManager;
        readonly SignInManager<AppUser> _signInManager;
        public UserController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }
        public IActionResult PasswordReset()
        {
            return View();
        }
        [HttpPost]
        public async Task<IActionResult> PasswordReset(ResetPasswordViewModel model)
        {
            AppUser user = await _userManager.FindByEmailAsync(model.Email);
            if (user != null)
            {
                string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);

                MailMessage mail = new MailMessage();
                mail.IsBodyHtml = true;
                mail.To.Add(user.Email);
                mail.From = new MailAddress("******@gmail.com", "Şifre Güncelleme", System.Text.Encoding.UTF8);
                mail.Subject = "Şifre Güncelleme Talebi";
                mail.Body = $"<a target=\"_blank\" href=\"https://localhost:5001{Url.Action("UpdatePassword", "User", new { userId = user.Id, token = HttpUtility.UrlEncode(resetToken) })}\">Yeni şifre talebi için tıklayınız</a>";
                mail.IsBodyHtml = true;
                SmtpClient smp = new SmtpClient();
                smp.Credentials = new NetworkCredential("*****@gmail.com", "******");
                smp.Port = 587;
                smp.Host = "smtp.gmail.com";
                smp.EnableSsl = true;
                smp.Send(mail);

                ViewBag.State = true;
            }
            else
                ViewBag.State = false;

            return View();
        }
        .
        .
        .
        //diğer actionlar
        .
        .
        .
    }

Yukarıdaki kod bloğunda, birazdan view içeriğinide göreceğimiz “PasswordReset” actionı geliştirilmiştir. Yapılan post neticesinde kullanıcı tarafından doğru email adresi girilmişse eğer 20. satırda “GeneratePasswordResetTokenAsync” metodu ile kullanıcıya özel token değeri üretilmektedir. Hemen ardından üretilen bu değer user id değeri ile birlikte oluşturulan bir update linkine query string olarak eklenmekte ve ilgili url yeni şifre talep eden kullanıcının email adresine gönderilmektedir. Dolayısıyla kullanıcı url üzerinden gönderilen token değerinin güvencesiyle kendisine ait hesaba dair şifreyi güncelleyebilecektir.

Evet… Burada email yapılanmasını farklı bir katmanda tasarlamak daha doğru olabilir. Lakin örneklendirmeyi fazla parçalamamak adına olması gereken bu durumu sizlere bırakıyorum…

Şimdide “PasswordReset” actionının view’ini görelim.

@model AspNetCoreIdentityExample.Models.ViewModels.ResetPasswordViewModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h3>Şifremi Unuttum</h3>

<hr />
@if (ViewBag.State == null)
{
    <form asp-action="PasswordReset">
        <table>
            <tr>
                <td colspan="3"><div asp-validation-summary="All"></div></td>
            </tr>
            <tr>
                <td><label asp-for="Email"></label></td>
                <td><input asp-for="Email" /></td>
                <td><span asp-validation-for="Email"></span></td>
            </tr>
            <tr>
                <td colspan="3"><input type="submit" value="Yeni Şifre Talebi Gönder" /></td>
            </tr>
        </table>
    </form>
}
else
{
    if (ViewBag.State)
    {
        @:<div class="alert-success">Şifre talebi için e-posta adresinize bilgilerindirici mail gönderilmiştir.</div>
    }
    else
    {
        @:<div class="alert-success">Böyle bir e-posta bulunmamaktadır.</div>
    }
}

Evet, artık şifreyi güncelleme işlemini operasyonel olarak gerçekleştirecek “UpdatePassword” action metodunu tasarlayabiliriz.

Şifreyi Güncelleme Sayfasının Tasarlanması

Kullanıcı tarafımızca mail üzerinden gönderilen url’e tıkladığı vakit yeni şifresini belirleyebilmek için “UpdatePassword” action metodu tarafından karşılanacaktır. Dolayısıyla ilk olarak kullanıcının girdiği şifreyi taşıması için “UpdatePasswordViewModel” isminde bir viewmodel tasarlayalım.

    public class UpdatePasswordViewModel
    {
        [Display(Name = "Yeni Şifre")]
        [Required(ErrorMessage = "Lütfen şifreyi boş geçmeyiniz.")]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }

Ardından “UpdatePassword” action metodunu inşa edelim.

    public class UserController : Controller
    {
        readonly UserManager<AppUser> _userManager;
        readonly SignInManager<AppUser> _signInManager;
        public UserController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }
        [HttpGet("[action]/{userId}/{token}")]
        public IActionResult UpdatePassword(string userId, string token)
        {
            return View();
        }
        [HttpPost("[action]/{userId}/{token}")]
        public async Task<IActionResult> UpdatePassword(UpdatePasswordViewModel model, string userId, string token)
        {
            AppUser user = await _userManager.FindByIdAsync(userId);
            IdentityResult result = await _userManager.ResetPasswordAsync(user, HttpUtility.UrlDecode(token), model.Password);
            if (result.Succeeded)
            {
                ViewBag.State = true;
                await _userManager.UpdateSecurityStampAsync(user);
            }
            else
                ViewBag.State = false;
            return View();
        }
    }
    .
    .
    .
    //diğer actionlar
    .
    .
    .

Görüldüğü üzere kullanıcıya gönderilen e-postadaki urle tıklandığı vakit query string olarak belirtilen userId ve token değerleri “UpdatePassword” action metodu tarafından yakalanmakta ve TempData‘ya atılmaktadır. Post neticesinde “UpdatePasswordViewModel” parametresi kullanıcı tarafından girilen yeni şifreyi taşımaktadır ve 19. satırda olduğu gibi “ResetPasswordAsync” metodu ile token değeri kontrolünde şifre güncellemesi gerçekleştirilmektedir. 23. satırda ise ana değerlerden biri olan şifrenin değişmesinden dolayı “UpdateSecurityStampAsync” metodu aracılığıyla ilgili kullanıcının SecurityStamp kolonu yeni bir değerle güncellenmiştir. Böylece önceki üretilen cookie değerleri çürütülmüştür.

“UpdatePassword” actionının view dosyasınıda incelersek eğer;

@model AspNetCoreIdentityExample.Models.ViewModels.UpdatePasswordViewModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h3>Şifremi Unuttum</h3>

<hr />
@if (ViewBag.State == null)
{
    <form asp-action="UpdatePassword">
        <table>
            <tr>
                <td colspan="3"><div asp-validation-summary="All"></div></td>
            </tr>
            <tr>
                <td><label asp-for="Password"></label></td>
                <td><input asp-for="Password" /></td>
                <td><span asp-validation-for="Password"></span></td>
            </tr>
            <tr>
                <td colspan="3"><input type="submit" value="Şifreyi Güncelle" /></td>
            </tr>
        </table>
    </form>
}
else
{
    if (ViewBag.State)
    {
        @:<div class="alert-success">Şifre başarıyla güncellenmiştir.</div>
    }
    else
    {
        @:<div class="alert-success">Şifreyi güncellerken beklenmeyen hatayla karşılaşıldı.</div>
    }
}

şeklinde olacaktır.

Artık uygulamanın bu son halini kaydedip, derlediğiniz vakit aşağıdaki gibi şifremi unuttum mekanizmasının çalıştığını gözlemleyebilirsiniz.
Asp.NET Core Identity - Şifremi Unuttum - XI

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

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

Bunlar da hoşunuza gidebilir...

57 Cevaplar

  1. Şenol dedi ki:

    Merhaba Hocam,

    Şifre yenileme talebi için e-postaya gelen mail’e tıkladığımda
    ” HTTP Error 404.11 – Not Found
    İstek filtreleme modülü çift kaçış sırası içeren bir isteği reddedecek şekilde yapılandırıldı.” hatası alıyorum.
    Nasıl düzeltebilirim.

  2. Şenol dedi ki:

    hocam size gonderdiğim kod engelleniyor heralde

  3. Şenol dedi ki:

    Görüntü kabul etmiyor bu alan.

  4. Şenol dedi ki:

    Mail atmıştım size ordan bakabilir misiniz?

  5. Şenol dedi ki:

    Size gönderdiğim fotoğrafa sığması için böyle yazmıştım. Normalde kod tek satırda yazılı. Örnek URL’e burdan ulaşabilirsiniz:
    https://ibb.co/X8zHQ39

    • Gençay dedi ki:

      Url’i görsel olarak tam görememekteyim. Lütfen metin olarak paylaşınız. Ya da siz URL’de özellikle “+” operatörü ya da benzeri var mı kontrol ediniz. Hatanın sebebi url’de ki bu tarz bir karakterin olması olabilir.

  6. Şenol dedi ki:

    https://localhost:44330/UpdatePassword/94519abf-d22a
    -45ed-88ec-c61e3afdc913/CfDJ8Cv5GzmHKPNMjkS%252byklWmBHnf0x
    cfJZZ0zfRCM9S2yGZLMUmoeSL2YQSJOJ9uJdjhnAYw0cd35Y8k4
    rcEX%252b1VvY09hKlQqLIwMsryPlhNwXfEDmovG6UaC%252fW0rnC
    TPlF55C3%252bwE%252f5iPBSDM9GpiibAYh1L%252fn6LpxTXtl4pJqYb
    %252fWNJKM360QulZD6IJBVep7PUmIZEfQUro0saLx4Uvhdq2qZqvpuSEtNpqccXR%252fGJ1j

  7. dgc dedi ki:

    merhaba hocam bu sorunun çözümü için yardımcı olabilir misiniz?

    • Gençay dedi ki:

      Merhaba,

      Hangi sorunun çözümü için yardım istiyorsunuz?

      • dgc dedi ki:

        Şifre yenileme talebi için e-postaya gelen mail’e tıkladığımda
        ” HTTP Error 404.11 – Not Found
        İstek filtreleme modülü çift kaçış sırası içeren bir isteği reddedecek şekilde yapılandırıldı.” hatasını bende alıyorum ve bu hatanın oluşan url in token değerinde özel karakterlerin bulunmasından kaynaklı olduğu için hata veriyor fakat bu özel karakterleri nasıl ortadan kaldırırım veya nasıl bu şekilde çalışmasına izin verilir bunu bulamadım.

  8. ishak dedi ki:

    Sorunun çözümü :

    byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(resetToken);
    var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
    

    ve

    var codeDecodedBytes = WebEncoders.Base64UrlDecode(UID);
    var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
    

    bunlar ile değiştirin.

    • Gençay dedi ki:

      Teşekkürler.

      • ishak dedi ki:

        Ben teşekkür ederim aslında bu güzel bilgileri bizimle paylaştığınız için.

        • Gençay dedi ki:

          Çok sağol İshak kardeşim 🙂

          • Berkay dedi ki:

            Hocam aynı hatayı alıyorum bu code decoded ve encoded ları nerede değiştireceğiz hiç anlamadım projede öyle bi kod parçacığım yok malesef

          • Gençay dedi ki:

            İshak Beyin şuradaki çözümüyle alakalı sorun yaşıyor olabilirsin. İncelemeni öneririm.

        • Berkay dedi ki:

          Hocam inceledim fakat anlamadigim nokta şurası bu posttaki şekilde yapilandirdim kodumu fakatnencode ve decode yaptigim bir alan yok ishak bey encode ve decode yapiyor nereye ekleyecegimi bilemedim ishak beyin çöźümünü

          • Yunus dedi ki:

            Berkay bey aynı problemi bende yaşıyorum . Yani posttaki yapıda İshak beyin çözümünü nerede yapacağımızı bulamadım. Yapan varsa bilgilendirebilir mi?

  9. fatih dedi ki:

    mrhba efendim bu ıdenty kodunun tamamını git de palaşırmısnz bu mailden cevap yazarsanız sevinirim

  10. Berkay dedi ki:

    Hocam selamlar,

    PasswordReset Actionunda smp.send(mail) kısmında hata almaktayım.
    hata şu şekilde;
    ///////
    An unhandled exception occurred while processing the request.
    SocketException: Bilinen böyle bir ana bilgisayar yok
    System.Net.Dns.InternalGetHostByName(string hostName)

    SmtpException: Failure sending mail.
    System.Net.Mail.SmtpClient.Send(MailMessage message)
    /////

    ViewBag.state=true da patlıyor. sanırım bunun nedeni SmtpClient in config tarafında sorun var fakat her bilgi doğru yazdığımı düşünüyorum.

    public async Task PasswordReset(ResetPasswordViewModel model)
            {
                CustomIdentityUser user = await _userManager.FindByEmailAsync(model.Email);
                if (user != null)
                {
                    string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);
    
                    MailMessage mail = new MailMessage();
                    mail.IsBodyHtml = true;
                    mail.To.Add(user.Email);
                    mail.From = new MailAddress("******@gmail.com", "Şifre Güncelleme", System.Text.Encoding.UTF8);
                    mail.Subject = "Şifre Güncelleme Talebi";
                    mail.Body = $"<a>Yeni şifre talebi için tıklayınız</a>";
                    mail.IsBodyHtml = true;
                    SmtpClient smp = new SmtpClient();
                    smp.Credentials = new NetworkCredential("info@bilisimkampusu.com", "*****");
                    smp.Port = 587;
                    smp.Host = "smtp.bilisimkampusu.com";
                    smp.EnableSsl = true;
                    smp.Send(mail);
    
                    ViewBag.State = true;
                }
                else
                    ViewBag.State = false;
    
                return View();
            }
    
  11. Furkan oktay dedi ki:

    Selamün aleyküm

  12. Enis dedi ki:

    Kolay gelsin başlığı core olarak açmışsınız ama .net frameworkta kodlar çalışıyormu bilginiz varmı?

    • Gençay dedi ki:

      Merhaba,

      Bu yazı serisinde sadece .NET Core’a uygun bir anlatım sergilenmiştir. .NET Framework’te de çalışmaların benzer niteliklerde sergilenebileceği kanaatindeyim.

  13. latif dedi ki:

    mail.Body = $”Yeni şifre talebi için tıklayınız”;

  14. Sadık dedi ki:

    Hocam merhaba,

    “GeneratePasswordResetTokenAsync” metodu ile oluşturulan token’ınımız (userId, token,expireTime gibi bilgilerle) bir cookie’de tutuluyor değil mi?

    İyi çalışmalar.

    • Gençay dedi ki:

      Merhaba,

      İlgili fonksiyon neticesinde SecurityStamp değeriyle doğrulanabilir bir token oluşturuluyor. Haliyle bizler token’ı doğruladıktan sonra ilgili ‘SecurityStamp’ değerini güncelliyoruz.

  15. yasin dedi ki:

    else
    ViewBag.State = false;
    return View();
    BURAYA GELİYOR YADA 404.11

  16. yasin dedi ki:

    Sorunun çözümü :

    1
    2
    byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(resetToken);
    var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
    ve

    1
    2
    var codeDecodedBytes = WebEncoders.Base64UrlDecode(UID);
    var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);

    nedir??

  17. iHSAK dedi ki:

    Sa Hocam Bir Sorum Var

  18. cihan dedi ki:

    .Net core 5 İdentity içerisinde Resetpassword kullanıyorum mail bağlantısı ile sifre sıfırlama ekranına geliyorum fakat orda şifre sıfırlarken invalid token hatası alıyorum. neden olabilir .

  19. Bülent dedi ki:

    merhabalar gençay hocam
    konuyu çok güzel anlatmışsınız elinize sağlık
    yalnız kafama takılan bir konu var bu email adresine gönderilen token değeri veritabanında yada başka bir yerde depolanmıyormu çünkü ben emaile gelen tokena tıkladığımda action metoda gelen token parametresini emaile gönderilen tokenla karşılaştırması yapılmayacakmı
    eğer vaktiniz olurda cevaplarsanız çok memnun olurum

    • Gençay dedi ki:

      Merhaba,

      Hayır, token karşılaştırmasından ziyade o token’ı çözümseyecek değerlere ihtiyacınız olacaktır. Asp.NET Core Identity mekanizmasında bu değer(ler)i AspNetUsers tablosundaki SecurityStamp kolonu sağlamaktadır. Siz, SecurityStamp değeri ile ürettiğiniz token’ı email üzerinden gönderdikten sonra kullanıcı bu token ile dönüş yapıyorsa tekrar SecurityStamp ile gelen değeri çözümser ve kontrol edersiniz. Tabi burada bu kontrol sürecini ResetPasswordAsync fonksiyonu üstlenmektedir. Hatta ilgili token doğrulanıp şifre yenilendiği taktirde UpdateSecurityStampAsync metodu ile mevcudiyetteki SecurityStamp değeri güncellenerek üretilmiş token eskitilmiş olur.

  20. Kazım dedi ki:

    HTTP Error 404.11 – Not Found
    İstek filtreleme modülü çift kaçış sırası içeren bir isteği reddedecek şekilde yapılandırıldı. Bu şekilde hata alıyorum çözebilen var mı

  21. Ünsal Gel dedi ki:
     using BusinessLayer.Concrete;
    using CoreProje.Models;
    using DataAccesLayer.Concrete;
    using DataAccesLayer.EntityFramework;
    using EntityLayer.Concrete;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.WebUtilities;
    using Newtonsoft.Json.Linq;
    using System.Data;
    using System.Linq;
    using System.Net;
    using System.Net.Mail;
    using System.Net.NetworkInformation;
    using System.Text;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace CoreProje.Controllers
    {
        [AllowAnonymous]
        public class ResetPasswordController : Controller
        {
            readonly UserManager<WriterUser> _userManager;
            readonly SignInManager<WriterUser> _signInManager;
    
            public ResetPasswordController(UserManager<WriterUser> userManager, SignInManager<WriterUser> signInManager)
            {
                _userManager=userManager;
                _signInManager=signInManager;
            }
            [HttpGet]
            public IActionResult PasswordReset()
            {
                return View();
            }
           [HttpPost]
            public async Task<IActionResult> PasswordReset(ResetPasswordViewModel model)
            {
                WriterUser User = await _userManager.FindByEmailAsync(model.Email);
                if (User != null)
                {
                    string resetToken=await _userManager.GeneratePasswordResetTokenAsync(User);
                    byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(resetToken);
                    var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
                    MailMessage mail=new MailMessage();
                    mail.IsBodyHtml= true;  
                    mail.To.Add(User.Email);
                    mail.From=new MailAddress("unsal.gel@outlook.com", "Şifre Güncelleme", System.Text.Encoding.UTF8);
                    mail.Subject = "Şifre Güncelleme Talebi";
                    mail.Body = $"<a target=\"_blank\" href=\"https://localhost:44308{Url.Action("UpdatePassword", "ResetPassword", new { userId = User.Id, token = codeEncoded })}\">Yeni şifre talebi için tıklayınız</a>";
                    mail.IsBodyHtml = true;
                    SmtpClient smtpClient = new SmtpClient();
                    smtpClient.Credentials=new NetworkCredential("mail adresiniz", "eposta şifreniz");
                    smtpClient.Port=587;
                    smtpClient.Host="smtp-mail.outlook.com";
                    smtpClient.EnableSsl=true;
                    smtpClient.Send(mail);
                    ViewBag.State = true;
                }
                else
                    ViewBag.State = false;
           
                return View();
            }
            //[HttpGet]
            [HttpGet("[controller]/[action]/{userID}/{Token}")]
            public IActionResult UpdatePassword(string userID, string Token)
            {
             
                return View();
            }
           // [HttpPost]
            [HttpPost("[controller]/[action]/{userID}/{Token}")]
            public async Task<IActionResult> UpdatePassword(UpdatePasswordViewModel model,string userID, string Token)
            {
                WriterUser user = await _userManager.FindByIdAsync(userID);
                var codeDecodedBytes = WebEncoders.Base64UrlDecode(Token);
                var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
    
                IdentityResult result = await _userManager.ResetPasswordAsync(user, codeDecoded, model.Password);
                if (result.Succeeded)
                {
                    ViewBag.State = true;
                    await _userManager.UpdateSecurityStampAsync(user);
                }
                else
                    ViewBag.State = false;
                return View();
            }
        }
    }
    
    

    bu şekilde sorun çözülüyor yinede Bad Request – Invalid URL – HTTP Error 400. hatası alırsanız bilgisayarınızın başlat kısmında arama yerine powershell yazın açılan mavi consoleda Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\HTTP\Parameters -Name UrlSegmentMaxLength -Value 2000 -Type “Dword” bu kodu yazıp entera basın daha sonra net stop http yazın kapanınca bide net start http yazın kapandıktan sonra açılmassa bilgisayarı yeniden başlatın otomatik açılıyor ve sorun çözülüyor değerli bilgileri için hocama teşekkür ederim..

  22. Ünsal Gel dedi ki:
      [HttpGet]
            public IActionResult PasswordReset()
            {
                return View();
            }
           [HttpPost]
            public async Task PasswordReset(ResetPasswordViewModel model)
            {
                WriterUser User = await _userManager.FindByEmailAsync(model.Email);
                if (User != null)
                {
                    string resetToken=await _userManager.GeneratePasswordResetTokenAsync(User);
                    byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(resetToken);
                    var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
                    MailMessage mail=new MailMessage();
                    mail.IsBodyHtml= true;  
                    mail.To.Add(User.Email);
                    mail.From=new MailAddress("unsal.gel@outlook.com", "Şifre Güncelleme", System.Text.Encoding.UTF8);
                    mail.Subject = "Şifre Güncelleme Talebi";
                    mail.Body = $"<a>Yeni şifre talebi için tıklayınız</a>";
                    mail.IsBodyHtml = true;
                    SmtpClient smtpClient = new SmtpClient();
                    smtpClient.Credentials=new NetworkCredential("mail adresiniz", "şifreniz");
                    smtpClient.Port=587;
                    smtpClient.Host="smtp-mail.outlook.com";
                    smtpClient.EnableSsl=true;
                    smtpClient.Send(mail);
                    ViewBag.State = true;
                }
                else
                    ViewBag.State = false;
           
                return View();
            }
       
            [HttpGet("[controller]/[action]/{userID}/{Token}")]
            public IActionResult UpdatePassword(string userID, string Token)
            {
             
                return View();
            }
          
            [HttpPost("[controller]/[action]/{userID}/{Token}")]
            public async Task UpdatePassword(UpdatePasswordViewModel model,string userID, string Token)
            {
                WriterUser user = await _userManager.FindByIdAsync(userID);
                var codeDecodedBytes = WebEncoders.Base64UrlDecode(Token);
                var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
                IdentityResult result = await _userManager.ResetPasswordAsync(user, codeDecoded, model.Password);
                if (result.Succeeded)
                {
                    ViewBag.State = true;
                    await _userManager.UpdateSecurityStampAsync(user);
                }
                else
                    ViewBag.State = false;
                return View();
            }
    

    yinede çalışmaz da Bad Request – Invalid URL hatası alırsanız başlat çubuğundan arama yerine powershell yazıp açılan komut satırında Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\HTTP\Parameters -Name UrlSegmentMaxLength -Value 2000 -Type “Dword” bu kodu yapıştırıp çalıştırın daha sonra yine aynı komut satırında net stop http yazıp enter’a basın kapandıktan sonra net start http yazın ve açın yani aslında yeniden başlatıyoruz oldu ki başlamassa bilgisayarı yeniden başlatın ve artık projeyi açıp denediğinizde sorun çözülmüş olacaktır 🙂

  23. Selçuk dedi ki:

    İyi günler Hocam mail gönderimi için kendi kişisel gmail adresimi kullandım fakat smtp hatası oldum hatanın sebebi gmail hesabımda ayarlardan daha az güvenlikli uygulamalara izin ver durumunu açmamam imiş fakat google 30 mayıs 2022 tarihinde bu hizmeti kapatmış yani istesek de bu ayarı kişisel gmail hesabımızda açıp kullanamıyoruz.

  24. Adil dedi ki:

    Merhaba hocam. Ilk once rahatsizlik verdiyim icin ve sorumun garip gele bileceyinden dolayi onceden ozur diliyorum.

    Identity-nin simdiki bolumunde kullandigimiz ‘token’ kelmesi tam olarak ne anlama gelmekte? ‘token’ , ‘token yaratmak’ soylediyim zaman aklimda bir sey canlanmiyor. Rica etsem tokenin turkcede tam olarak ne anlama geldiyini soylermisiniz? Tesekkur ederim.

    google-da bir kac yere baktim anlamadim, mesela karsima ilk cikan aciklama:
    _________________________
    Tokens are used in Identity in several ways. You can use them to reset a password or confirm the email address of a user. Here you generate a token specific for the appropriate user which can be used for these two purposes. They will be send to the user, for example as a link to a view which handles the confirmation.

    * aciklamanin kaynagi : https://stackoverflow.com/questions/27677345/what-are-a-security-token-and-security-stamp-in-asp-net-identity#:~:text=Tokens%20are%20used%20in%20Identity,view%20which%20handles%20the%20confirmation.
    _________________________

    * Bu arada “gmail.com” ve “mail.ru”-dan mail atmak bende calismadi, farkli portlar ve saire denedim, olmuyor, maksimum ulastigim sonuc Timeout almak oldu 😀 onun yerine maili Hotmaildan attim usere asagida yazdigim sekilde (arayan olursa benim gibi, boyle yapa bilir). Gmaildan mail ata bilen banada soylerse mutlu olurum.

    + Attigimiz mail userin mailinde ‘Spam’ folderina dusuyor.

    [HttpPost]
    public async Task PasswordReset(ResetPasswordViewModel model) 
    {
        AppUser user = await UserManager.FindByEmailAsync(model.Email);
    
        if (user != null)
        {
            string resetToken = await UserManager.GeneratePasswordResetTokenAsync(user);
    
            MailMessage mail = new MailMessage
            {
                From = new MailAddress("BenimHotmailAdresim@gmail.com", "Şifre Güncelleme", System.Text.Encoding.UTF8),
                Subject = "Şifre Güncelleme Talebi",
                IsBodyHtml = true,
                Body = $"<a>Yeni şifre talebi için tıklayınız</a>",
            };
            mail.To.Add(user.Email);
    
            SmtpClient smtpClient = new SmtpClient
            {
                EnableSsl = true,
                Host = "smtp-mail.outlook.com",
                Port =  587,  // 25,  465,
                Timeout = 60000, // 60 saniye
                UseDefaultCredentials = false,
                Credentials = new NetworkCredential("BenimHotmailAdresim@gmail.com", "BenimHotmailPasswordum")
            };
    
            smtpClient.Send(mail);
            smtpClient.Dispose();
    
            ViewBag.State = true;
        }
        else { ViewBag.State = false; }
    
        return View();
    }
    
  1. 30 Ağustos 2019

    […] Asp.NET Core Identity – Şifremi Unuttum – XI […]

  2. 01 Eylül 2019

    […] ‘şifremi unuttum‘ senaryolarında kullanıcının şifreyi resetlemesi için üretilen token değerini […]

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir