| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Diligent.WebAPI.Business.Helper | |||||
| { | |||||
| public static class HTMLHelper | |||||
| { | |||||
| public static string RenderForgotPasswordPage(string url) | |||||
| { | |||||
| return "<div style=\"font-family: sans-serif\">" + | |||||
| "<div style=\"font-family: sans-serif;text-align: center;\">" + | |||||
| "<h2 style=\"color: #017397;\">HR Center Password Reset</h2>" + | |||||
| "<p style=\"font-size: 20px\">" + | |||||
| "To reset your HR Center password, please click on the button below." + | |||||
| "</p>" + | |||||
| "<a style = \"color: white;text-decoration:none;background-color: #017397;cursor: pointer;font-size: 20px;width: 220px;text-align: center;border-radius: 5px;padding: 5px 15px;height: 25px;\" " + | |||||
| $"href=\"{url}\">" + | |||||
| " RESET PASSWORD" + | |||||
| "</a>" + | |||||
| "<p style = \"font-size: 12px; margin-top: 25px;\" >" + | |||||
| "Please do not reply to this email.This message was sent from a notification-only address that is not monitored." + | |||||
| "</p>" + | |||||
| "</div>" + | |||||
| "</div>"; | |||||
| } | |||||
| } | |||||
| } |
| | |||||
| namespace Diligent.WebAPI.Business.Services | |||||
| namespace Diligent.WebAPI.Business.Services | |||||
| { | { | ||||
| public class AdService : IAdService | public class AdService : IAdService | ||||
| { | { |
| using Microsoft.AspNetCore.WebUtilities; | |||||
| using Microsoft.Extensions.Logging; | |||||
| using System.Net; | |||||
| namespace Diligent.WebAPI.Business.Services | |||||
| { | |||||
| public class AuthenticationService : IAuthenticationService | |||||
| { | |||||
| private readonly AuthorizationSettings _authSettings; | |||||
| private readonly FrontEndSettings _frontEndSettings; | |||||
| private readonly UserManager<User> _userManager; | |||||
| private readonly DatabaseContext _databaseContext; | |||||
| private readonly IEmailer _emailer; | |||||
| private readonly ILogger<AuthenticationService> _logger; | |||||
| private readonly IHttpClientService _httpClient; | |||||
| public AuthenticationService(IOptions<AuthorizationSettings> authSettings, | |||||
| IOptions<FrontEndSettings> frontEndSettings, | |||||
| UserManager<User> userManager, | |||||
| DatabaseContext databaseContext, | |||||
| IEmailer emailer, | |||||
| ILogger<AuthenticationService> logger, | |||||
| IHttpClientService httpClient) | |||||
| { | |||||
| _authSettings = authSettings.Value; | |||||
| _frontEndSettings = frontEndSettings.Value; | |||||
| _userManager = userManager; | |||||
| _databaseContext = databaseContext; | |||||
| _httpClient = httpClient; | |||||
| _emailer = emailer; | |||||
| _logger = logger; | |||||
| } | |||||
| public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model) | |||||
| { | |||||
| var user = await _userManager.FindByNameAsync(model.Username); | |||||
| // return null if user not found | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Username is not valid" | |||||
| }; | |||||
| } | |||||
| var result = await _userManager.CheckPasswordAsync(user, model.Password); | |||||
| // password is not correct | |||||
| if (!result) | |||||
| { | |||||
| await _userManager.AccessFailedAsync(user); | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Password is not correct" | |||||
| }; | |||||
| } | |||||
| return await GenerateToken(user); | |||||
| } | |||||
| public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiModel model) | |||||
| { | |||||
| if (!(await _httpClient.IsTokenValid(model.Token))) | |||||
| { | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Invalid Google Api Token" | |||||
| }; | |||||
| } | |||||
| var user = await _userManager.FindByEmailAsync(model.User.email); | |||||
| // return null if user not found | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = $"User with email {model.User.email} does not exist in database" | |||||
| }; | |||||
| } | |||||
| return await GenerateToken(user); | |||||
| } | |||||
| private async Task<ServiceResponseDTO<AuthenticateResponseDto>> GenerateToken(User user) | |||||
| { | |||||
| var isLocked = await _userManager.IsLockedOutAsync(user); | |||||
| if (isLocked) | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "The account is locked out" | |||||
| }; | |||||
| // authentication successful so generate jwt token | |||||
| var token = await GenerateJwtToken(user, true); | |||||
| var data = new AuthenticateResponseDto | |||||
| { | |||||
| Id = user.Id, | |||||
| Username = user.UserName, | |||||
| FirstName = user.FirstName, | |||||
| LastName = user.LastName, | |||||
| Token = token, | |||||
| RefreshToken = token | |||||
| }; | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| Data = data | |||||
| }; | |||||
| } | |||||
| private async Task<string> GenerateJwtToken(User user, bool authenticate = false) | |||||
| { | |||||
| // generate token that is valid for 7 days | |||||
| var tokenHandler = new JwtSecurityTokenHandler(); | |||||
| var key = Encoding.ASCII.GetBytes(_authSettings.Secret); | |||||
| var tokenDescriptor = new SecurityTokenDescriptor | |||||
| { | |||||
| Subject = new ClaimsIdentity(new[] { | |||||
| new Claim(JwtRegisteredClaimNames.Jti, user.Id.ToString()), | |||||
| new Claim("id", user.Id.ToString()) | |||||
| }), | |||||
| Expires = DateTime.UtcNow.AddMinutes(_authSettings.JwtExpiredTime), | |||||
| SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) | |||||
| }; | |||||
| var token = tokenHandler.CreateToken(tokenDescriptor); | |||||
| var writedToken = tokenHandler.WriteToken(token); | |||||
| var refreshToken = new RefreshToken | |||||
| { | |||||
| Token = writedToken, | |||||
| JwtId = user.Id.ToString(), | |||||
| UserId = user.Id, | |||||
| User = user, | |||||
| CreationDate = DateTime.UtcNow, | |||||
| ExpiryDate = DateTime.UtcNow.AddMinutes(_authSettings.JwtRefreshExpiredTime) | |||||
| }; | |||||
| var existRefreshToken = await _databaseContext.RefreshTokens.Where(x => x.UserId == user.Id).FirstOrDefaultAsync(); | |||||
| if (existRefreshToken != null) | |||||
| { | |||||
| existRefreshToken.Token = writedToken; | |||||
| existRefreshToken.JwtId = token.Id; | |||||
| existRefreshToken.CreationDate = DateTime.UtcNow; | |||||
| existRefreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(_authSettings.JwtRefreshExpiredTime); | |||||
| if (authenticate) | |||||
| { | |||||
| existRefreshToken.Used = false; | |||||
| existRefreshToken.Invalidated = false; | |||||
| } | |||||
| _databaseContext.RefreshTokens.Update(existRefreshToken); | |||||
| await UpdateRefreshToken(existRefreshToken); | |||||
| } | |||||
| else | |||||
| { | |||||
| await _databaseContext.RefreshTokens.AddAsync(refreshToken); | |||||
| } | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| return writedToken; | |||||
| } | |||||
| public async Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto model) | |||||
| { | |||||
| var validatedToken = GetPrincipalFromToken(model.Token, false); | |||||
| if (validatedToken == null) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "Invalid token" }; | |||||
| } | |||||
| var jti = validatedToken.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Jti).Value; | |||||
| var storedRefreshToken = await _databaseContext.RefreshTokens.SingleOrDefaultAsync(x => x.JwtId == jti); | |||||
| if (storedRefreshToken == null) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token does not exist" }; | |||||
| } | |||||
| var userk = await _databaseContext.Users.Where(u => u.Id == storedRefreshToken.UserId).FirstOrDefaultAsync(); | |||||
| if (userk == null) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "There is no user which is associated with refresh token" }; | |||||
| } | |||||
| var expiryDateUnix = long.Parse(validatedToken.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Exp).Value); | |||||
| var expiryDateTimeUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) | |||||
| .AddMinutes(expiryDateUnix); | |||||
| if (expiryDateTimeUtc < DateTime.UtcNow) | |||||
| { | |||||
| return new RefreshTokenResultDto | |||||
| { | |||||
| Data = new AuthenticateResponseDto | |||||
| { | |||||
| Id = userk.Id, | |||||
| FirstName = userk.FirstName, | |||||
| LastName = userk.LastName, | |||||
| Username = userk.UserName, | |||||
| Token = model.Token, | |||||
| RefreshToken = model.RefreshToken | |||||
| } | |||||
| }; | |||||
| } | |||||
| if (DateTime.UtcNow > storedRefreshToken.ExpiryDate) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token has expired" }; | |||||
| } | |||||
| if (storedRefreshToken.Invalidated) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token has been invalidated" }; | |||||
| } | |||||
| if (storedRefreshToken.JwtId != jti) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token does not match this JWT" }; | |||||
| } | |||||
| storedRefreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(_authSettings.JwtRefreshExpiredTime); | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| var user = await _userManager.FindByIdAsync(validatedToken.Claims.Single(x => x.Type == "id").Value); | |||||
| var token = await GenerateJwtToken(user); | |||||
| return new RefreshTokenResultDto | |||||
| { | |||||
| Data = new AuthenticateResponseDto | |||||
| { | |||||
| Id = userk.Id, | |||||
| FirstName = userk.FirstName, | |||||
| LastName = userk.LastName, | |||||
| Username = userk.UserName, | |||||
| Token = model.Token, | |||||
| RefreshToken = model.RefreshToken | |||||
| } | |||||
| }; | |||||
| } | |||||
| public async Task<ServiceResponseDTO<string>> DeleteRefreshToken(int userId) | |||||
| { | |||||
| var refreshToken = await _databaseContext.RefreshTokens.Where(r => r.UserId == userId).FirstOrDefaultAsync(); | |||||
| if (refreshToken is null) | |||||
| return new ServiceResponseDTO<string> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "There is no refresh token for user" | |||||
| }; | |||||
| _databaseContext.RefreshTokens.Remove(refreshToken); | |||||
| var result = await _databaseContext.SaveChangesAsync() > 0; | |||||
| if (!result) | |||||
| return new ServiceResponseDTO<string> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Problem with saving changes into database" | |||||
| }; | |||||
| return new ServiceResponseDTO<string> | |||||
| { | |||||
| Data = null | |||||
| }; | |||||
| } | |||||
| private ClaimsPrincipal? GetPrincipalFromToken(string token, bool validateLifetime) | |||||
| { | |||||
| var tokenHandler = new JwtSecurityTokenHandler(); | |||||
| var key = Encoding.ASCII.GetBytes(_authSettings.Secret); | |||||
| var tokenValidationParameters = new TokenValidationParameters | |||||
| { | |||||
| ValidateIssuerSigningKey = true, | |||||
| IssuerSigningKey = new SymmetricSecurityKey(key), | |||||
| ValidateIssuer = false, | |||||
| ValidateAudience = false, | |||||
| RequireExpirationTime = false, | |||||
| ValidateLifetime = validateLifetime, | |||||
| // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later) | |||||
| //ClockSkew = TimeSpan.Zero | |||||
| }; | |||||
| try | |||||
| { | |||||
| var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var validatedToken); | |||||
| if (!IsJwtWithValidSecurityAlgorithm(validatedToken)) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| return principal; | |||||
| } | |||||
| catch (Exception) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| private static bool IsJwtWithValidSecurityAlgorithm(SecurityToken validatedToken) | |||||
| { | |||||
| return (validatedToken is JwtSecurityToken jwtSecurityToken) && | |||||
| jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, | |||||
| StringComparison.InvariantCultureIgnoreCase); | |||||
| } | |||||
| public async Task<RefreshToken?> GetRefreshTokenByUserId(int userId) | |||||
| { | |||||
| return await _databaseContext.RefreshTokens.Where(x => x.UserId == userId).FirstOrDefaultAsync(); | |||||
| } | |||||
| public async Task UpdateRefreshToken(RefreshToken refreshToken) | |||||
| { | |||||
| _databaseContext.RefreshTokens.Update(refreshToken); | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| } | |||||
| public async Task<ServiceResponseDTO<object>> GetEmailConfirmationUrlAsync(string email) | |||||
| { | |||||
| var user = await _userManager.FindByEmailAsync(email); | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Email did not find." | |||||
| }; | |||||
| } | |||||
| var token = await _userManager.GenerateEmailConfirmationTokenAsync(user); | |||||
| token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token)); | |||||
| await _emailer.SendEmailAndWriteToDbAsync(email, "Reset password", HTMLHelper.RenderForgotPasswordPage($"{_frontEndSettings.BaseUrl}/reset-password?token={token}&email={email}"), isHtml: true); | |||||
| user.PasswordResetToken = token; | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| Data = new { code = token, email = email } | |||||
| }; | |||||
| } | |||||
| public async Task<ServiceResponseDTO<object>> PasswordResetAsync(string email, string code, string password) | |||||
| { | |||||
| var user = await _userManager.FindByEmailAsync(email); | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Email did not find." | |||||
| }; | |||||
| } | |||||
| // FOR SOME REASON USERMANAGER.RESETPASSWORDASYNC returns InvalidToken. In future change this | |||||
| //var passwordResetToken = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); | |||||
| //IdentityResult resetResult = await _userManager.ResetPasswordAsync(user, passwordResetToken, password); | |||||
| //if (resetResult.Succeeded) | |||||
| await _userManager.RemovePasswordAsync(user); | |||||
| await _userManager.AddPasswordAsync(user, password); | |||||
| if (user.PasswordResetToken == code) | |||||
| { | |||||
| if (await _userManager.IsLockedOutAsync(user)) | |||||
| { | |||||
| await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow); | |||||
| } | |||||
| return new ServiceResponseDTO<object> { Data = true }; | |||||
| } | |||||
| //var errors = resetResult.Errors.Select(x => x.Description); | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Invalid reset password token" | |||||
| }; | |||||
| } | |||||
| } | |||||
| } |
| using System.Net; | |||||
| namespace Diligent.WebAPI.Business.Services | |||||
| { | |||||
| public class HttpClientService : IHttpClientService | |||||
| { | |||||
| private const string GoogleApiTokenInfoUrl = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}"; | |||||
| private string[] SupportedClientsIds = { "" }; | |||||
| private readonly AuthorizationSettings _authSettings; | |||||
| public HttpClientService(IOptions<AuthorizationSettings> authSettings) | |||||
| { | |||||
| _authSettings = authSettings.Value; | |||||
| } | |||||
| public async Task<bool> IsTokenValid(string providerToken) | |||||
| { | |||||
| var httpClient = new HttpClient(); | |||||
| var requestUri = new Uri(string.Format(GoogleApiTokenInfoUrl, providerToken)); | |||||
| HttpResponseMessage httpResponseMessage; | |||||
| try | |||||
| { | |||||
| httpResponseMessage = httpClient.GetAsync(requestUri).Result; | |||||
| } | |||||
| catch | |||||
| { | |||||
| return false; | |||||
| } | |||||
| if (httpResponseMessage.StatusCode != HttpStatusCode.OK) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| var response = httpResponseMessage.Content.ReadAsStringAsync().Result; | |||||
| var googleApiTokenInfo = JsonConvert.DeserializeObject<GoogleApiTokenInfo>(response); | |||||
| //if (!SupportedClientsIds.Contains(googleApiTokenInfo.aud)) | |||||
| if (googleApiTokenInfo.aud != _authSettings.GoogleClientId) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } |
| namespace Diligent.WebAPI.Business.Services.Interfaces | |||||
| { | |||||
| public interface IAuthenticationService | |||||
| { | |||||
| Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model); | |||||
| Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiModel model); | |||||
| Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto model); | |||||
| Task<RefreshToken?> GetRefreshTokenByUserId(int userId); | |||||
| Task UpdateRefreshToken(RefreshToken refreshToken); | |||||
| Task<ServiceResponseDTO<string>> DeleteRefreshToken(int userId); | |||||
| Task<ServiceResponseDTO<object>> GetEmailConfirmationUrlAsync(string email); | |||||
| Task<ServiceResponseDTO<object>> PasswordResetAsync(string email, string code, string password); | |||||
| } | |||||
| } |
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Diligent.WebAPI.Business.Services.Interfaces | |||||
| { | |||||
| public interface IHttpClientService | |||||
| { | |||||
| Task<bool> IsTokenValid(string providedToken); | |||||
| } | |||||
| } |
| { | { | ||||
| public interface IUserService | public interface IUserService | ||||
| { | { | ||||
| Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model); | |||||
| Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiModel model); | |||||
| Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto model); | |||||
| Task<IEnumerable<User?>> GetAll(); | Task<IEnumerable<User?>> GetAll(); | ||||
| Task<User?> GetById(int id); | Task<User?> GetById(int id); | ||||
| Task CreateUser(CreateUserRequestDto model); | Task CreateUser(CreateUserRequestDto model); | ||||
| Task<RefreshToken?> GetRefreshTokenByUserId(int userId); | |||||
| Task UpdateRefreshToken(RefreshToken refreshToken); | |||||
| Task<ServiceResponseDTO<string>> DeleteRefreshToken(int userId); | |||||
| Task<ServiceResponseDTO<object>> GetEmailConfirmationUrlAsync(string email); | |||||
| Task<ServiceResponseDTO<object>> PasswordResetAsync(string email, string code, string password); | |||||
| } | } | ||||
| } | } |
| using Microsoft.AspNetCore.WebUtilities; | |||||
| using Diligent.WebAPI.Business.Services.Interfaces; | |||||
| using Diligent.WebAPI.Business.Settings; | |||||
| using Diligent.WebAPI.Data; | |||||
| using Microsoft.AspNetCore.Identity; | |||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
| using System.Net; | |||||
| namespace Diligent.WebAPI.Business.Services | namespace Diligent.WebAPI.Business.Services | ||||
| { | { | ||||
| await _userManager.CreateAsync(user, model.Password); | await _userManager.CreateAsync(user, model.Password); | ||||
| } | } | ||||
| private bool IsTokenValid(string providerToken) | |||||
| { | |||||
| var httpClient = new HttpClient(); | |||||
| var requestUri = new Uri(string.Format(GoogleApiTokenInfoUrl, providerToken)); | |||||
| HttpResponseMessage httpResponseMessage; | |||||
| try | |||||
| { | |||||
| httpResponseMessage = httpClient.GetAsync(requestUri).Result; | |||||
| } | |||||
| catch (Exception ex) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| if (httpResponseMessage.StatusCode != HttpStatusCode.OK) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| var response = httpResponseMessage.Content.ReadAsStringAsync().Result; | |||||
| var googleApiTokenInfo = JsonConvert.DeserializeObject<GoogleApiTokenInfo>(response); | |||||
| //if (!SupportedClientsIds.Contains(googleApiTokenInfo.aud)) | |||||
| if(googleApiTokenInfo.aud != _authSettings.GoogleClientId) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(AuthenticateRequestDto model) | |||||
| { | |||||
| var user = await _userManager.FindByNameAsync(model.Username); | |||||
| // return null if user not found | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Username is not valid" | |||||
| }; | |||||
| } | |||||
| var result = await _userManager.CheckPasswordAsync(user, model.Password); | |||||
| // password is not correct | |||||
| if (!result) | |||||
| { | |||||
| await _userManager.AccessFailedAsync(user); | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Password is not correct" | |||||
| }; | |||||
| } | |||||
| return await GenerateToken(user); | |||||
| } | |||||
| public async Task<ServiceResponseDTO<AuthenticateResponseDto>> Authenticate(GoogleApiModel model) | |||||
| { | |||||
| if (!IsTokenValid(model.Token)) | |||||
| { | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Invalid Google Api Token" | |||||
| }; | |||||
| } | |||||
| var user = await _userManager.FindByEmailAsync(model.User.email); | |||||
| // return null if user not found | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = $"User with email {model.User.email} does not exist in database" | |||||
| }; | |||||
| } | |||||
| return await GenerateToken(user); | |||||
| } | |||||
| private async Task<ServiceResponseDTO<AuthenticateResponseDto>> GenerateToken(User user) | |||||
| { | |||||
| var isLocked = await _userManager.IsLockedOutAsync(user); | |||||
| if (isLocked) | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "The account is locked out" | |||||
| }; | |||||
| // authentication successful so generate jwt token | |||||
| var token = await GenerateJwtToken(user, true); | |||||
| var data = new AuthenticateResponseDto | |||||
| { | |||||
| Id = user.Id, | |||||
| Username = user.UserName, | |||||
| FirstName = user.FirstName, | |||||
| LastName = user.LastName, | |||||
| Token = token, | |||||
| RefreshToken = token | |||||
| }; | |||||
| return new ServiceResponseDTO<AuthenticateResponseDto> | |||||
| { | |||||
| Data = data | |||||
| }; | |||||
| } | |||||
| private async Task<string> GenerateJwtToken(User user, bool authenticate = false) | |||||
| { | |||||
| // generate token that is valid for 7 days | |||||
| var tokenHandler = new JwtSecurityTokenHandler(); | |||||
| var key = Encoding.ASCII.GetBytes(_authSettings.Secret); | |||||
| var tokenDescriptor = new SecurityTokenDescriptor | |||||
| { | |||||
| Subject = new ClaimsIdentity(new[] { | |||||
| new Claim(JwtRegisteredClaimNames.Jti, user.Id.ToString()), | |||||
| new Claim("id", user.Id.ToString()) | |||||
| }), | |||||
| Expires = DateTime.UtcNow.AddMinutes(_authSettings.JwtExpiredTime), | |||||
| SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) | |||||
| }; | |||||
| var token = tokenHandler.CreateToken(tokenDescriptor); | |||||
| var writedToken = tokenHandler.WriteToken(token); | |||||
| var refreshToken = new RefreshToken | |||||
| { | |||||
| Token = writedToken, | |||||
| JwtId = user.Id.ToString(), | |||||
| UserId = user.Id, | |||||
| User = user, | |||||
| CreationDate = DateTime.UtcNow, | |||||
| ExpiryDate = DateTime.UtcNow.AddMinutes(_authSettings.JwtRefreshExpiredTime) | |||||
| }; | |||||
| var existRefreshToken = await _databaseContext.RefreshTokens.Where(x => x.UserId == user.Id).FirstOrDefaultAsync(); | |||||
| if (existRefreshToken != null) | |||||
| { | |||||
| existRefreshToken.Token = writedToken; | |||||
| existRefreshToken.JwtId = token.Id; | |||||
| existRefreshToken.CreationDate = DateTime.UtcNow; | |||||
| existRefreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(_authSettings.JwtRefreshExpiredTime); | |||||
| if (authenticate) | |||||
| { | |||||
| existRefreshToken.Used = false; | |||||
| existRefreshToken.Invalidated = false; | |||||
| } | |||||
| _databaseContext.RefreshTokens.Update(existRefreshToken); | |||||
| await UpdateRefreshToken(existRefreshToken); | |||||
| } | |||||
| else | |||||
| { | |||||
| await _databaseContext.RefreshTokens.AddAsync(refreshToken); | |||||
| } | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| return writedToken; | |||||
| } | |||||
| public async Task<RefreshTokenResultDto> RefreshTokenAsync(RefreshTokenRequestDto model) | |||||
| { | |||||
| var validatedToken = GetPrincipalFromToken(model.Token, false); | |||||
| if (validatedToken == null) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "Invalid token" }; | |||||
| } | |||||
| var jti = validatedToken.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Jti).Value; | |||||
| var storedRefreshToken = await _databaseContext.RefreshTokens.SingleOrDefaultAsync(x => x.JwtId == jti); | |||||
| if (storedRefreshToken == null) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token does not exist" }; | |||||
| } | |||||
| var userk = await _databaseContext.Users.Where(u => u.Id == storedRefreshToken.UserId).FirstOrDefaultAsync(); | |||||
| if (userk == null) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "There is no user which is associated with refresh token" }; | |||||
| } | |||||
| var expiryDateUnix = long.Parse(validatedToken.Claims.Single(x => x.Type == JwtRegisteredClaimNames.Exp).Value); | |||||
| var expiryDateTimeUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) | |||||
| .AddMinutes(expiryDateUnix); | |||||
| if (expiryDateTimeUtc < DateTime.UtcNow) | |||||
| { | |||||
| return new RefreshTokenResultDto | |||||
| { | |||||
| Data = new AuthenticateResponseDto | |||||
| { | |||||
| Id = userk.Id, | |||||
| FirstName = userk.FirstName, | |||||
| LastName = userk.LastName, | |||||
| Username = userk.UserName, | |||||
| Token = model.Token, | |||||
| RefreshToken = model.RefreshToken | |||||
| } | |||||
| }; | |||||
| } | |||||
| if (DateTime.UtcNow > storedRefreshToken.ExpiryDate) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token has expired" }; | |||||
| } | |||||
| if (storedRefreshToken.Invalidated) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token has been invalidated" }; | |||||
| } | |||||
| if (storedRefreshToken.JwtId != jti) | |||||
| { | |||||
| return new RefreshTokenResultDto { Error = "This refresh token does not match this JWT" }; | |||||
| } | |||||
| storedRefreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(_authSettings.JwtRefreshExpiredTime); | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| var user = await _userManager.FindByIdAsync(validatedToken.Claims.Single(x => x.Type == "id").Value); | |||||
| var token = await GenerateJwtToken(user); | |||||
| return new RefreshTokenResultDto | |||||
| { | |||||
| Data = new AuthenticateResponseDto | |||||
| { | |||||
| Id = userk.Id, | |||||
| FirstName = userk.FirstName, | |||||
| LastName = userk.LastName, | |||||
| Username = userk.UserName, | |||||
| Token = model.Token, | |||||
| RefreshToken = model.RefreshToken | |||||
| } | |||||
| }; | |||||
| } | |||||
| public async Task<ServiceResponseDTO<string>> DeleteRefreshToken(int userId) | |||||
| { | |||||
| var refreshToken = await _databaseContext.RefreshTokens.Where(r => r.UserId == userId).FirstOrDefaultAsync(); | |||||
| if (refreshToken is null) | |||||
| return new ServiceResponseDTO<string> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "There is no refresh token for user" | |||||
| }; | |||||
| _databaseContext.RefreshTokens.Remove(refreshToken); | |||||
| var result = await _databaseContext.SaveChangesAsync() > 0; | |||||
| if (!result) | |||||
| return new ServiceResponseDTO<string> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Problem with saving changes into database" | |||||
| }; | |||||
| return new ServiceResponseDTO<string> | |||||
| { | |||||
| Data = null | |||||
| }; | |||||
| } | |||||
| private ClaimsPrincipal? GetPrincipalFromToken(string token, bool validateLifetime) | |||||
| { | |||||
| var tokenHandler = new JwtSecurityTokenHandler(); | |||||
| var key = Encoding.ASCII.GetBytes(_authSettings.Secret); | |||||
| var tokenValidationParameters = new TokenValidationParameters | |||||
| { | |||||
| ValidateIssuerSigningKey = true, | |||||
| IssuerSigningKey = new SymmetricSecurityKey(key), | |||||
| ValidateIssuer = false, | |||||
| ValidateAudience = false, | |||||
| RequireExpirationTime = false, | |||||
| ValidateLifetime = validateLifetime, | |||||
| // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later) | |||||
| //ClockSkew = TimeSpan.Zero | |||||
| }; | |||||
| try | |||||
| { | |||||
| var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var validatedToken); | |||||
| if (!IsJwtWithValidSecurityAlgorithm(validatedToken)) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| return principal; | |||||
| } | |||||
| catch (Exception) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| private static bool IsJwtWithValidSecurityAlgorithm(SecurityToken validatedToken) | |||||
| { | |||||
| return (validatedToken is JwtSecurityToken jwtSecurityToken) && | |||||
| jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, | |||||
| StringComparison.InvariantCultureIgnoreCase); | |||||
| } | |||||
| public async Task<RefreshToken?> GetRefreshTokenByUserId(int userId) | |||||
| { | |||||
| return await _databaseContext.RefreshTokens.Where(x => x.UserId == userId).FirstOrDefaultAsync(); | |||||
| } | |||||
| public async Task UpdateRefreshToken(RefreshToken refreshToken) | |||||
| { | |||||
| _databaseContext.RefreshTokens.Update(refreshToken); | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| } | |||||
| public async Task<ServiceResponseDTO<object>> GetEmailConfirmationUrlAsync(string email) | |||||
| { | |||||
| var user = await _userManager.FindByEmailAsync(email); | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Email did not find." | |||||
| }; | |||||
| } | |||||
| var token = await _userManager.GenerateEmailConfirmationTokenAsync(user); | |||||
| token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token)); | |||||
| await _emailer.SendEmailAndWriteToDbAsync(email, "Reset password", renderHTMLtoString($"{_frontEndSettings.BaseUrl}/reset-password?token={token}&email={email}"), isHtml: true); | |||||
| user.PasswordResetToken = token; | |||||
| await _databaseContext.SaveChangesAsync(); | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| Data = new { code = token, email = email } | |||||
| }; | |||||
| } | |||||
| private string renderHTMLtoString(string url) | |||||
| { | |||||
| return "<div style=\"font-family: sans-serif\">" + | |||||
| "<div style=\"font-family: sans-serif;text-align: center;\">" + | |||||
| "<h2 style=\"color: #017397;\">HR Center Password Reset</h2>" + | |||||
| "<p style=\"font-size: 20px\">" + | |||||
| "To reset your HR Center password, please click on the button below." + | |||||
| "</p>" + | |||||
| "<a style = \"color: white;text-decoration:none;background-color: #017397;cursor: pointer;font-size: 20px;width: 220px;text-align: center;border-radius: 5px;padding: 5px 15px;height: 25px;\" " + | |||||
| $"href=\"{url}\">" + | |||||
| " RESET PASSWORD" + | |||||
| "</a>" + | |||||
| "<p style = \"font-size: 12px; margin-top: 25px;\" >" + | |||||
| "Please do not reply to this email.This message was sent from a notification-only address that is not monitored." + | |||||
| "</p>" + | |||||
| "</div>" + | |||||
| "</div>"; | |||||
| } | |||||
| public async Task<ServiceResponseDTO<object>> PasswordResetAsync(string email, string code, string password) | |||||
| { | |||||
| var user = await _userManager.FindByEmailAsync(email); | |||||
| if (user == null) | |||||
| { | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Email did not find." | |||||
| }; | |||||
| } | |||||
| // FOR SOME REASON USERMANAGER.RESETPASSWORDASYNC returns InvalidToken. In future change this | |||||
| //var passwordResetToken = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); | |||||
| //IdentityResult resetResult = await _userManager.ResetPasswordAsync(user, passwordResetToken, password); | |||||
| //if (resetResult.Succeeded) | |||||
| await _userManager.RemovePasswordAsync(user); | |||||
| await _userManager.AddPasswordAsync(user, password); | |||||
| if(user.PasswordResetToken == code) | |||||
| { | |||||
| if (await _userManager.IsLockedOutAsync(user)) | |||||
| { | |||||
| await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow); | |||||
| } | |||||
| return new ServiceResponseDTO<object> { Data = true }; | |||||
| } | |||||
| //var errors = resetResult.Errors.Select(x => x.Description); | |||||
| return new ServiceResponseDTO<object> | |||||
| { | |||||
| IsError = true, | |||||
| ErrorMessage = "Invalid reset password token" | |||||
| }; | |||||
| } | |||||
| } | } | ||||
| } | } |
| global using Diligent.WebAPI.Business.Services.Interfaces; | global using Diligent.WebAPI.Business.Services.Interfaces; | ||||
| global using Diligent.WebAPI.Business.Settings; | global using Diligent.WebAPI.Business.Settings; | ||||
| global using Diligent.WebAPI.Business.Helper; | |||||
| global using Diligent.WebAPI.Data; | global using Diligent.WebAPI.Data; | ||||
| global using Diligent.WebAPI.Data.Entities; | global using Diligent.WebAPI.Data.Entities; |
| namespace Diligent.WebAPI.Host.Controllers.V1 | |||||
| { | |||||
| [ApiVersion("1.0")] | |||||
| [Route("v{version:apiVersion}/authentications")] | |||||
| [ApiController] | |||||
| public class AuthenticationsController : ControllerBase | |||||
| { | |||||
| private readonly IAuthenticationService _service; | |||||
| public AuthenticationsController(IAuthenticationService service) | |||||
| { | |||||
| _service = service; | |||||
| } | |||||
| [HttpGet("ForgotPassword")] | |||||
| public async Task<IActionResult> ForgotPassword(string email) | |||||
| { | |||||
| var response = await _service.GetEmailConfirmationUrlAsync(email); | |||||
| if (response.IsError is true) | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| return Ok(response.Data); | |||||
| } | |||||
| [HttpPost("RessetPassword")] | |||||
| public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordModel model) | |||||
| { | |||||
| var response = await _service.PasswordResetAsync(email: model.Email, code: model.Code, password: model.Password); | |||||
| if (response.IsError is true) | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| return Ok(response.Data); | |||||
| } | |||||
| [HttpPost("authenticate")] | |||||
| public async Task<IActionResult> Authenticate([FromBody] AuthenticateRequestDto model) | |||||
| { | |||||
| var response = await _service.Authenticate(model); | |||||
| if (response.IsError is true) | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| return Ok(response.Data); | |||||
| } | |||||
| [HttpPost("refresh")] | |||||
| public async Task<IActionResult> RefreshToken([FromBody] RefreshTokenRequestDto model) | |||||
| { | |||||
| var response = await _service.RefreshTokenAsync(model); | |||||
| if (response.Error != null) | |||||
| { | |||||
| return BadRequest(new AuthFailedResponse { Error = response.Error }); | |||||
| } | |||||
| return Ok(response); | |||||
| } | |||||
| [HttpPost("logout")] | |||||
| public async Task<IActionResult> Logout(int userId) | |||||
| { | |||||
| var response = await _service.DeleteRefreshToken(userId); | |||||
| if (response.IsError) | |||||
| { | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| } | |||||
| return Ok(); | |||||
| } | |||||
| [HttpPost("authenticateGoogle")] | |||||
| public async Task<IActionResult> GoogleLogin(GoogleApiModel model) | |||||
| { | |||||
| var response = await _service.Authenticate(model); | |||||
| if (response.IsError is true) | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| return Ok(response.Data); | |||||
| } | |||||
| } | |||||
| } |
| { | { | ||||
| private readonly IUserService _userService; | private readonly IUserService _userService; | ||||
| private readonly IMapper _mapper; | private readonly IMapper _mapper; | ||||
| private readonly IEmailer _emailer; | |||||
| public UsersController(IUserService userService, IEmailer emailer, IMapper mapper) | |||||
| public UsersController(IUserService userService, IMapper mapper) | |||||
| { | { | ||||
| _userService = userService; | _userService = userService; | ||||
| _mapper = mapper; | _mapper = mapper; | ||||
| _emailer = emailer; | |||||
| } | } | ||||
| [Authorize] | [Authorize] | ||||
| return Ok(_mapper.Map<IEnumerable<User?>, IEnumerable<UserResponseDTO>>(await _userService.GetAll())); | return Ok(_mapper.Map<IEnumerable<User?>, IEnumerable<UserResponseDTO>>(await _userService.GetAll())); | ||||
| } | } | ||||
| [HttpGet("ForgotPassword")] | |||||
| public async Task<IActionResult> ForgotPassword(string email) | |||||
| { | |||||
| var result = await _userService.GetEmailConfirmationUrlAsync(email); | |||||
| return Ok(result); | |||||
| } | |||||
| [HttpPost("RessetPassword")] | |||||
| public async Task<IActionResult> ResetPassword([FromBody]ResetPasswordModel model) | |||||
| { | |||||
| var result = await _userService.PasswordResetAsync(email:model.Email,code: model.Code,password: model.Password); | |||||
| return Ok(result); | |||||
| } | |||||
| [Authorize] | |||||
| [HttpPost] | [HttpPost] | ||||
| public async Task<IActionResult> CreateUser([FromBody] CreateUserRequestDto model) | public async Task<IActionResult> CreateUser([FromBody] CreateUserRequestDto model) | ||||
| { | { | ||||
| return Ok(); | return Ok(); | ||||
| } | } | ||||
| [HttpPost("authenticate")] | |||||
| public async Task<IActionResult> Authenticate([FromBody] AuthenticateRequestDto model) | |||||
| { | |||||
| var response = await _userService.Authenticate(model); | |||||
| if (response.IsError is true) | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| return Ok(response.Data); | |||||
| } | |||||
| [HttpPost("refresh")] | |||||
| public async Task<IActionResult> RefreshToken([FromBody] RefreshTokenRequestDto model) | |||||
| { | |||||
| var response = await _userService.RefreshTokenAsync(model); | |||||
| if (response.Error != null) | |||||
| { | |||||
| return BadRequest(new AuthFailedResponse { Error = response.Error }); | |||||
| } | |||||
| return Ok(response); | |||||
| } | |||||
| [HttpPost("logout")] | |||||
| public async Task<IActionResult> Logout(int userId) | |||||
| { | |||||
| var response = await _userService.DeleteRefreshToken(userId); | |||||
| if (response.IsError) | |||||
| { | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| } | |||||
| return Ok(); | |||||
| } | |||||
| [HttpPost("authenticateGoogle")] | |||||
| public async Task<IActionResult> GoogleLogin(GoogleApiModel model) | |||||
| { | |||||
| var response = await _userService.Authenticate(model); | |||||
| if (response.IsError is true) | |||||
| return BadRequest(new { message = response.ErrorMessage }); | |||||
| return Ok(response.Data); | |||||
| } | |||||
| } | } | ||||
| } | } |
| { | { | ||||
| return Ok("Hello from protected route"); | return Ok("Hello from protected route"); | ||||
| } | } | ||||
| [HttpPost("authenticate")] | |||||
| public IActionResult Authenticate([FromBody] AuthenticateRequestDto model) | |||||
| { | |||||
| var response = _userService.Authenticate(model); | |||||
| if (response == null) | |||||
| return BadRequest(new { message = "Username or password is incorrect" }); | |||||
| return Ok(response); | |||||
| } | |||||
| } | } | ||||
| } | } |
| services.AddScoped<IInsurersService, InsurersService>(); | services.AddScoped<IInsurersService, InsurersService>(); | ||||
| services.AddScoped<IEmailer, Emailer>(); | services.AddScoped<IEmailer, Emailer>(); | ||||
| services.AddScoped<IHttpClientService, HttpClientService>(); | |||||
| services.AddScoped<IInsuranceCompaniesService, InsuranceCompaniesService>(); | services.AddScoped<IInsuranceCompaniesService, InsuranceCompaniesService>(); | ||||
| services.AddScoped<IInsurancePoliciesService, InsurancePoliciesService>(); | services.AddScoped<IInsurancePoliciesService, InsurancePoliciesService>(); | ||||
| services.AddScoped<IWebhookSubscriptionService, WebhookSubscriptionService>(); | services.AddScoped<IWebhookSubscriptionService, WebhookSubscriptionService>(); | ||||
| services.AddScoped<IWebhookPublisherService, WebhookPublisherService>(); | services.AddScoped<IWebhookPublisherService, WebhookPublisherService>(); | ||||
| services.AddScoped<IWebhookPublisherService, WebhookPublisherService>(); | services.AddScoped<IWebhookPublisherService, WebhookPublisherService>(); | ||||
| services.AddScoped<IApplicantService, ApplicantService>(); | services.AddScoped<IApplicantService, ApplicantService>(); | ||||
| services.AddScoped<IAuthenticationService, AuthenticationService>(); | |||||
| services.AddScoped<IAdService, AdService>(); | services.AddScoped<IAdService, AdService>(); | ||||
| services.AddScoped<ITechnologyService, TechnologyService>(); | services.AddScoped<ITechnologyService, TechnologyService>(); | ||||
| } | } |
| _authSettings = authSettings.Value; | _authSettings = authSettings.Value; | ||||
| } | } | ||||
| public async Task Invoke(HttpContext context, IUserService userService) | |||||
| public async Task Invoke(HttpContext context, IAuthenticationService authService, IUserService userService) | |||||
| { | { | ||||
| var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); | var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); | ||||
| if (token != null) | if (token != null) | ||||
| await AttachUserToContext(context, userService, token); | |||||
| await AttachUserToContext(context, authService, userService, token); | |||||
| await _next(context); | await _next(context); | ||||
| } | } | ||||
| private async Task AttachUserToContext(HttpContext context, IUserService userService, string token) | |||||
| private async Task AttachUserToContext(HttpContext context, IAuthenticationService authService,IUserService userService, string token) | |||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| // attach user to context on successful jwt validation | // attach user to context on successful jwt validation | ||||
| context.Items["User"] = await userService.GetById(userId); | context.Items["User"] = await userService.GetById(userId); | ||||
| await UpdateRefreshToken(context, userService, userId); | |||||
| await UpdateRefreshToken(context, authService, userId); | |||||
| } | } | ||||
| catch | catch | ||||
| { | { | ||||
| } | } | ||||
| } | } | ||||
| private async Task UpdateRefreshToken(HttpContext context, IUserService userService, int userId) | |||||
| private async Task UpdateRefreshToken(HttpContext context, IAuthenticationService service, int userId) | |||||
| { | { | ||||
| var refreshToken = await userService.GetRefreshTokenByUserId(userId); | |||||
| var refreshToken = await service.GetRefreshTokenByUserId(userId); | |||||
| if (refreshToken == null) | if (refreshToken == null) | ||||
| return; | return; | ||||
| refreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(30); | refreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(30); | ||||
| await userService.UpdateRefreshToken(refreshToken); | |||||
| await service.UpdateRefreshToken(refreshToken); | |||||
| } | } | ||||
| } | } | ||||
| } | } |