167 lines
6.5 KiB
C#
167 lines
6.5 KiB
C#
using Blazored.LocalStorage;
|
|
using FrontOffice.BFF.User.Protobuf.Protos.User;
|
|
using Microsoft.AspNetCore.Components;
|
|
using MudBlazor;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
|
|
namespace FrontOffice.Main.Utilities;
|
|
|
|
public class AuthService
|
|
{
|
|
private readonly ILocalStorageService _localStorage;
|
|
private readonly NavigationManager _navigation;
|
|
private readonly ISnackbar _snackbar;
|
|
private readonly UserAuthInfo _userAuthInfo;
|
|
private readonly UserContract.UserContractClient _userContract;
|
|
private readonly ILogger<AuthService> _logger;
|
|
|
|
private const string TokenStorageKey = "auth:token";
|
|
|
|
public AuthService(
|
|
ILocalStorageService localStorage,
|
|
NavigationManager navigation,
|
|
ISnackbar snackbar,
|
|
UserAuthInfo userAuthInfo,
|
|
UserContract.UserContractClient userContract,
|
|
ILogger<AuthService> logger)
|
|
{
|
|
_localStorage = localStorage;
|
|
_navigation = navigation;
|
|
_snackbar = snackbar;
|
|
_userAuthInfo = userAuthInfo;
|
|
_userContract = userContract;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<bool> IsAuthenticatedAsync()
|
|
{
|
|
var token = await _localStorage.GetItemAsync<string>(TokenStorageKey);
|
|
return !string.IsNullOrWhiteSpace(token);
|
|
}
|
|
|
|
public async Task<string?> GetTokenAsync()
|
|
{
|
|
return await _localStorage.GetItemAsync<string>(TokenStorageKey);
|
|
}
|
|
public async Task<bool> IsCompleteRegisterAsync()
|
|
{
|
|
await InitUserAuthInfo();
|
|
if (!string.IsNullOrWhiteSpace(_userAuthInfo.NationalCode) && !string.IsNullOrWhiteSpace(_userAuthInfo.FirstName) && !string.IsNullOrWhiteSpace(_userAuthInfo.LastName) && _userAuthInfo.IsSignMainContract)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
public bool IsCompleteRegister()
|
|
{
|
|
InitUserAuthInfo().GetAwaiter();
|
|
if (!string.IsNullOrWhiteSpace(_userAuthInfo.NationalCode) && !string.IsNullOrWhiteSpace(_userAuthInfo.FirstName) && !string.IsNullOrWhiteSpace(_userAuthInfo.LastName) && _userAuthInfo.IsSignMainContract)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
public async Task<UserAuthInfo> GetUserAuthInfo()
|
|
{
|
|
await InitUserAuthInfo();
|
|
return _userAuthInfo;
|
|
}
|
|
|
|
public async Task InitUserAuthInfo()
|
|
{
|
|
var claims = await GetTokenClaimsAsync();
|
|
_userAuthInfo.UserClaims= claims;
|
|
var userIdStr = claims.FirstOrDefault(c => c.key == "UserId" || c.key == "sub" || c.key == "nameid").value;
|
|
var firstName = claims.FirstOrDefault(c => c.key == "FirstName").value;
|
|
var lastName = claims.FirstOrDefault(c => c.key == "LastName").value;
|
|
var nationalCode = claims.FirstOrDefault(c => c.key == "NationalCode").value;
|
|
var mobileNumber = claims.FirstOrDefault(c => c.key == "MobileNumber").value;
|
|
var isSignMainContractStr = claims.FirstOrDefault(c => c.key == "IsSignMainContract").value;
|
|
var hasPurchasedPackageStr = claims.FirstOrDefault(c => c.key == "HasPurchasedPackage").value;
|
|
var isClubMemberActiveStr = claims.FirstOrDefault(c => c.key == "IsClubMemberActive").value;
|
|
|
|
_userAuthInfo.UserId = long.TryParse(userIdStr, out var userId) ? userId : 0;
|
|
_userAuthInfo.FirstName = firstName ?? string.Empty;
|
|
_userAuthInfo.LastName = lastName ?? string.Empty;
|
|
_userAuthInfo.NationalCode = nationalCode ?? string.Empty;
|
|
_userAuthInfo.MobileNumber = mobileNumber ?? string.Empty;
|
|
_userAuthInfo.IsSignMainContract = bool.TryParse(isSignMainContractStr, out var isSignMainContract) && isSignMainContract;
|
|
_userAuthInfo.HasPurchasedPackage = bool.TryParse(hasPurchasedPackageStr, out var hasPurchased) && hasPurchased;
|
|
_userAuthInfo.IsClubMemberActive = bool.TryParse(isClubMemberActiveStr, out var isClubActive) && isClubActive;
|
|
}
|
|
|
|
private async Task<List<(string key, string value)>?> GetTokenClaimsAsync()
|
|
{
|
|
var token = await GetTokenAsync();
|
|
if (string.IsNullOrEmpty(token)) return null;
|
|
var handler = new JwtSecurityTokenHandler();
|
|
var jwtToken = handler.ReadJwtToken(token);
|
|
return jwtToken.Claims.Select(c => (c.Type, c.Value)).ToList();
|
|
}
|
|
|
|
public async Task LogoutAsync()
|
|
{
|
|
await _localStorage.RemoveItemAsync(TokenStorageKey);
|
|
await _localStorage.RemoveItemAsync("auth:phone-number");
|
|
await _localStorage.RemoveItemAsync("auth:redirect");
|
|
await _localStorage.RemoveItemAsync("referral:code");
|
|
|
|
_snackbar.Add("با موفقیت از حساب کاربری خارج شدید.", Severity.Success);
|
|
_navigation.NavigateTo(RouteConstants.Main.MainPage);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refresh the user's token by calling the BFF RefreshToken API.
|
|
/// If successful, the new token is stored and user info is updated.
|
|
/// </summary>
|
|
/// <returns>True if token was refreshed successfully</returns>
|
|
public async Task<bool> RefreshTokenAsync()
|
|
{
|
|
try
|
|
{
|
|
var currentToken = await GetTokenAsync();
|
|
if (string.IsNullOrEmpty(currentToken))
|
|
{
|
|
_logger.LogWarning("No token found for refresh");
|
|
return false;
|
|
}
|
|
|
|
var response = await _userContract.RefreshTokenAsync(new RefreshTokenRequest
|
|
{
|
|
CurrentToken = currentToken
|
|
});
|
|
|
|
if (response.Success && !string.IsNullOrEmpty(response.Token))
|
|
{
|
|
// Store the new token
|
|
await _localStorage.SetItemAsync(TokenStorageKey, response.Token);
|
|
|
|
// Update user auth info with new token claims
|
|
await InitUserAuthInfo();
|
|
|
|
_logger.LogInformation("Token refreshed successfully");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
_logger.LogInformation("Token refresh not needed: {Message}", response.Message);
|
|
return false;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to refresh token");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task RequireAuthenticationAsync()
|
|
{
|
|
var isAuthenticated = await IsAuthenticatedAsync();
|
|
if (!isAuthenticated)
|
|
{
|
|
_snackbar.Add("لطفاً ابتدا وارد حساب کاربری شوید.", Severity.Warning);
|
|
_navigation.NavigateTo(RouteConstants.Main.MainPage);
|
|
}
|
|
}
|
|
} |