339 lines
15 KiB
C#
339 lines
15 KiB
C#
using CPRNIMS.Domain.Contracts.Account;
|
|
using CPRNIMS.Domain.Services.Account;
|
|
using CPRNIMS.Domain.Services;
|
|
using CPRNIMS.Infrastructure.Entities.Account;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using CPRNIMS.Infrastructure.Models.Common;
|
|
using CPRNIMS.Infrastructure.Models.Account;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using CPRNIMS.Infrastructure.Helper;
|
|
using CPRNIMS.Infrastructure.Entities.Common;
|
|
using CPRNIMS.Infrastructure.ViewModel.Common;
|
|
|
|
namespace CPRNIMS.WebApi.Controllers.Account
|
|
{
|
|
public class AnonController : Base.BaseController
|
|
{
|
|
private readonly SMTPHelper _smtpHelper;
|
|
public readonly IForgotPassword _forgotPassword;
|
|
public readonly UserManager<ApplicationUser> _userManager;
|
|
public readonly SignInManager<ApplicationUser> _signInManager;
|
|
public readonly UserClaimsManager _userClaimsManager;
|
|
public readonly RoleManager<IdentityRole> _roleManager;
|
|
public readonly IControllerAccess _controllerAccess;
|
|
public readonly IDepartment _department;
|
|
public readonly IConfiguration _config;
|
|
public readonly IAccount _account;
|
|
public AnonController(ErrorMessageService errorMessageService,
|
|
IWebHostEnvironment webHostEnvironment
|
|
, SMTPHelper sMTPHelper, IForgotPassword forgotPassword
|
|
, UserManager<ApplicationUser> userManager
|
|
, SignInManager<ApplicationUser> signInManager
|
|
, IConfiguration configuration
|
|
, UserClaimsManager userClaimsManager, RoleManager<IdentityRole> roleManager
|
|
, IControllerAccess controllerAccess, IDepartment department
|
|
, IAccount account) :
|
|
base(errorMessageService, webHostEnvironment, configuration)
|
|
{
|
|
_smtpHelper = sMTPHelper;
|
|
_forgotPassword = forgotPassword;
|
|
_userManager = userManager;
|
|
_signInManager = signInManager;
|
|
_userClaimsManager = userClaimsManager;
|
|
_roleManager = roleManager;
|
|
_controllerAccess = controllerAccess;
|
|
_department = department;
|
|
_config = configuration;
|
|
_account = account;
|
|
}
|
|
[AllowAnonymous]
|
|
[HttpPost("GetToken")]
|
|
public async Task<IActionResult> GetToken([FromBody] User model)
|
|
{
|
|
try
|
|
{
|
|
var user = await _userManager.FindByNameAsync(model.UserName.ToLower());
|
|
var userRoles = await _userManager.GetRolesAsync(user);
|
|
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, lockoutOnFailure: false);
|
|
|
|
if (signInResult.Succeeded)
|
|
{
|
|
var authClaims = new List<Claim>
|
|
{ new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
|
};
|
|
|
|
foreach (var userRole in userRoles)
|
|
{
|
|
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
|
|
}
|
|
|
|
var token = GetToken(authClaims);
|
|
|
|
return Ok(new
|
|
{
|
|
token = new JwtSecurityTokenHandler().WriteToken(token),
|
|
expiration = token.ValidTo
|
|
});
|
|
}
|
|
return BadRequest();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
|
await PostErrorMessage(message, " WebApi");
|
|
throw;
|
|
}
|
|
}
|
|
[AllowAnonymous]
|
|
[HttpPost("login")]
|
|
public async Task<IActionResult> Login([FromBody] User model)
|
|
{
|
|
try
|
|
{
|
|
var user = await _userManager.FindByNameAsync(model.UserName.ToLower());
|
|
|
|
if (user != null)
|
|
{
|
|
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, lockoutOnFailure: false);
|
|
|
|
if (signInResult.Succeeded)
|
|
{
|
|
if (user.LockoutEnabled == true || user.LockoutEnd != null)
|
|
{
|
|
await _userManager.SetLockoutEnabledAsync(user, false);
|
|
user.LockoutEnd = null;
|
|
await _userManager.UpdateAsync(user);
|
|
}
|
|
|
|
// Reset access failed count upon successful login
|
|
await _userManager.ResetAccessFailedCountAsync(user);
|
|
|
|
var userRoles = await _userManager.GetRolesAsync(user);
|
|
|
|
try
|
|
{
|
|
var authClaims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), };
|
|
|
|
foreach (var userRole in userRoles)
|
|
{
|
|
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
|
|
}
|
|
|
|
var token = GetToken(authClaims);
|
|
|
|
return Ok(new
|
|
{
|
|
token = new JwtSecurityTokenHandler().WriteToken(token),
|
|
expiration = token.ValidTo
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
|
await PostErrorMessage(message, " WebApi");
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Increment access failed count
|
|
await _userManager.AccessFailedAsync(user);
|
|
|
|
// Check if the access failed count reaches a threshold
|
|
if (user.AccessFailedCount > 3)
|
|
{
|
|
await _userManager.SetLockoutEnabledAsync(user, true);
|
|
await _userManager.SetLockoutEndDateAsync(user, DateTime.Now.AddMinutes(30)); // Lock the account for 30 minutes (you can adjust as needed)
|
|
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = "Account is locked. Please try again after 30 minutes or contact support." });
|
|
}
|
|
else if (signInResult.IsLockedOut)
|
|
{
|
|
// Increment access failed count
|
|
await _userManager.AccessFailedAsync(user);
|
|
return BadRequest(new ResponseObject { success = false,statusResponse = "Failed", message = "Account is locked. Please try again after 30 minutes or contact support." });
|
|
}
|
|
//If the
|
|
else
|
|
{
|
|
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = "Invalid UserName or Password, please double check!" });
|
|
}
|
|
}
|
|
}
|
|
|
|
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = "Invalid UserName or Password, please double check!" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
|
await PostErrorMessage(message, " WebApi");
|
|
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = message });
|
|
}
|
|
}
|
|
[AllowAnonymous]
|
|
[HttpPost("ValidateOTP")]
|
|
public async Task<IActionResult> ValidateOTP([FromBody] EmailMessageDetailsVM viewModel)
|
|
{
|
|
try
|
|
{
|
|
var otpModel = new Otps
|
|
{
|
|
OTP = viewModel.OTP,
|
|
Email = viewModel.Email,
|
|
|
|
};
|
|
if (String.IsNullOrEmpty(otpModel.Email) || String.IsNullOrEmpty(otpModel.OTP))
|
|
{
|
|
return NotFound();
|
|
}
|
|
var isEmailExist = await _userManager.FindByEmailAsync(otpModel.Email.ToLower());
|
|
if (isEmailExist != null)
|
|
{
|
|
bool isOTPValid = await _forgotPassword.ValidateOTP(otpModel);
|
|
if (isOTPValid)
|
|
{
|
|
return Ok(new ResponseObject { messCode = 1, message = "You may proceed now." });
|
|
}
|
|
return Ok(new ResponseObject { messCode = 0, message = "Your OTP is invalid!." });
|
|
}
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
|
await PostErrorMessage(message, "ForgotPassWebApi");
|
|
throw;
|
|
}
|
|
}
|
|
[AllowAnonymous]
|
|
[HttpPost("GetUserByEmail")]
|
|
public async Task<IActionResult> GetUserByEmail([FromBody] EmailMessageDetailsVM model)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(model.Email))
|
|
{
|
|
return NotFound();
|
|
}
|
|
var isEmailExist = await _userManager.FindByEmailAsync(model.Email.ToLower());
|
|
if (isEmailExist != null)
|
|
{
|
|
var otpGenerated = _smtpHelper.GenerateOTP();
|
|
var otpDetails = new Otps
|
|
{
|
|
OTP = otpGenerated,
|
|
Email = model.Email,
|
|
CreatedBy = model.Email,
|
|
CreatedDate = DateTime.Now,
|
|
UpdatedBy = model.Email,
|
|
UpdatedDate = DateTime.Now,
|
|
};
|
|
bool isOTPExpired = await _forgotPassword.ValidateOTP(otpDetails);
|
|
if (isOTPExpired)
|
|
{
|
|
otpGenerated = _smtpHelper.GenerateOTP();
|
|
}
|
|
otpDetails.OTP = otpGenerated;
|
|
var message = EMailTemplate("Content/SMTPEmailContent", "ForgotPassword.cshtml");
|
|
message = message.Replace("@ViewBag.FullName", isEmailExist.FullName);
|
|
message = message.Replace("@ViewBag.OTPCode", otpGenerated);
|
|
var messageDetails = new EmailMessageDetailsVM
|
|
{
|
|
Message = message,
|
|
Subject = "CLMS - OTP code for password reset",
|
|
SenderEmail = _config["SMTP:SenderEmail"],
|
|
DisplayName = _config["SMTP:DisplayName"],
|
|
Recipient = model.Email,
|
|
Bcc = _config["SMTP:CC"],
|
|
CC = _config["SMTP:CC"],
|
|
NewPassword = _config["SMTP:Password"],
|
|
OutGoingPort = 587,
|
|
Server = _config["SMTP:Server"],
|
|
UserName = _config["SMTP:UserName"]
|
|
};
|
|
await _forgotPassword.SaveUpdateOTPAsync(otpDetails, true);
|
|
await _forgotPassword.SaveUpdateOTPAsync(otpDetails, false);
|
|
await _smtpHelper.SendEmailAsync(messageDetails);
|
|
|
|
return Ok(new ResponseObject { messCode = 1, message = "You may proceed now." });
|
|
}
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
|
await PostErrorMessage(message, "ForgotPassWebApi");
|
|
throw;
|
|
}
|
|
}
|
|
[AllowAnonymous]
|
|
[HttpPut("ChangePassword")]
|
|
public async Task<IActionResult> ChangePassword([FromBody] EmailMessageDetailsVM model)
|
|
{
|
|
try
|
|
{
|
|
var isEmailExist = await _userManager.FindByEmailAsync(model?.Email);
|
|
//If this email is exist then go to 2nd validation
|
|
if (isEmailExist != null)
|
|
{
|
|
var passwordToken = "";
|
|
|
|
// Check if the Password field is not empty
|
|
if (!string.IsNullOrEmpty(model.PasswordHash))
|
|
{
|
|
// Change the user's password
|
|
passwordToken = await _userManager.GeneratePasswordResetTokenAsync(isEmailExist);
|
|
var passwordChangeResult = await _userManager.ResetPasswordAsync(isEmailExist, passwordToken, model.PasswordHash);
|
|
|
|
if (!passwordChangeResult.Succeeded)
|
|
{
|
|
string passwordErrorMessage = passwordChangeResult.Errors?.FirstOrDefault().Description;
|
|
return StatusCode(StatusCodes.Status500InternalServerError, new ResponseObject { messCode = 0, message = passwordErrorMessage });
|
|
}
|
|
}
|
|
|
|
var otps = new Otps
|
|
{
|
|
Email = model.Email,
|
|
OTP = model.OTP
|
|
};
|
|
bool isOTPValid = await _forgotPassword.ValidateOTP(otps);
|
|
if (isOTPValid != true)
|
|
{
|
|
return NotFound(new ResponseObject { IsValid = false, message = "Your OTP is invalid or expired!." });
|
|
}
|
|
else
|
|
{
|
|
isEmailExist.UpdatedDate = DateTime.Now;
|
|
isEmailExist.UpdatedBy = model.Email;
|
|
isEmailExist.LockoutEnabled = false;
|
|
isEmailExist.LockoutEnd = null;
|
|
isEmailExist.AccessFailedCount = 0;
|
|
var result = await _userManager.UpdateAsync(isEmailExist);
|
|
if (!result.Succeeded)
|
|
{
|
|
string errorMessage = result.Errors.FirstOrDefault()?.Description;
|
|
return StatusCode(StatusCodes.Status500InternalServerError, new ResponseObject { messCode = 0, message = errorMessage });
|
|
}
|
|
|
|
await _forgotPassword.SaveUpdateOTPAsync(otps, true);
|
|
return Ok(new ResponseObject { messCode = 1, message = "Your password has been reset successfully!, please check your email." });
|
|
}
|
|
}
|
|
|
|
return NotFound(new ResponseObject { messCode = 0, message = "Email not exist!" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
|
|
await PostErrorMessage(message, "ForgotPassWebApi");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|