C# ile ASP.NET Core Identity: Güvenli Kimlik Doğrulama Sistemi Rehberi
Modern web uygulamalarında güvenli kimlik doğrulama ve yetkilendirme sistemleri oluşturmak, yazılım geliştirme sürecinin en kritik adımlarından biridir. ASP.NET Core Identity, Microsoft tarafından geliştirilen ve bu ihtiyacı karşılayan güçlü bir framework’tür. Bu kapsamlı rehberde, C# ile ASP.NET Core Identity’nin tüm yönlerini detaylı kod örnekleriyle inceleyeceğiz.

Kullanıcı kaydı, giriş işlemleri, rol yönetimi, claims tabanlı yetkilendirme ve token işlemlerinden clean architecture entegrasyonuna kadar her konuyu ele alacağız.
ASP.NET Core Identity Nedir?
ASP.NET Core Identity, kullanıcı hesapları, şifreler, roller ve yetkilendirme işlemlerini yönetmek için tasarlanmış bir üyelik sistemidir. Eski ASP.NET Membership sisteminin modern ve genişletilebilir halidir. Entity Framework Core ile entegre çalışır ve veritabanı işlemlerini otomatik olarak yönetir.
Identity framework’ü, kullanıcı kaydı, giriş-çıkış işlemleri, şifre sıfırlama, email doğrulama, iki faktörlü kimlik doğrulama (2FA) ve dış kimlik sağlayıcı entegrasyonları gibi temel özellikleri hazır olarak sunar. Bu sayede sıfırdan güvenlik altyapısı geliştirmek yerine, doğrudan iş mantığınıza odaklanabilirsiniz.
Neden ASP.NET Core Identity Kullanmalıyız?
ASP.NET Core Identity kullanmanın birçok avantajı vardır. Framework, endüstri standartlarına uygun şifre hashleme algoritmaları kullanır ve güvenlik en iyi pratiklerini varsayılan olarak uygular. Claims-based kimlik doğrulama modeli sayesinde esnek yetkilendirme senaryoları oluşturabilirsiniz. Ayrıca, Entity Framework Core ile tam entegrasyon sayesinde özelleştirilebilir veri modellerine sahip olursunuz.

Identity Kurulumu ve Yapılandırması
ASP.NET Core Identity’yi projenize entegre etmek için öncelikle gerekli NuGet paketlerini yüklemeniz gerekir. Visual Studio’da Package Manager Console üzerinden veya .NET CLI kullanarak bu paketleri projenize ekleyebilirsiniz.
Gerekli NuGet Paketleri
İlk adım olarak aşağıdaki NuGet paketlerini yükleyin:
// Package Manager Console'da
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
Bu paketler, Identity framework’ünün Entity Framework Core ile çalışması için gerekli tüm bileşenleri içerir. EntityFrameworkCore.SqlServer paketi SQL Server veritabanı desteği sağlarken, EntityFrameworkCore.Tools migration işlemleri için gereklidir.
DbContext Yapılandırması
Identity kullanmak için öncelikle IdentityDbContext‘ten türeyen bir veritabanı context sınıfı oluşturmalısınız:
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Tablo isimlerini özelleştirme (opsiyonel)
builder.Entity<ApplicationUser>().ToTable("Users");
builder.Entity<IdentityRole>().ToTable("Roles");
builder.Entity<IdentityUserRole<string>>().ToTable("UserRoles");
builder.Entity<IdentityUserClaim<string>>().ToTable("UserClaims");
builder.Entity<IdentityUserLogin<string>>().ToTable("UserLogins");
builder.Entity<IdentityRoleClaim<string>>().ToTable("RoleClaims");
builder.Entity<IdentityUserToken<string>>().ToTable("UserTokens");
}
}
Bu yapılandırma sayesinde Identity’nin varsayılan tablo isimlerini Türkçe veya kendi isimlendirme standartlarınıza göre özelleştirebilirsiniz. OnModelCreating metodu içinde Fluent API kullanarak daha detaylı veritabanı yapılandırmaları yapabilirsiniz.
Program.cs Yapılandırması
ASP.NET Core 6.0 ve sonrası için Program.cs dosyasında Identity servislerini aşağıdaki şekilde yapılandırın:
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// DbContext yapılandırması
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// Identity servisleri
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
// Şifre gereksinimleri
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequiredLength = 8;
// Kullanıcı gereksinimleri
options.User.RequireUniqueEmail = true;
// Lockout ayarları
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// SignIn ayarları
options.SignIn.RequireConfirmedEmail = true;
options.SignIn.RequireConfirmedPhoneNumber = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Cookie ayarları
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = "/Account/AccessDenied";
options.ExpireTimeSpan = TimeSpan.FromDays(7);
options.SlidingExpiration = true;
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Bu yapılandırma, güvenli bir kimlik doğrulama sistemi için gerekli tüm ayarları içerir. Şifre politikaları, hesap kilitleme kuralları ve cookie güvenlik seçenekleri detaylı şekilde yapılandırılmıştır.
Özel Kullanıcı Modeli Oluşturma
Varsayılan IdentityUser sınıfı temel özellikleri içerirken, çoğu projede ek kullanıcı bilgilerine ihtiyaç duyarsınız. Özel kullanıcı modeli oluşturmak için IdentityUser‘dan türetilmiş bir sınıf tanımlayın:
using Microsoft.AspNetCore.Identity;
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? BirthDate { get; set; }
public string ProfilePicture { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public bool IsActive { get; set; } = true;
// Navigation properties
public virtual ICollection<UserAddress> Addresses { get; set; }
public virtual ICollection<UserOrder> Orders { get; set; }
// Computed property
public string FullName => $"{FirstName} {LastName}";
public int Age
{
get
{
if (!BirthDate.HasValue)
return 0;
var today = DateTime.Today;
var age = today.Year - BirthDate.Value.Year;
if (BirthDate.Value.Date > today.AddYears(-age))
age--;
return age;
}
}
}
Bu model, kullanıcılarınız hakkında ek bilgiler saklamanızı sağlar. Navigation property’ler sayesinde Entity Framework Core ile ilişkili verileri de yönetebilirsiniz. Computed property’ler ise veritabanında saklanmayan ancak kullanışlı olan bilgileri sunar.
Kullanıcı Yönetimi (UserManager)
ASP.NET Core Identity’de kullanıcı işlemleri UserManager<TUser> servisi üzerinden gerçekleştirilir. Bu servis, dependency injection ile controller veya servis sınıflarınıza enjekte edilir.
Kullanıcı Kaydı İşlemi
Yeni kullanıcı oluşturmak için önce bir ViewModel tanımlayın:
using System.ComponentModel.DataAnnotations;
public class RegisterViewModel
{
[Required(ErrorMessage = "Ad alanı zorunludur")]
[StringLength(50, ErrorMessage = "Ad en fazla 50 karakter olabilir")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Soyad alanı zorunludur")]
[StringLength(50, ErrorMessage = "Soyad en fazla 50 karakter olabilir")]
public string LastName { get; set; }
[Required(ErrorMessage = "Email adresi zorunludur")]
[EmailAddress(ErrorMessage = "Geçerli bir email adresi giriniz")]
public string Email { get; set; }
[Required(ErrorMessage = "Kullanıcı adı zorunludur")]
[StringLength(50, MinimumLength = 3, ErrorMessage = "Kullanıcı adı 3-50 karakter arasında olmalıdır")]
public string UserName { get; set; }
[Required(ErrorMessage = "Şifre zorunludur")]
[StringLength(100, MinimumLength = 8, ErrorMessage = "Şifre en az 8 karakter olmalıdır")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required(ErrorMessage = "Şifre tekrarı zorunludur")]
[DataType(DataType.Password)]
[Compare("Password", ErrorMessage = "Şifreler eşleşmiyor")]
public string ConfirmPassword { get; set; }
[Required(ErrorMessage = "Doğum tarihi zorunludur")]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }
}
Ardından AccountController içinde kayıt işlemini gerçekleştirin:
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
}
[HttpGet]
public IActionResult Register()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid)
return View(model);
var user = new ApplicationUser
{
UserName = model.UserName,
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName,
BirthDate = model.BirthDate,
CreatedAt = DateTime.UtcNow,
IsActive = true
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Email doğrulama token'ı oluştur
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action(
"ConfirmEmail",
"Account",
new { userId = user.Id, token = token },
protocol: Request.Scheme);
// Email gönder
await _emailSender.SendEmailAsync(
user.Email,
"Email Adresinizi Doğrulayın",
$"Lütfen email adresinizi doğrulamak için <a href='{callbackUrl}'>buraya tıklayın</a>.");
// Varsayılan rol ata
await _userManager.AddToRoleAsync(user, "User");
TempData["Success"] = "Kayıt başarılı! Lütfen email adresinizi doğrulayın.";
return RedirectToAction("Login");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return View(model);
}
}
Bu kod, güvenli kullanıcı kaydı için gerekli tüm adımları içerir. Email doğrulama, hata yönetimi ve rol ataması otomatik olarak gerçekleştirilir.
Kullanıcı Girişi
Kullanıcı giriş işlemi için LoginViewModel oluşturun:
public class LoginViewModel
{
[Required(ErrorMessage = "Email veya kullanıcı adı zorunludur")]
public string UserNameOrEmail { get; set; }
[Required(ErrorMessage = "Şifre zorunludur")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Beni Hatırla")]
public bool RememberMe { get; set; }
}
Giriş action metodunu implement edin:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
if (!ModelState.IsValid)
return View(model);
// Email veya kullanıcı adı ile kullanıcıyı bul
var user = await _userManager.FindByEmailAsync(model.UserNameOrEmail)
?? await _userManager.FindByNameAsync(model.UserNameOrEmail);
if (user == null)
{
ModelState.AddModelError(string.Empty, "Geçersiz giriş bilgileri");
return View(model);
}
// Email doğrulama kontrolü
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty, "Lütfen önce email adresinizi doğrulayın");
return View(model);
}
// Hesap aktiflik kontrolü
if (!user.IsActive)
{
ModelState.AddModelError(string.Empty, "Hesabınız aktif değil. Lütfen destek ile iletişime geçin");
return View(model);
}
var result = await _signInManager.PasswordSignInAsync(
user.UserName,
model.Password,
model.RememberMe,
lockoutOnFailure: true);
if (result.Succeeded)
{
// Giriş logunu kaydet
user.UpdatedAt = DateTime.UtcNow;
await _userManager.UpdateAsync(user);
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction("LoginWith2fa", new { returnUrl, model.RememberMe });
}
if (result.IsLockedOut)
{
return RedirectToAction("Lockout");
}
ModelState.AddModelError(string.Empty, "Geçersiz giriş bilgileri");
return View(model);
}
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
return Redirect(returnUrl);
return RedirectToAction("Index", "Home");
}
Bu implementasyon, güvenli giriş için tüm kontrolleri içerir. Email doğrulama, hesap kilitleme ve iki faktörlü kimlik doğrulama desteği mevcuttur.
Rol Tabanlı Yetkilendirme
Rol yönetimi, kullanıcıların erişim yetkilerini kontrol etmek için kullanılır. ASP.NET Core Identity’de roller RoleManager<TRole> servisi ile yönetilir.
Rol Oluşturma ve Yönetimi
Roller için bir service sınıfı oluşturun:
public interface IRoleService
{
Task<IdentityResult> CreateRoleAsync(string roleName);
Task<IdentityResult> DeleteRoleAsync(string roleName);
Task<List<IdentityRole>> GetAllRolesAsync();
Task<bool> RoleExistsAsync(string roleName);
}
public class RoleService : IRoleService
{
private readonly RoleManager<IdentityRole> _roleManager;
public RoleService(RoleManager<IdentityRole> roleManager)
{
_roleManager = roleManager;
}
public async Task<IdentityResult> CreateRoleAsync(string roleName)
{
if (string.IsNullOrWhiteSpace(roleName))
throw new ArgumentException("Rol adı boş olamaz", nameof(roleName));
if (await RoleExistsAsync(roleName))
return IdentityResult.Failed(new IdentityError
{
Description = "Bu rol zaten mevcut"
});
var role = new IdentityRole(roleName);
return await _roleManager.CreateAsync(role);
}
public async Task<IdentityResult> DeleteRoleAsync(string roleName)
{
var role = await _roleManager.FindByNameAsync(roleName);
if (role == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Rol bulunamadı"
});
return await _roleManager.DeleteAsync(role);
}
public async Task<List<IdentityRole>> GetAllRolesAsync()
{
return await _roleManager.Roles.ToListAsync();
}
public async Task<bool> RoleExistsAsync(string roleName)
{
return await _roleManager.RoleExistsAsync(roleName);
}
}
Kullanıcıya Rol Atama
Kullanıcılara rol atamak için UserManager kullanın:
public class UserService
{
private readonly UserManager<ApplicationUser> _userManager;
public UserService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<IdentityResult> AssignRoleToUserAsync(string userId, string roleName)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
if (await _userManager.IsInRoleAsync(user, roleName))
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı zaten bu role sahip"
});
return await _userManager.AddToRoleAsync(user, roleName);
}
public async Task<IdentityResult> RemoveRoleFromUserAsync(string userId, string roleName)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
return await _userManager.RemoveFromRoleAsync(user, roleName);
}
public async Task<List<string>> GetUserRolesAsync(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return new List<string>();
var roles = await _userManager.GetRolesAsync(user);
return roles.ToList();
}
}
Controller’da Rol Kontrolü
Rol tabanlı yetkilendirme için [Authorize] attribute’unu kullanın:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
[HttpGet]
public IActionResult Dashboard()
{
return View();
}
[HttpGet]
[Authorize(Roles = "Admin,SuperAdmin")]
public IActionResult UserManagement()
{
return View();
}
}
[Authorize(Roles = "User")]
public class ProfileController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public ProfileController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
public async Task<IActionResult> Index()
{
var user = await _userManager.GetUserAsync(User);
return View(user);
}
}
Claims ve Policy Yönetimi
Claims-based yetkilendirme, rol tabanlı yetkilendirmeden daha esnek bir yapı sunar. Her kullanıcı için özel izinler tanımlayabilir ve bunları policy’ler ile kontrol edebilirsiniz.
Claim Ekleme ve Yönetme
Kullanıcılara claim eklemek için:
public class ClaimService
{
private readonly UserManager<ApplicationUser> _userManager;
public ClaimService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<IdentityResult> AddClaimToUserAsync(
string userId,
string claimType,
string claimValue)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
var claim = new Claim(claimType, claimValue);
return await _userManager.AddClaimAsync(user, claim);
}
public async Task<IdentityResult> RemoveClaimFromUserAsync(
string userId,
string claimType,
string claimValue)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
var claim = new Claim(claimType, claimValue);
return await _userManager.RemoveClaimAsync(user, claim);
}
public async Task<IList<Claim>> GetUserClaimsAsync(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return new List<Claim>();
return await _userManager.GetClaimsAsync(user);
}
}
Policy Tanımlama
Program.cs içinde custom policy’ler tanımlayın:
builder.Services.AddAuthorization(options =>
{
// Basit policy
options.AddPolicy("RequireAdminRole", policy =>
policy.RequireRole("Admin"));
// Claim tabanlı policy
options.AddPolicy("CanEditPosts", policy =>
policy.RequireClaim("Permission", "EditPost"));
// Birden fazla claim gerektiren policy
options.AddPolicy("CanManageUsers", policy =>
policy.RequireClaim("Permission", "ViewUser", "EditUser", "DeleteUser"));
// Kombinasyon policy
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireRole("Admin");
policy.RequireClaim("Department", "IT");
policy.RequireAssertion(context =>
context.User.HasClaim(c => c.Type == "EmployeeNumber"));
});
// Özel requirement ile policy
options.AddPolicy("MinimumAge18", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(18)));
});
Custom Authorization Requirement
Özel yetkilendirme kuralları için requirement ve handler oluşturun:
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
private readonly UserManager<ApplicationUser> _userManager;
public MinimumAgeHandler(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
protected override async Task HandleRequirementAsync(
AuthorizationHandlerContext context,
MinimumAgeRequirement requirement)
{
if (!context.User.Identity.IsAuthenticated)
{
context.Fail();
return;
}
var user = await _userManager.GetUserAsync(context.User);
if (user?.BirthDate == null)
{
context.Fail();
return;
}
var age = DateTime.Today.Year - user.BirthDate.Value.Year;
if (user.BirthDate.Value.Date > DateTime.Today.AddYears(-age))
age--;
if (age >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
Handler’ı Program.cs’de kaydedin:
builder.Services.AddScoped<IAuthorizationHandler, MinimumAgeHandler>();
Policy Kullanımı
Controller’da policy kullanımı:
[Authorize(Policy = "CanEditPosts")]
public class PostController : Controller
{
[HttpGet]
public IActionResult Edit(int id)
{
return View();
}
[HttpPost]
[Authorize(Policy = "MinimumAge18")]
public async Task<IActionResult> PublishPost(PostViewModel model)
{
// Post yayınlama işlemleri
return RedirectToAction("Index");
}
}
Token İşlemleri ve Güvenlik
ASP.NET Core Identity, email doğrulama, şifre sıfırlama ve iki faktörlü kimlik doğrulama için token mekanizmaları sunar.
Email Doğrulama
Email doğrulama token’ı oluşturma ve doğrulama:
public class EmailConfirmationService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _emailSender;
public EmailConfirmationService(
UserManager<ApplicationUser> userManager,
IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
public async Task<string> GenerateEmailConfirmationTokenAsync(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
throw new ArgumentException("Kullanıcı bulunamadı", nameof(userId));
return await _userManager.GenerateEmailConfirmationTokenAsync(user);
}
public async Task<IdentityResult> ConfirmEmailAsync(string userId, string token)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
return await _userManager.ConfirmEmailAsync(user, token);
}
public async Task SendConfirmationEmailAsync(ApplicationUser user, string callbackUrl)
{
var emailBody = $@"
<h2>Email Adresinizi Doğrulayın</h2>
<p>Merhaba {user.FirstName},</p>
<p>Hesabınızı aktifleştirmek için lütfen aşağıdaki linke tıklayın:</p>
<p><a href='{callbackUrl}'>Email Adresimi Doğrula</a></p>
<p>Bu linkin geçerlilik süresi 24 saattir.</p>
";
await _emailSender.SendEmailAsync(
user.Email,
"Email Adresinizi Doğrulayın",
emailBody);
}
}
Controller’da kullanımı:
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ConfirmEmail(string userId, string token)
{
if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(token))
{
return BadRequest("Geçersiz email doğrulama bağlantısı");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound("Kullanıcı bulunamadı");
}
var result = await _userManager.ConfirmEmailAsync(user, token);
if (result.Succeeded)
{
TempData["Success"] = "Email adresiniz başarıyla doğrulandı. Şimdi giriş yapabilirsiniz.";
return RedirectToAction("Login");
}
return View("Error");
}
Şifre Sıfırlama
Şifre sıfırlama token işlemleri:
public class PasswordResetService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IEmailSender _emailSender;
public PasswordResetService(
UserManager<ApplicationUser> userManager,
IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
public async Task<string> GeneratePasswordResetTokenAsync(string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null || !await _userManager.IsEmailConfirmedAsync(user))
throw new InvalidOperationException("Kullanıcı bulunamadı veya email doğrulanmamış");
return await _userManager.GeneratePasswordResetTokenAsync(user);
}
public async Task<IdentityResult> ResetPasswordAsync(
string email,
string token,
string newPassword)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
return await _userManager.ResetPasswordAsync(user, token, newPassword);
}
public async Task SendPasswordResetEmailAsync(ApplicationUser user, string callbackUrl)
{
var emailBody = $@"
<h2>Şifre Sıfırlama Talebi</h2>
<p>Merhaba {user.FirstName},</p>
<p>Şifrenizi sıfırlamak için lütfen aşağıdaki linke tıklayın:</p>
<p><a href='{callbackUrl}'>Şifremi Sıfırla</a></p>
<p>Bu isteği siz yapmadıysanız, bu emaili görmezden gelebilirsiniz.</p>
<p>Bu linkin geçerlilik süresi 1 saattir.</p>
";
await _emailSender.SendEmailAsync(
user.Email,
"Şifre Sıfırlama",
emailBody);
}
}
İki Faktörlü Kimlik Doğrulama (2FA)
2FA için gerekli yapılandırma ve kullanım:
public class TwoFactorService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public TwoFactorService(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public async Task<IdentityResult> EnableTwoFactorAsync(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
return IdentityResult.Failed(new IdentityError
{
Description = "Kullanıcı bulunamadı"
});
await _userManager.SetTwoFactorEnabledAsync(user, true);
return IdentityResult.Success;
}
public async Task<string> GenerateTwoFactorTokenAsync(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
throw new ArgumentException("Kullanıcı bulunamadı", nameof(userId));
return await _userManager.GenerateTwoFactorTokenAsync(user, "Email");
}
public async Task<SignInResult> TwoFactorSignInAsync(
string code,
bool rememberMe,
bool rememberMachine)
{
return await _signInManager.TwoFactorSignInAsync(
"Email",
code,
rememberMe,
rememberMachine);
}
}
Clean Architecture Entegrasyonu
ASP.NET Core Identity’yi katmanlı mimari içinde doğru şekilde konumlandırmak, sürdürülebilir ve test edilebilir kod yazmak için önemlidir.
Katman Yapısı
Domain Layer (Core):
// Domain/Entities/ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? BirthDate { get; set; }
}
// Domain/Interfaces/IAuthenticationService.cs
public interface IAuthenticationService
{
Task<AuthResult> RegisterAsync(RegisterRequest request);
Task<AuthResult> LoginAsync(LoginRequest request);
Task<bool> LogoutAsync();
}
Infrastructure Layer:
// Infrastructure/Persistence/ApplicationDbContext.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Custom configurations
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
// Infrastructure/Services/AuthenticationService.cs
public class AuthenticationService : IAuthenticationService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public AuthenticationService(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public async Task<AuthResult> RegisterAsync(RegisterRequest request)
{
var user = new ApplicationUser
{
UserName = request.UserName,
Email = request.Email,
FirstName = request.FirstName,
LastName = request.LastName
};
var result = await _userManager.CreateAsync(user, request.Password);
return new AuthResult
{
Succeeded = result.Succeeded,
Errors = result.Errors.Select(e => e.Description).ToList()
};
}
public async Task<AuthResult> LoginAsync(LoginRequest request)
{
var result = await _signInManager.PasswordSignInAsync(
request.UserName,
request.Password,
request.RememberMe,
lockoutOnFailure: true);
return new AuthResult
{
Succeeded = result.Succeeded,
RequiresTwoFactor = result.RequiresTwoFactor,
IsLockedOut = result.IsLockedOut
};
}
public async Task<bool> LogoutAsync()
{
await _signInManager.SignOutAsync();
return true;
}
}
Application Layer:
// Application/DTOs/RegisterRequest.cs
public class RegisterRequest
{
public string UserName { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
}
// Application/DTOs/AuthResult.cs
public class AuthResult
{
public bool Succeeded { get; set; }
public bool RequiresTwoFactor { get; set; }
public bool IsLockedOut { get; set; }
public List<string> Errors { get; set; } = new();
}
Presentation Layer:
// WebAPI/Controllers/AuthController.cs
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly IAuthenticationService _authService;
public AuthController(IAuthenticationService authService)
{
_authService = authService;
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
{
var result = await _authService.RegisterAsync(request);
if (!result.Succeeded)
return BadRequest(result.Errors);
return Ok(new { message = "Kayıt başarılı" });
}
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
var result = await _authService.LoginAsync(request);
if (!result.Succeeded)
return Unauthorized(new { message = "Giriş başarısız" });
return Ok(new { message = "Giriş başarılı" });
}
}
Best Practices ve İpuçları
ASP.NET Core Identity kullanırken dikkat edilmesi gereken önemli noktalar:
Güvenlik En İyi Uygulamaları
Şifre Politikaları: Güçlü şifre gereksinimleri belirleyin. Minimum uzunluk, büyük-küçük harf, rakam ve özel karakter zorunluluğu ekleyin.
Hesap Kilitleme: Brute force saldırılarına karşı hesap kilitleme mekanizmasını aktif edin. Başarısız giriş denemelerini sınırlayın.
Email Doğrulama: Kullanıcıların gerçek email adresleri ile kayıt olmalarını sağlayın. Email doğrulamasını zorunlu hale getirin.
HTTPS Kullanımı: Tüm kimlik doğrulama işlemlerinde HTTPS kullanın. Cookie’leri yalnızca HTTPS üzerinden iletin.
Token Güvenliği: Token’ların geçerlilik sürelerini makul seviyelerde tutun. Hassas işlemler için kısa ömürlü token’lar kullanın.
Performans Optimizasyonu
Asenkron Metodlar: Tüm Identity işlemlerinde async/await kullanın. Veritabanı işlemlerinin blocking olmamasını sağlayın.
Caching: Sık erişilen kullanıcı bilgilerini cache’leyin. Rol ve claim bilgilerini memory cache’de tutun.
Eager Loading: İlişkili verileri çekerken eager loading kullanın. N+1 sorgu probleminden kaçının.
Kod Organizasyonu
Separation of Concerns: Identity işlemlerini servis katmanına taşıyın. Controller’ları mümkün olduğunca ince tutun.
Dependency Injection: Tüm servisleri DI container üzerinden kullanın. Constructor injection tercih edin.
Error Handling: Merkezi hata yönetimi implementasyonu yapın. Kullanıcıya anlamlı hata mesajları gösterin.
Sonuç
ASP.NET Core Identity, modern web uygulamaları için kapsamlı ve güvenli bir kimlik doğrulama altyapısı sunar. Bu rehberde ele aldığımız konular ile kullanıcı yönetimi, rol tabanlı ve claims tabanlı yetkilendirme, token işlemleri ve clean architecture entegrasyonunu başarıyla gerçekleştirebilirsiniz.
Identity framework’ü esnek yapısı sayesinde her türlü iş gereksinimini karşılayabilir. Varsayılan yapılandırmaların yanı sıra özelleştirilebilir modeller, custom authorization handler’lar ve policy’ler ile ihtiyacınıza özel çözümler geliştirebilirsiniz.
Unutmayın ki güvenlik, sürekli güncel tutulması gereken bir konudur. Microsoft’un resmi dokümantasyonunu takip edin, güvenlik güncellemelerini düzenli olarak uygulayın ve best practice’lere sadık kalın.