using Core.Abstractions; using Core.DomainObjects; using DataProviders.Collections; using DomainResults.Common; using ExtensionMethods; using HashService; using JWTService; using WeatherForecast.Models.Requests; namespace WeatherForecast.Services { /// /// /// public interface IAuthenticationService { /// /// /// /// /// /// (string?, IDomainResult) Post(Guid siteId, AuthenticationRequestModel requestData); } /// /// /// public class AutheticationService : ServiceBase, IAuthenticationService { private readonly IUserDataProvider _userDataProvider; private readonly IHashService _hashService; private readonly IJWTService _jwtService; /// /// /// /// /// /// /// public AutheticationService ( ILogger logger, IUserDataProvider userDataProvider, IHashService hashService, IJWTService jwtService ) : base(logger) { _userDataProvider = userDataProvider; _hashService = hashService; _jwtService = jwtService; } /// /// /// /// /// /// public (string?, IDomainResult) Post(Guid siteId, AuthenticationRequestModel requestData) { var opId = Guid.NewGuid(); // Retrieve user from database by userName var (user, getUserResult) = _userDataProvider.GetByNickName(requestData.Username); if (!getUserResult.IsSuccess || user == null) return IDomainResult.NotFound(); if (user.Passwords.Password == null) return IDomainResult.Failed($"Opid = [{opId}] Password is not set, create new password."); // Check provided password hash with the stored one var (salt, hash) = _hashService.CreateSaltedHash(requestData.Password); if (!_hashService.ValidateHash(requestData.Password, salt, hash)) return IDomainResult.Unauthorized(); // Check password expiration if enabled if (user.Passwords.Expiration.Enabled && DateTime.UtcNow > user.Passwords.Password.Created.AddDays(user.Passwords.Expiration.Days)) { user.Passwords.Expired.Add(user.Passwords.Password.Prototype()); user.Passwords.Password = null; return IDomainResult.Failed(); } // Creating JWT token var claims = new List> { new KeyValuePair("UserId", $"{user.Id}") }; var created = DateTime.UtcNow; var expires = created.AddDays(365); var token = _jwtService.CreateJwtToken(expires, claims); user.Tokens.Add(new Token { Value = token, Created = created, Expires = expires, }); return IDomainResult.Success(token); } /// /// /// /// /// public IDomainResult Get(string token) { #region Retrieve user id from token claim var (claims, getClaimsResult) = _jwtService.JwtTokenClaims(token); if (!getClaimsResult.IsSuccess || claims == null) return IDomainResult.Failed(); var userId = claims.SingleOrDefault(x => x.Key == "UserId").Value.ToGuid(); if(userId == Guid.Empty) return IDomainResult.Failed(); #endregion var (user, getUserRersult) = _userDataProvider.Get(userId); if(!getUserRersult.IsSuccess || user == null) return IDomainResult.Failed(); // remove expired tokens user.Tokens = user.Tokens.Where(x => x.Expires < DateTime.UtcNow).ToList(); if (!user.Tokens.Any(x => x.Value == token)) return IDomainResult.Failed(); return IDomainResult.Success(); } } }