Files

216 lines
6.8 KiB
C#

using System.Security.Claims;
using GozareshgirProgramManager.Application._Common.Interfaces;
using Microsoft.AspNetCore.Http;
namespace GozareshgirProgramManager.Infrastructure.Services.Authentication;
/// <summary>
/// سرویس کمکی برای کار با JWT و HttpContext
/// این کلاس فقط با توکن و Context کار می‌کند و هیچ عملیات دیتابیسی ندارد
/// </summary>
public class AuthHelper : IAuthHelper
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly JwtTokenGenerator _jwtTokenGenerator;
public AuthHelper(
IHttpContextAccessor httpContextAccessor,
JwtTokenGenerator jwtTokenGenerator)
{
_httpContextAccessor = httpContextAccessor;
_jwtTokenGenerator = jwtTokenGenerator;
}
public LoginSession SignIn(long userId, string userName, string fullName, long accountId, List<string> roles)
{
// 1. تولید Access Token
var accessToken = GenerateAccessToken(userId, userName, fullName, accountId, roles);
var accessTokenExpiration = DateTime.Now.AddMinutes(30);
// 2. تولید Refresh Token
var refreshToken = GenerateRefreshToken();
var refreshTokenExpiration = GetRefreshTokenExpiration();
// 3. ذخیره Refresh Token در Cookie
_httpContextAccessor.HttpContext?.Response.Cookies.Append("rf-token", refreshToken, new CookieOptions
{
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Lax,
Expires = refreshTokenExpiration
});
// 4. تنظیم Authorization Header (اختیاری - معمولاً کلاینت خودش این کار را می‌کند)
_httpContextAccessor.HttpContext?.Response.Headers.Append("Authorization", $"Bearer {accessToken}");
return new LoginSession
{
AccessToken = accessToken,
RefreshToken = refreshToken,
RefreshTokenExpiration = refreshTokenExpiration,
AccessTokenExpiration = accessTokenExpiration
};
}
/// <summary>
/// تولید Access Token
/// </summary>
public string GenerateAccessToken(long userId, string userName, string fullName, long? accountId, List<string> roles)
{
return _jwtTokenGenerator.GenerateAccessToken(userId, userName, fullName, accountId, roles);
}
/// <summary>
/// تولید Refresh Token
/// </summary>
public string GenerateRefreshToken()
{
return _jwtTokenGenerator.GenerateRefreshToken();
}
/// <summary>
/// دریافت تاریخ انقضای Refresh Token
/// </summary>
public DateTime GetRefreshTokenExpiration()
{
return _jwtTokenGenerator.GetRefreshTokenExpiration();
}
/// <summary>
/// اعتبارسنجی توکن و استخراج Claims
/// </summary>
public ClaimsPrincipal? ValidateToken(string token)
{
return _jwtTokenGenerator.ValidateToken(token);
}
/// <summary>
/// اعتبارسنجی توکن منقضی شده (بدون چک زمان)
/// </summary>
public ClaimsPrincipal? ValidateExpiredToken(string token)
{
return _jwtTokenGenerator.ValidateExpiredToken(token);
}
/// <summary>
/// استخراج UserId از توکن (حتی اگر منقضی شده باشد)
/// </summary>
public long? GetUserIdFromToken(string token)
{
try
{
var principal = _jwtTokenGenerator.ValidateExpiredToken(token);
if (principal == null) return null;
var userIdClaim = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return long.TryParse(userIdClaim, out var userId) ? userId : null;
}
catch
{
return null;
}
}
/// <summary>
/// دریافت اطلاعات IP کاربر جاری
/// </summary>
public string? GetClientIpAddress()
{
return _httpContextAccessor.HttpContext?.Connection.RemoteIpAddress?.ToString();
}
/// <summary>
/// دریافت User Agent کاربر جاری
/// </summary>
public string? GetUserAgent()
{
return _httpContextAccessor.HttpContext?.Request.Headers["User-Agent"].ToString();
}
/// <summary>
/// دریافت Refresh Token از Header
/// </summary>
public string? GetRefreshTokenFromCookie()
{
return _httpContextAccessor.HttpContext?.Request.Cookies["rf-token"];
}
/// <summary>
/// بررسی احراز هویت کاربر جاری
/// </summary>
public bool IsAuthenticated()
{
return _httpContextAccessor.HttpContext?.User?.Identity?.IsAuthenticated ?? false;
}
/// <summary>
/// دریافت شناسه کاربر جاری از Claims
/// </summary>
public long? GetCurrentUserId()
{
var userIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst("pm.userId")?.Value;
return long.TryParse(userIdClaim, out var userId) ? userId : null;
}
/// <summary>
/// دریافت نام کاربری جاری از Claims
/// </summary>
public string? GetCurrentUserName()
{
return _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.Name)?.Value;
}
/// <summary>
/// دریافت نام کامل کاربر جاری از Claims
/// </summary>
public string? GetCurrentFullName()
{
return _httpContextAccessor.HttpContext?.User?.FindFirst("FullName")?.Value;
}
/// <summary>
/// دریافت AccountId کاربر جاری از Claims
/// </summary>
public long? GetCurrentAccountId()
{
var accountIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst("AccountId")?.Value;
return long.TryParse(accountIdClaim, out var accountId) ? accountId : null;
}
/// <summary>
/// دریافت نقش‌های کاربر جاری از Claims
/// </summary>
public List<string> GetCurrentUserRoles()
{
var roles = _httpContextAccessor.HttpContext?.User?.FindAll(ClaimTypes.Role)
.Select(c => c.Value)
.ToList();
return roles ?? new List<string>();
}
/// <summary>
/// بررسی دسترسی کاربر به نقش خاص
/// </summary>
public bool HasRole(string roleName)
{
return _httpContextAccessor.HttpContext?.User?.IsInRole(roleName) ?? false;
}
/// <summary>
/// بررسی دسترسی کاربر به یکی از نقش‌ها
/// </summary>
public bool HasAnyRole(params string[] roleNames)
{
return roleNames.Any(HasRole);
}
public void SignOut()
{
_httpContextAccessor.HttpContext?.Response.Cookies.Delete("rf-token");
_httpContextAccessor.HttpContext?.Response.Headers.Remove("Authorization");
}
}