133 lines
4.1 KiB
C#
133 lines
4.1 KiB
C#
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 {
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public interface IAuthenticationService {
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="siteId"></param>
|
|
/// <param name="requestData"></param>
|
|
/// <returns></returns>
|
|
(string?, IDomainResult) Post(Guid siteId, AuthenticationRequestModel requestData);
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public class AutheticationService : ServiceBase<AutheticationService>, IAuthenticationService {
|
|
|
|
private readonly IUserDataProvider _userDataProvider;
|
|
private readonly IHashService _hashService;
|
|
private readonly IJWTService _jwtService;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="logger"></param>
|
|
/// <param name="userDataProvider"></param>
|
|
/// <param name="hashService"></param>
|
|
/// <param name="jwtService"></param>
|
|
public AutheticationService (
|
|
ILogger<AutheticationService> logger,
|
|
IUserDataProvider userDataProvider,
|
|
IHashService hashService,
|
|
IJWTService jwtService
|
|
) : base(logger) {
|
|
_userDataProvider = userDataProvider;
|
|
_hashService = hashService;
|
|
_jwtService = jwtService;
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="siteId"></param>
|
|
/// <param name="requestData"></param>
|
|
/// <returns></returns>
|
|
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<string?>();
|
|
|
|
if (user.Passwords.Password == null)
|
|
return IDomainResult.Failed<string?>($"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<string?>();
|
|
|
|
// 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<string?>();
|
|
}
|
|
|
|
// Creating JWT token
|
|
var claims = new List<KeyValuePair<string, string>> {
|
|
new KeyValuePair<string, string>("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);
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="token"></param>
|
|
/// <returns></returns>
|
|
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();
|
|
}
|
|
}
|
|
}
|