Levge.Identity
2.3.0
dotnet add package Levge.Identity --version 2.3.0
NuGet\Install-Package Levge.Identity -Version 2.3.0
<PackageReference Include="Levge.Identity" Version="2.3.0" />
<PackageVersion Include="Levge.Identity" Version="2.3.0" />
<PackageReference Include="Levge.Identity" />
paket add Levge.Identity --version 2.3.0
#r "nuget: Levge.Identity, 2.3.0"
#:package Levge.Identity@2.3.0
#addin nuget:?package=Levge.Identity&version=2.3.0
#tool nuget:?package=Levge.Identity&version=2.3.0
Levge.Identity
.NET 10 uygulamaları için JWT tabanlı kimlik doğrulama ve yetkilendirme altyapısı.
Tenant destekli, enum tabanlı rol hiyerarşisi ve clean architecture uyumlu tasarım.
İçindekiler
- Kurulum
- Program.cs
- JwtConfig Referansı
- Token Üretimi — LevgeClaimsFactory
- IJwtTokenService
- ICurrentUser
- Yetkilendirme — LevgePolicies
- IPasswordHasher
- ICodeGenerator
- LevgeClaimTypes
- Bağımlılıklar
Kurulum
dotnet add package Levge.Identity
dotnet add package Levge.Domain
Program.cs
builder.Services
.AddLevgeIdentity(new JwtConfig
{
Secret = "en-az-32-karakter-uzun-gizli-anahtar",
Issuer = "https://api.levge.com",
Audience = "https://api.levge.com",
AccessTokenExpirationMinutes = 60,
RefreshTokenExpirationMinutes = 43200 // 30 gün
})
.AddLevgeAuthorization();
// Middleware sırası
app.UseAuthentication();
app.UseAuthorization();
Özel bir IIdentityProvider implemente ettiyseniz:
builder.Services.AddLevgeIdentity<MyCustomProvider>(jwtConfig);
JwtConfig Referansı
| Özellik | Tür | Varsayılan | Açıklama |
|---|---|---|---|
Secret |
string |
— | HMAC-SHA256 imzalama anahtarı (≥32 karakter) |
Issuer |
string |
— | Token yayıncısı |
Audience |
string |
— | Token izleyicisi |
Authority |
string |
— | OIDC authority (opsiyonel) |
AccessTokenExpirationMinutes |
int |
60 |
Access token ömrü (dakika) |
RefreshTokenExpirationMinutes |
int |
43200 |
Refresh token ömrü (dakika) |
EnableRefreshTokens |
bool |
true |
Refresh token desteği |
ValidateIssuer |
bool |
true |
Issuer doğrulaması |
ValidateAudience |
bool |
true |
Audience doğrulaması |
ValidateLifetime |
bool |
true |
Süre doğrulaması |
ValidateSigningKey |
bool |
true |
İmza anahtarı doğrulaması |
AuthScheme |
string? |
"Bearer" |
Authentication şeması |
Token Üretimi — LevgeClaimsFactory
Application katmanında token oluşturmadan önce standart claim listesi üretin:
using Levge.Identity;
using Levge.Domain.Enums;
// Temel kullanım
var claims = LevgeClaimsFactory.Create(
userId: user.Id,
email: user.Email,
role: AppUserRole.TenantOwner,
tenantId: user.TenantId,
tenantName: user.TenantName,
roleId: user.RoleId
);
var accessToken = _jwtTokenService.GenerateAccessToken(claims);
var refreshToken = _jwtTokenService.GenerateRefreshToken();
var expiresAt = _jwtTokenService.GetAccessTokenExpireTime();
Ek claim eklemek için extra parametresini kullanın:
var claims = LevgeClaimsFactory.Create(
userId: user.Id,
email: user.Email,
role: AppUserRole.SuperAdmin,
extra: [new Claim("custom_key", "custom_value")]
);
IJwtTokenService
public interface IJwtTokenService
{
string GenerateAccessToken(IEnumerable<Claim> claims);
string GenerateRefreshToken();
DateTime GetAccessTokenExpireTime();
DateTime GetRefreshTokenExpireTime();
ClaimsPrincipal? GetPrincipalFromExpiredToken(string accessToken);
}
Refresh Token Akışı
GetPrincipalFromExpiredToken imzayı doğrular ancak süre kontrolü yapmaz — süresi dolmuş access token'dan kullanıcıyı tanımlamak için kullanılır:
[HttpPost("refresh")]
public async Task<IActionResult> Refresh([FromBody] RefreshRequest request)
{
var principal = _jwtTokenService.GetPrincipalFromExpiredToken(request.AccessToken);
if (principal is null)
return Unauthorized();
var userId = long.Parse(principal.FindFirstValue(LevgeClaimTypes.UserId)!);
var user = await _userRepo.GetWithRefreshTokenAsync(userId, request.RefreshToken);
if (user is null || user.RefreshTokenExpiry < DateTime.UtcNow)
return Unauthorized();
var claims = LevgeClaimsFactory.Create(user.Id, user.Email, user.AppRole, user.TenantId);
var accessToken = _jwtTokenService.GenerateAccessToken(claims);
var refreshToken = _jwtTokenService.GenerateRefreshToken();
await _userRepo.UpdateRefreshTokenAsync(user.Id, refreshToken,
_jwtTokenService.GetRefreshTokenExpireTime());
return Ok(new { AccessToken = accessToken, RefreshToken = refreshToken });
}
ICurrentUser
Herhangi bir servis veya controller'a inject ederek mevcut kullanıcıyı okuyun:
public class OrderService
{
private readonly ICurrentUser _currentUser;
public OrderService(ICurrentUser currentUser)
=> _currentUser = currentUser;
public void Create()
{
if (!_currentUser.IsAuthenticated)
throw new UnauthorizedAccessException();
long userId = _currentUser.UserId!.Value;
string email = _currentUser.Email!;
long tenantId = _currentUser.TenantId!.Value;
string tenantName = _currentUser.TenantName!;
string deviceId = _currentUser.DeviceId ?? "unknown";
// Enum tabanlı rol kontrolü
AppUserRole? role = _currentUser.AppRole; // AppUserRole.TenantOwner
// Hiyerarşik rol kontrolü
bool canManage = _currentUser.IsInRole(AppUserRole.TenantOwner);
// SuperAdmin → true (hepsi)
// TenantOwner → true (TenantOwner + TenantUser)
// TenantUser → false
// Ham claim okuma
string? custom = _currentUser.GetClaimValue("my_claim");
string? header = _currentUser.GetHeaderValue("X-Correlation-Id");
}
}
ICurrentUser Üyeleri
| Üye | Tür | Açıklama |
|---|---|---|
UserId |
long? |
Kullanıcı birincil anahtarı |
RoleId |
long? |
Veritabanı rol kimliği |
AppRole |
AppUserRole? |
Enum rol değeri |
Role |
string? |
Rol adı (ham string) |
Email |
string? |
E-posta adresi |
TenantId |
long? |
Tenant birincil anahtarı |
TenantName |
string? |
Tenant adı |
DeviceId |
string? |
X-Device-Id başlığı |
IsAuthenticated |
bool |
Kimlik doğrulandı mı |
IsInRole(role) |
bool |
Hiyerarşik rol kontrolü |
GetClaimValue(type) |
string? |
Claim değeri okuma |
GetHeaderValue(key) |
string? |
HTTP başlığı okuma |
Yetkilendirme — LevgePolicies
AddLevgeAuthorization() üç hiyerarşik policy kaydeder:
| Policy sabiti | Erişim |
|---|---|
LevgePolicies.SuperAdmin |
Yalnızca SuperAdmin |
LevgePolicies.TenantOwner |
SuperAdmin + TenantOwner |
LevgePolicies.TenantUser |
SuperAdmin + TenantOwner + TenantUser |
// Controller veya endpoint üzerinde kullanım
[Authorize(Policy = LevgePolicies.SuperAdmin)]
[HttpDelete("admin/users/{id}")]
public IActionResult DeleteUser(long id) { ... }
[Authorize(Policy = LevgePolicies.TenantOwner)]
[HttpGet("tenant/reports")]
public IActionResult GetReports() { ... }
[Authorize(Policy = LevgePolicies.TenantUser)]
[HttpGet("me")]
public IActionResult GetProfile() { ... }
AppUserRole Enum
public enum AppUserRole
{
SuperAdmin = 0, // Tüm tenant'lar üzerinde tam yetki
TenantOwner = 1, // Kendi tenant'ı üzerinde tam yetki
TenantUser = 2 // Standart tenant kullanıcısı
}
IPasswordHasher
PBKDF2 algoritmasıyla şifre karma ve doğrulama:
public interface IPasswordHasher
{
string Hash(string password);
bool Verify(string password, string hashedPassword);
}
// Kayıt
var hashed = _passwordHasher.Hash(request.Password);
// Giriş
bool valid = _passwordHasher.Verify(request.Password, user.PasswordHash);
if (!valid) return Unauthorized();
ICodeGenerator
public interface ICodeGenerator
{
string GenerateNumericCode(int length = 6);
string GenerateAlphaNumericCode(int length = 8);
string GenerateScopedCode(string scopeKey, string entityId);
string GeneratePassword(int length, int minUpper = 1, int minDigits = 1,
int minSpecial = 1, string specialChars = "!@#$%^&*");
}
| Metot | Örnek çıktı | Kullanım |
|---|---|---|
GenerateNumericCode(6) |
"483921" |
SMS / e-posta OTP |
GenerateAlphaNumericCode(8) |
"K7MX2QBW" |
Aktivasyon kodu |
GenerateScopedCode("email-verify", userId) |
"Xk9mT2pQrL4A" |
Tek kullanımlık bağlantı token'ı |
GeneratePassword(12) |
"aB3@xKm!9Zqp" |
Geçici parola üretimi |
// OTP
var otp = _codeGenerator.GenerateNumericCode(); // 6 hane
// E-posta doğrulama linki için
var token = _codeGenerator.GenerateScopedCode("email-verify", user.Id.ToString());
// Geçici parola
var tempPwd = _codeGenerator.GeneratePassword(length: 12, minUpper: 2, minSpecial: 2);
LevgeClaimTypes
Token üretimi ve okuma arasında tutarlılık için sabitler — her iki tarafta da bu sabitleri kullanın:
public static class LevgeClaimTypes
{
public const string UserId = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
public const string Email = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
public const string Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
public const string RoleId = "role_id";
public const string TenantId = "tenant_id";
public const string TenantName = "tenant_name";
}
Clean Architecture Örneği
src/
├── MyApp.Domain/
├── MyApp.Application/
│ └── Features/Auth/
│ ├── LoginCommand.cs
│ └── LoginCommandHandler.cs ← LevgeClaimsFactory + IJwtTokenService burada
├── MyApp.Infrastructure/
│ └── Persistence/UserRepository.cs
└── MyApp.WebApi/
├── Program.cs ← AddLevgeIdentity + AddLevgeAuthorization
└── Controllers/AuthController.cs
// Application katmanı — LoginCommandHandler.cs
public class LoginCommandHandler
{
private readonly IJwtTokenService _jwt;
private readonly IPasswordHasher _hasher;
private readonly IUserRepository _users;
public async Task<TokenResponse> Handle(LoginCommand cmd)
{
var user = await _users.FindByEmailAsync(cmd.Email)
?? throw new UnauthorizedException();
if (!_hasher.Verify(cmd.Password, user.PasswordHash))
throw new UnauthorizedException();
var claims = LevgeClaimsFactory.Create(
userId: user.Id,
email: user.Email,
role: user.AppRole,
tenantId: user.TenantId,
tenantName: user.TenantName
);
return new TokenResponse(
AccessToken: _jwt.GenerateAccessToken(claims),
RefreshToken: _jwt.GenerateRefreshToken(),
ExpiresAt: _jwt.GetAccessTokenExpireTime()
);
}
}
// WebApi katmanı — Controller
[ApiController, Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly ICurrentUser _currentUser;
[HttpPost("login")]
[AllowAnonymous]
public Task<IActionResult> Login([FromBody] LoginCommand cmd) { ... }
[HttpGet("me")]
[Authorize(Policy = LevgePolicies.TenantUser)]
public IActionResult Me() => Ok(new
{
_currentUser.UserId,
_currentUser.Email,
_currentUser.AppRole,
_currentUser.TenantId,
_currentUser.TenantName
});
}
Bağımlılıklar
| Paket | Amaç |
|---|---|
Microsoft.AspNetCore.App (FrameworkReference) |
ASP.NET Core altyapısı |
Microsoft.AspNetCore.Authentication.JwtBearer |
JWT middleware |
Levge.Domain |
AppUserRole enum ve domain primitives |
Levge.Exceptions |
LevgeException temel exception türleri |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Levge.Domain (>= 2.3.0)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.7)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on Levge.Identity:
| Package | Downloads |
|---|---|
|
Levge.AuditLog
EF Core tabanlı otomatik audit log altyapısı. Tenant ve soft-delete desteğiyle birlikte clean architecture uyumlu denetim kaydı çözümü. |
|
|
Levge.Tenancy
SaaS uygulamaları için çok kiracılı (multi-tenant) altyapı. JWT tabanlı tenant çözümleme, EF Core Global Query Filter ve tenant yaşam döngüsü yönetimi. |
|
|
Levge.MediatR
MediatR tabanlı domain event dispatcher, EF Core interceptor ve FluentValidation pipeline behavior. IDomainEventDispatcher implementasyonu, SaveChanges sonrası otomatik domain event dispatch ve ValidationBehavior altyapısı. |
|
|
Levge.Caching
Levge ekosistemi için opsiyonel önbellekleme altyapısı. Memory Cache ve Redis desteği, JWT token revoke servisi. AddLevgeCaching() ile projeye eklenebilir. |
|
|
Levge.Subscription
Levge ekosistemi için opsiyonel abonelik ve kota takip altyapısı. Plan, modül, tenant aboneliği, kullanım takibi ve yenileme job desteği. AddLevgeSubscription() ile projeye eklenebilir. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.3.0 | 159 | 4/29/2026 |
| 2.1.0 | 117 | 4/27/2026 |
| 2.0.1 | 131 | 4/27/2026 |
| 1.1.46 | 145 | 1/22/2026 |
| 1.1.45 | 288 | 1/20/2026 |
| 1.1.44 | 111 | 1/20/2026 |
| 1.1.43 | 506 | 7/3/2025 |
| 1.1.42 | 233 | 7/3/2025 |
| 1.1.41 | 256 | 6/22/2025 |
| 1.1.21 | 185 | 6/22/2025 |
| 1.1.1 | 492 | 6/18/2025 |
| 1.1.0 | 228 | 6/18/2025 |
| 1.0.5 | 212 | 6/17/2025 |
| 1.0.4 | 218 | 6/17/2025 |
| 1.0.3 | 215 | 6/17/2025 |
| 1.0.2 | 217 | 6/17/2025 |
| 1.0.0 | 234 | 6/16/2025 |