TourIAm/TIAMWebApp/Server/Controllers/UserAPIController.cs

376 lines
14 KiB
C#

using DevExpress.Office.Crypto;
using DevExpress.Xpo.DB;
using DevExpress.XtraPrinting;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text.Json;
using TIAMWebApp.Shared.Application.Models;
using TIAMWebApp.Shared.Application.Models.PageModels;
using TIAMWebApp.Server.Models;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using TIAM.Database.DataLayers.Users;
using AyCode.Utils.Helpers;
using TIAM.Entities.Users;
using TIAMWebApp.Server.ModelsTIAMWebApp.Shared.Application.Models;
using TIAMWebApp.Shared.Application.Utility;
namespace TIAMWebApp.Server.Controllers
{
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class UserAPIController : ControllerBase
{
private UserDal _userDal;
private readonly IConfiguration _configuration;
private readonly IWebHostEnvironment _webHostEnvironment;
PasswordHasher hasher = new PasswordHasher();
/*private UserModel[] users = new UserModel[]
{
new UserModel(new Guid("540271f6-c604-4c16-8160-d5a7cafedf00"), "test@tiam.hu", "+36701234567", "Asdasd123456"),
new UserModel(new Guid("4cbaed43-2465-4d99-84f1-c8bc6b7025f7"), "adam@tiam.hu", "+36701234567", "Asdasd987654")
};*/
private readonly ILogger<UserAPIController> _logger;
public UserAPIController(ILogger<UserAPIController> logger, IConfiguration configuration, IWebHostEnvironment webHostEnvironment, UserDal userDal)
{
_logger = logger;
_configuration = configuration;
_webHostEnvironment = webHostEnvironment;
_userDal = userDal;
}
/*[HttpPost]
[Route("Auth")]
public async Task<IActionResult> AuthenticateUser([FromBody] JsonElement SerializedLoginModel)
{
Console.WriteLine("Auth called");
Console.WriteLine(SerializedLoginModel.GetRawText());
if (string.IsNullOrEmpty(SerializedLoginModel.GetRawText()))
{
return BadRequest("SerializedLoginModel is required");
}
else
{
var userModel = JObject.Parse(SerializedLoginModel.GetRawText()).ToObject<LoginModel>();
Console.WriteLine(userModel.Email);
Console.WriteLine(userModel.Password);
if (userModel.Email == "test@tiam.hu" && userModel.Password == "Asdasd123456")
{
Console.WriteLine("UserModel authenticated");
return Ok("yes");
}
else
{
Console.WriteLine("UserModel NOT authenticated");
return Ok("no");
}
}
}*/
[AllowAnonymous]
[HttpPost]
[Route("AuthenticateUser")]
public async Task<IActionResult> AuthenticateUser([FromBody] JsonElement SerializedLoginModel)
{
Console.WriteLine("AuthenticateUser called");
var authenticateUser = JObject.Parse(SerializedLoginModel.GetRawText()).ToObject<LoginModel>();
//check if userModel exists
//var userModel = await _userManager.FindByNameAsync(authenticateUser.UserName);
//if (userModel == null) return Unauthorized();
Console.WriteLine(authenticateUser.Email);
//var dbUser = await GetUserByEmail(authenticateUser.Email);
var dbUser = await _userDal.GetUserByEmailAsync(authenticateUser.Email);
//check if password is valid
//bool isValidUser = await _userManager.CheckPasswordAsync(userModel, authenticateUser.Password);
//mocking
if (dbUser is null)
{
return Unauthorized();
}
else
{
bool isValidUser = false;
if (dbUser.Password == authenticateUser.Password)
{
Console.WriteLine("Password is valid");
isValidUser = true;
}
if (isValidUser)
{
Console.WriteLine("UserModel authenticated, let's start JWT");
string accessToken = GenerateAccessToken(dbUser);
Console.WriteLine("Generate refresh token");
var refreshToken = GenerateRefreshToken();
dbUser.RefreshToken = refreshToken;
//Update userModel with refreshToken!!
await _userDal.UpdateUserAsync(dbUser);
var response = new MainResponse
{
Content = new AuthenticationResponse
{
RefreshToken = refreshToken,
AccessToken = accessToken
},
IsSuccess = true,
ErrorMessage = ""
};
return Ok(response);
}
else
{
return Unauthorized();
}
}
}
private string GenerateAccessToken(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var token = new JwtSecurityToken();
Console.WriteLine("----------------------------------------------------------");
var keyDetail = Encoding.UTF8.GetBytes(_configuration["JWT:Key"]);
Console.WriteLine(_configuration["JWT:Key"]);
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Email, user.Email)
};
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)
};
token = tokenHandler.CreateToken(tokenDescriptor) as JwtSecurityToken;
string writtenToken = tokenHandler.WriteToken(token);
Console.WriteLine(writtenToken);
return writtenToken;
}
[AllowAnonymous]
[HttpPost]
[Route("RefreshToken")]
public async Task<IActionResult> RefreshToken(RefreshTokenRequest refreshTokenRequest)
{
Console.WriteLine("RefreshToken called");
var response = new MainResponse();
if (refreshTokenRequest is null)
{
Console.WriteLine("RefreshTokenRequest is null");
response.ErrorMessage = "Invalid request";
return BadRequest(response);
}
var principal = GetPrincipalFromExpiredToken(refreshTokenRequest.AccessToken);
if (principal != null)
{
Console.WriteLine("Principal is not null");
var email = principal.Claims.FirstOrDefault(f => f.Type == ClaimTypes.Email);
//var userModel = await _userManager.FindByEmailAsync(email?.Value);
//UserModel? user = users.FirstOrDefault(x => x.Email == email?.Value);
User? dbUser = null;
if (email != null)
{
//get user from db
dbUser = await _userDal.GetUserByEmailAsync(email.Value);
}
//mocking - update userModel with new refreshToken so it returns true after the check below
//dbUser.RefreshToken = refreshTokenRequest.RefreshToken;
if (dbUser is null || dbUser.RefreshToken != refreshTokenRequest.RefreshToken)
{
response.ErrorMessage = "Invalid Request";
return BadRequest(response);
}
string newAccessToken = GenerateAccessToken(dbUser);
string refreshToken = GenerateRefreshToken();
//mocking - update userModel with new refreshToken
dbUser.RefreshToken = refreshToken;
//await _userManager.UpdateAsync(userModel);
response.IsSuccess = true;
response.Content = new AuthenticationResponse
{
RefreshToken = refreshToken,
AccessToken = newAccessToken
};
return Ok(response);
}
else
{
Console.WriteLine("Principal is null");
return NotFound("Invalid Token Found");
}
}
private ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var keyDetail = Encoding.UTF8.GetBytes(_configuration["JWT:Key"]);
var tokenValidationParameter = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
ValidIssuer = _configuration["JWT:Issuer"],
ValidAudience = _configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(keyDetail),
};
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, tokenValidationParameter, out securityToken);
var jwtSecurityToken = securityToken as JwtSecurityToken;
if (jwtSecurityToken == null || !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);
}
}
[AllowAnonymous]
[HttpPost]
[Route("CreateUser")]
public async Task<IActionResult> CreateUser([FromBody] JsonElement SerializedRegistrationModel)
{
Console.WriteLine("CreateUser called");
if (string.IsNullOrEmpty(SerializedRegistrationModel.GetRawText()))
{
return BadRequest("SerializedLoginModel is required");
}
else
{
RegistrationModel? user = JObject.Parse(SerializedRegistrationModel.GetRawText()).ToObject<RegistrationModel>();
if(user != null)
{
//add userModel to users array
//Array.Resize(ref users, users.Length + 1);
//users[users.Length - 1] = new UserModel(user.Email, user.PhoneNumber, user.Password);
var userId = Guid.NewGuid();
string? email = user?.Email;
string? phoneNumber = user?.PhoneNumber;
string? password = user?.Password;
if(email is null || phoneNumber is null || password is null)
{
return BadRequest("Invalid request");
}
else
{
Console.WriteLine($"User to be created: {userId}");
Console.WriteLine($"User to be created: {email}");
Console.WriteLine($"User to be created: {phoneNumber}");
Console.WriteLine($"User to be created: {password}");
await _userDal.CreateUserAsync(new User(userId, email, phoneNumber, password));
}
}
return Ok("yes");
}
}
[HttpPost]
[Route("Test1")]
public async Task<IActionResult> TestEndpoint([FromBody] int testParam)
{
return Ok(testParam.ToString());
}
[HttpGet]
[Route("Test2")]
public string TestEndpoint2(int testParam)
{
return testParam.ToString();
}
[AllowAnonymous]
[HttpGet]
[Route("GetUsers")]
public Task<List<User>> GetUsers()
{
//var users = await _userDal.Ctx.Users.ToListAsync();//.GetUsersAsync();
//return users;
return _userDal.GetUsersAsync();
}
[AllowAnonymous]
[HttpGet]
[Route("GetUserByEmail")]
public async Task<User?> GetUserByEmail(string email)
{
return await _userDal.GetUserByEmailAsync(email);
}
private bool VerifyPassword(string password, string hashedPassword)
{
bool isPasswordValid = hasher.VerifyPassword(password, hashedPassword);
return isPasswordValid;
}
private string HashPassword(string password)
{
var hashedPassword = hasher.HashPassword(password);
return hashedPassword;
}
}
}