AyCode.Core/AyCode.Services.Server/Logins/AcLoginServiceServer.cs

179 lines
7.6 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using AyCode.Core.Helpers;
using AyCode.Interfaces.Addresses;
using AyCode.Interfaces.Logins;
using AyCode.Interfaces.Profiles;
using AyCode.Interfaces.Server.Logins;
using AyCode.Interfaces.ServiceProviders;
using AyCode.Interfaces.Users;
using AyCode.Services.Logins;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using AyCode.Database.DataLayers;
using Microsoft.EntityFrameworkCore;
using AyCode.Database.DbContexts;
using AyCode.Core.Consts;
using AyCode.Core.Extensions;
using AyCode.Database.DataLayers.Users;
using AyCode.Database.DbContexts.Users;
using AyCode.Models.Logins;
using AyCode.Models.Server.Logins;
using AyCode.Utils.Extensions;
using AyCode.Utils.Helpers;
using Microsoft.Extensions.Configuration;
namespace AyCode.Services.Server.Logins;
public class AcLoginServiceServer<TResultLoggedInModel, TDal, TDbContext, TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>(TDal userDal, IConfiguration configuration)
: AcLoginServiceBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>, IAcLoginServiceServer<TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
where TResultLoggedInModel: class, IAcLoggedInModelBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
where TDal : AcUserDalBase<TDbContext, TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress>
where TDbContext : AcDbContextBase, IAcUserDbContextBase<TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress>
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
where TUserToken : class, IAcUserTokenBase
where TProfile : class, IAcProfile<TProfileAddress>
where TServiceProvider : class, IAcServiceProviderBase
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
where TProfileAddress : class, IAcAddress
{
public virtual TUser? Login(string email, string password, out string accessToken)
{
accessToken = string.Empty;
//var loginModel = Activator.CreateInstance<TResultLoggedInModel>();
if (!AcValidate.IsValidEmailAndPasswordFormat(email, password, out var errorCode)) return null;//return loginModel;
var user = userDal.GetUserByEmail(email);
if (user is not { EmailConfirmed: true } || !string.Equals(user.EmailAddress, email, StringComparison.CurrentCultureIgnoreCase)
|| !PasswordHasher.VerifyPassword(password, user.Password, GenerateDynamicSalt(user.Id))) return null;
//loginModel.LoggedInUser = user;
return LoggedInUser = user;
}
public virtual Task<TUser?> LoginAsync(string email, string password)
{
return TaskHelper.ToThreadPoolTask(() => Login(email, password, out _));
}
public virtual bool Logout()
{
LoggedInUser = null;
return true;
}
public virtual Task<bool> LogoutAsync()
{
return TaskHelper.ToThreadPoolTask(Logout);
}
public virtual TUser? Registration(string email, string password, string? phoneNumber = null)
=> Registration(Guid.NewGuid(), email, password, phoneNumber);
public virtual TUser? Registration(Guid userId, string email, string password, string? phoneNumber = null)
{
if ((phoneNumber != null && !AcValidate.IsValidPhoneNumberFormat(phoneNumber, out var errorCode)) ||
!AcValidate.IsValidEmailAndPasswordFormat(email, password, out errorCode)) return null;
var user = Activator.CreateInstance<TUser>();
user.Id = userId;
user.EmailAddress = email;
user.EmailConfirmed = true;
user.Password = PasswordHasher.HashPassword(password, GenerateDynamicSalt(userId));
var address = Activator.CreateInstance<TProfileAddress>();
address.Id = Guid.NewGuid();
var userName = email.Split('@')[0]; //TODO: generálni egy nevet... - J.
return userDal.AddUser(user, userName, address) ? null : userDal.GetUserById(userId);
}
public virtual Task<TUser?> RegistrationAsync(string email, string password, string? phoneNumber = null)
=> RegistrationAsync(Guid.NewGuid(), email, password, phoneNumber);
public virtual Task<TUser?> RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null)
{
return TaskHelper.ToThreadPoolTask(() => Registration(userId, email, password, phoneNumber));
}
//SEMMILYEN KÖRÜLMÉNYEK KÖZÖTT SE VÁLTOZTASD MEG METÓDUS LOGIKÁJÁT!!! Különben senki sem fog tudni Login-olni! - J.
public virtual string GenerateDynamicSalt(Guid userId)
=> userId.ToString("N").ToLower().Reverse().MixCharacters(AcConst.ProjectSalt);
private string GenerateAccessToken(TUser user)
{
var tokenHandler = new JwtSecurityTokenHandler();
Console.WriteLine("----------------------------------------------------------");
if (configuration["JWT:Key"] == null)
throw new SecurityTokenException("Token is null");
var keyDetail = Encoding.UTF8.GetBytes(configuration["JWT:Key"] ?? string.Empty);
Console.WriteLine(configuration["JWT:Key"]);
var claims = new List<Claim>
{
new(ClaimTypes.NameIdentifier, user.Id.ToString()),
new(ClaimTypes.Email, user.EmailAddress)
};
var tokenDescriptor = new SecurityTokenDescriptor
{
Audience = configuration["JWT:Audience"],
Issuer = configuration["JWT:Issuer"],
Expires = DateTime.UtcNow.AddMinutes(30),
Subject = new ClaimsIdentity(claims),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyDetail), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor) as JwtSecurityToken;
var writtenToken = tokenHandler.WriteToken(token);
Console.WriteLine(writtenToken);
return writtenToken;
}
private ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
if (configuration["JWT:Key"] == null)
throw new SecurityTokenException("Token is null");
var keyDetail = Encoding.UTF8.GetBytes(configuration["JWT:Key"] ?? string.Empty);
var tokenValidationParameter = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuer = configuration["JWT:Issuer"],
ValidAudience = configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(keyDetail),
};
var principal = tokenHandler.ValidateToken(token, tokenValidationParameter, out var securityToken);
if (securityToken is not JwtSecurityToken jwtSecurityToken || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
throw new SecurityTokenException("Invalid token");
return principal;
}
private string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}
}