AdminDal (?), Registration and login almost finished (works from db already), login approvements, new api endpoints

This commit is contained in:
Adam 2023-11-25 03:17:41 +01:00
parent 4bed3bc4f4
commit 7096c90637
28 changed files with 438 additions and 176 deletions

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using TIAM.Database.DbContexts;
using TIAM.Entities.Users;
namespace TIAM.Database.DataLayers.Users
{
public class AdminDal : TiamDalBase<AdminDbContext>
{
public AdminDal() : base()
{
}
public Task<List<User>> GetUsersAsync()
{
return Ctx.Users.ToListAsync();
}
public Task<User?> GetUserByEmailAsync(string email)
{
Console.WriteLine($"Getting user from db {email}");
var emailLower = email.ToLower();
return Ctx.Users.SingleOrDefaultAsync(x=>x.Email.ToLower() == emailLower);
}
public Task<bool> CreateUserAsync(User user)
{
user.Created = DateTime.UtcNow;
user.Modified = DateTime.UtcNow;
Ctx.Users.Add(user);
Console.WriteLine($"Saving user to db {user.Id}, {user.Email}, {user.PhoneNumber}, {user.Password}");
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
public Task<bool> UpdateUserAsync(User user)
{
user.Modified = DateTime.UtcNow;
Ctx.Users.Update(user);
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
}
}

View File

@ -7,6 +7,7 @@ using AyCode.Database;
using Microsoft.Identity.Client;
using TIAM.Database.DbContexts;
using TIAM.Entities.TransferDestinations;
using TIAM.Entities.Users;
namespace TIAM.Database.DataLayers.TransferDestinations;
@ -15,4 +16,12 @@ public class TransferDestinationDal : TiamDalBase<TransferDestinationDbContext>
public TransferDestinationDal() : base()
{
}
public Task<bool> CreateTransferDestinationAsync(TransferDestination transferDestination)
{
transferDestination.Created = DateTime.UtcNow;
transferDestination.Modified = DateTime.UtcNow;
Ctx.TransferDestinations.Add(transferDestination);
return Ctx.SaveChangesAsync().ContinueWith(x => x.Result > 0);
}
}

View File

@ -23,8 +23,25 @@ namespace TIAM.Database.DataLayers.Users
public Task<User?> GetUserByEmailAsync(string email)
{
Console.WriteLine($"Getting user from db {email}");
var emailLower = email.ToLower();
return Ctx.Users.SingleOrDefaultAsync(x=>x.Email.ToLower() == emailLower);
}
public Task<bool> CreateUserAsync(User user)
{
user.Created = DateTime.UtcNow;
user.Modified = DateTime.UtcNow;
Ctx.Users.Add(user);
Console.WriteLine($"Saving user to db {user.Id}, {user.Email}, {user.PhoneNumber}, {user.Password}");
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
public Task<bool> UpdateUserAsync(User user)
{
user.Modified = DateTime.UtcNow;
Ctx.Users.Update(user);
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AyCode.Database.DbContexts;
using Microsoft.EntityFrameworkCore;
using TIAM.Entities.TransferDestinations;
using TIAM.Entities.Users;
namespace TIAM.Database.DbContexts
{
public class AdminDbContext : TiamDbContextBase
{
public DbSet<User> Users { get; set; }
public DbSet<TransferDestination> TransferDestinations { get; set; }
public AdminDbContext() //: this(string.Empty)
{
}
public AdminDbContext(string name) : base(name)
{
}
public AdminDbContext(DbContextOptions<DbContext> options, string name) : base(options, name)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableDetailedErrors(true);
base.OnConfiguring(optionsBuilder);
}
}
}

View File

@ -29,7 +29,10 @@ namespace TIAM.Database.DbContexts
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableDetailedErrors(true);
base.OnConfiguring(optionsBuilder);
}
}
}

View File

@ -1,44 +1,30 @@
using System.ComponentModel.DataAnnotations.Schema;
using AyCode.Entities.Interfaces;
using AyCode.Entities.Locations;
using AyCode.Interfaces.TimeStampInfo;
namespace TIAM.Entities.TransferDestinations
{
[Table("TransferDestination")]
public class TransferDestination : IEntityGuid, ITimeStampInfo
public class TransferDestination : LocationBase, ITimeStampInfo
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id
{
get;
set;
}
public string Name
{
get;
set;
}
public string Description
{
get;
set;
}
public decimal Longitude
{
get;
set;
}
public decimal Latitude
{
get;
set;
}
public Guid Id { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public string? Address { get; set; }
public string? Name { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public TransferDestination() { }
public TransferDestination(double longitude, double latitude, string address) : this(Guid.NewGuid(), longitude, latitude, address) { }
public TransferDestination(Guid id, double longitude, double latitude, string address) : base(Guid.NewGuid(), longitude, latitude, address) { }
public TransferDestination(Guid id, string name, double longitude, double latitude, string address) : base(id, longitude, latitude, address) { }
}
}

View File

@ -13,5 +13,10 @@ namespace TIAM.Entities.Users
public User(string email, string password) : this(Guid.NewGuid(), email, password) { }
public User(Guid id, string email, string password) : base(id, email, password)
{ }
public User(Guid id, string email, string phoneNumber, string password) : base(id, email, phoneNumber, password)
{ }
public User(Guid id, string email, string phoneNumber, string password, string refreshToken) : base(id, email, phoneNumber, password, refreshToken)
{ }
}
}

View File

@ -21,5 +21,16 @@ namespace TIAMMobileApp.Services
{
return await SecureStorage.GetAsync(key);
}
public async Task DeleteFromSecureStorageAsync(string key)
{
SecureStorage.Remove(key);
}
public async Task ClearAllSecureStorageAsync()
{
SecureStorage.RemoveAll();
}
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.JSInterop;
using Newtonsoft.Json;
using System.Net.Http.Json;
using System.Text;
@ -7,21 +8,23 @@ using TIAMWebApp.Shared.Application.Interfaces;
using TIAMWebApp.Shared.Application.Models;
using TIAMWebApp.Shared.Application.Models.ClientSide;
using TIAMWebApp.Shared.Application.Models.PageModels;
using TIAMWebApp.Shared.Application.Utility;
namespace TIAMMobilApp.Services
{
public class UserDataService : IUserDataService
{
private readonly HttpClient http;
private readonly ISecureStorageHandler secureStorageHandler;
private readonly ISecureStorageHandler secureStorageHandler;
public UserModel? User { get; set; } = new UserModel("", "", "");
public Dictionary<int, string> userRoleTypes { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public UserDataService(HttpClient http, ISecureStorageHandler secureStorageHandler)
{
this.http = http;
this.secureStorageHandler = secureStorageHandler;
this.secureStorageHandler = secureStorageHandler;
}
@ -127,18 +130,18 @@ namespace TIAMMobilApp.Services
return (isSuccess, result);
}
public Task<IEnumerable<User>> GetUsersAsync()
public async Task<IEnumerable<User>?> GetUsersAsync()
{
throw new NotImplementedException();
return await http.GetFromJsonAsync<IEnumerable<User>>(APIUrls.GetUsers);
}
public Task<User> GetUserByEmailAsync(string email)
public async Task<User?> GetUserByEmailAsync(string email)
{
throw new NotImplementedException();
return await http.GetFromJsonAsync<User?>(APIUrls.GetUserByEmail);
}
public async Task<bool> RefreshToken()
{
{
bool isTokenRefreshed = false;
using (var client = new HttpClient())
{

View File

@ -1,4 +1,4 @@
@page "/";
@page "/admin";
@using TIAMWebApp.Shared.Application.Interfaces
@using TIAMWebApp.Shared.Application.Models
@using TIAMWebApp.Shared.Application.Utility
@ -6,18 +6,25 @@
@using System.IdentityModel.Tokens.Jwt
@using TIAMWebApp.Shared.Application.Models.ClientSide
@inject NavigationManager NavManager
@inject IJSRuntime JSRuntime
@inject LogToBrowserConsole logToBrowserConsole
@inject IUserDataService UserDataService
@inject ISecureStorageHandler SecureStorageHandler
@inject HttpClient http;
<h3>AppLaunch</h3>
Loading....
@code {
protected async override Task OnInitializedAsync()
{
logToBrowserConsole = new LogToBrowserConsole(JSRuntime);
//wait for 5 seconds
await Task.Delay(5000);
string userDetailsStr = await SecureStorageHandler.GetFromSecureStorageAsync(nameof(Setting.UserBasicDetails));
logToBrowserConsole.LogToBC(userDetailsStr);
if (!string.IsNullOrWhiteSpace(userDetailsStr))
@ -25,30 +32,37 @@ Loading....
var userBasicDetail = JsonConvert.DeserializeObject<UserBasicDetails>(userDetailsStr);
var handler = new JwtSecurityTokenHandler();
var jsontoken = handler.ReadToken(userBasicDetail.AccessToken) as JwtSecurityToken;
Setting.UserBasicDetails = userBasicDetail;
var jsontoken = handler.ReadToken(userBasicDetail?.AccessToken) as JwtSecurityToken;
if(userBasicDetail!= null)
Setting.UserBasicDetails = userBasicDetail;
if (jsontoken.ValidTo < DateTime.UtcNow)
if (jsontoken?.ValidTo < DateTime.UtcNow)
{
logToBrowserConsole.LogToBC("Token needs to be refreshed");
bool isTokenRefreshed = await UserDataService.RefreshToken();
if (isTokenRefreshed)
{
logToBrowserConsole.LogToBC("Token refreshed");
NavManager.NavigateTo("/home");
}
else
{
logToBrowserConsole.LogToBC("Couldn't refresh token");
NavManager.NavigateTo("/login");
}
}
else
{
logToBrowserConsole.LogToBC("Valid token found");
NavManager.NavigateTo("/home");
}
}
else
{
logToBrowserConsole.LogToBC("No token stored yet");
NavManager.NavigateTo("/login");
}

View File

@ -1,4 +1,4 @@
@page "/index"
@page "/"
@using TIAMSharedUI.Shared
<PageTitle>Index</PageTitle>

View File

@ -57,7 +57,7 @@
}
}
<div class="text-center fs-6">
Already have an account? <a href="login">Sign in here!</a>
No account yet? <a href="register">Sign up here!</a>
</div>
</div>
@ -130,7 +130,7 @@
//await App.Current.MainPage.DisplayAlert("Error", "Invalid credentials", "Ok");
//display error message via jsinterop
logToBrowserConsole.LogToBC("Invalid credentials");
navManager.NavigateTo("login2");
navManager.NavigateTo("login");
}
else
{
@ -153,7 +153,7 @@
//await App.Current.MainPage.DisplayAlert("Error", "An error occured while trying to login", "Ok");
//display error message via jsinterop
logToBrowserConsole.LogToBC("An error occured while trying to login");
navManager.NavigateTo("login2");
navManager.NavigateTo("login");
}
}

View File

@ -5,14 +5,11 @@
@inject IJSRuntime jsRuntime
<div class="page">
@if (Setting.UserBasicDetails != null)
{
<div class="my-sidebar">
<NavMenu />
</div>
}
<main>
<article class="content">
@{
@ -20,8 +17,7 @@
{
<TopRow></TopRow>
}
}
}
@Body
</article>
</main>

View File

@ -1,4 +1,7 @@
<div class="top-row ps-3 navbar navbar-light">
@using TIAMWebApp.Shared.Application.Interfaces
@inject ISecureStorageHandler SecureStorageHandler
<div class="top-row ps-3 navbar navbar-light">
<div class="container-fluid">
<button title="Back button" class="my-back-button" style="display:none" @onclick="NavigateBack">
<img src="_content/TIAMSharedUI/images/navbar-toggler.png" width="40" />
@ -44,8 +47,8 @@
</div>
<hr />
<div class="nav-item px-3">
<NavLink class="nav-link" href="swagger">
Api
<NavLink class="nav-link" href="#" @onclick="SignOut">
Signout
</NavLink>
</div>
</nav>
@ -63,6 +66,11 @@
private void NavigateBack()
{
}
private void SignOut()
{
SecureStorageHandler.ClearAllSecureStorageAsync();
}
}

View File

@ -1,4 +1,7 @@
<div class="top-row ps-3 navbar navbar-light">
@using TIAMWebApp.Shared.Application.Interfaces
@inject ISecureStorageHandler SecureStorageHandler
<div class="top-row ps-3 navbar navbar-light">
<div class="container-fluid">
<button title="Back button" class="my-back-button" style="display:none" @onclick="NavigateBack">
<img src="_content/TIAMSharedUI/images/navbar-toggler.png" width="40" />
@ -50,6 +53,11 @@
Settings
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="#" @onclick="SignOut">
Signout
</NavLink>
</div>
</nav>
</div>
@ -67,4 +75,10 @@
{
}
private void SignOut()
{
SecureStorageHandler.ClearAllSecureStorageAsync();
}
}

View File

@ -29,5 +29,17 @@ namespace TIAMWebApp.Client.Services
return await ssa.GetValueAsync<string>(key);
}
public async Task DeleteFromSecureStorageAsync(string key)
{
await localStoragService.RemoveItemAsync(key);
await ssa.RemoveAsync(key);
}
public async Task ClearAllSecureStorageAsync()
{
await localStoragService.ClearAsync();
await ssa.Clear();
}
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.JSInterop;
using Newtonsoft.Json;
using System.Net.Http.Json;
using System.Text;
@ -8,6 +9,7 @@ using TIAMWebApp.Shared.Application.Interfaces;
using TIAMWebApp.Shared.Application.Models;
using TIAMWebApp.Shared.Application.Models.ClientSide;
using TIAMWebApp.Shared.Application.Models.PageModels;
using TIAMWebApp.Shared.Application.Utility;
namespace TIAMWebApp.Client.Services
@ -16,13 +18,17 @@ namespace TIAMWebApp.Client.Services
{
private readonly HttpClient http;
private readonly ISecureStorageHandler secureStorageHandler;
private readonly IJSRuntime jsRuntime;
private readonly LogToBrowserConsole logToBrowserConsole;
public UserModel? User { get; set; } = new UserModel("", "", "");
public Dictionary<int, string> userRoleTypes { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public UserDataService(HttpClient http, ISecureStorageHandler secureStorageHandler)
public UserDataService(HttpClient http, ISecureStorageHandler secureStorageHandler, IJSRuntime jSRuntime)
{
this.http = http;
this.secureStorageHandler = secureStorageHandler;
this.jsRuntime = jSRuntime;
this.logToBrowserConsole = new LogToBrowserConsole(jsRuntime);
}
@ -108,9 +114,9 @@ namespace TIAMWebApp.Client.Services
{
bool isSuccess = true;
string result = string.Empty;
var url = APIUrls.CreateUser;
string result = string.Empty;
var url = $"{Setting.BaseUrl}/{APIUrls.CreateUser}";
logToBrowserConsole.LogToBC("CreateUser url: " + url);
var response = await http.PostAsJsonAsync(url, regModel);
result = await response.Content.ReadAsStringAsync();
/*if (response.IsSuccessStatusCode)
@ -140,10 +146,12 @@ namespace TIAMWebApp.Client.Services
public async Task<bool> RefreshToken()
{
logToBrowserConsole.LogToBC("RefreshToken() called");
bool isTokenRefreshed = false;
using (var client = new HttpClient())
{
var url = APIUrls.RefreshToken;
var url = $"{Setting.BaseUrl}{APIUrls.RefreshToken}";
//var url = APIUrls.RefreshToken;
var serializedStr = JsonConvert.SerializeObject(new AuthenticateRequestAndResponse
{
@ -153,6 +161,7 @@ namespace TIAMWebApp.Client.Services
try
{
logToBrowserConsole.LogToBC("Refreshtoken url: " + url);
var response = await client.PostAsync(url, new StringContent(serializedStr, Encoding.UTF8, "application/json"));
if (response.IsSuccessStatusCode)
{
@ -173,6 +182,7 @@ namespace TIAMWebApp.Client.Services
catch (Exception ex)
{
string msg = ex.Message;
logToBrowserConsole.LogToBC("Refreshtoken exception: " + ex.ToString());
}

View File

@ -16,7 +16,7 @@ using GoogleApi.Entities.Maps.DistanceMatrix.Response;
namespace TIAMWebApp.Server.Controllers
{
[ApiController]
[Route("[controller]")]
[Route("api/[controller]")]
public class GoogleAPIController : ControllerBase
{

View File

@ -1,17 +1,22 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using System.Reflection.Metadata;
using System.Text.Json;
using TIAM.Database.DataLayers;
using TIAM.Database.DataLayers.TransferDestinations;
using TIAM.Database.DataLayers.Users;
using TIAM.Database.DbContexts;
using TIAM.Entities.TransferDestinations;
using TIAM.Entities.Users;
using TIAMWebApp.Shared.Application.Models;
using TIAMWebApp.Shared.Application.Models.PageModels;
namespace TIAMWebApp.Server.Controllers
{
[ApiController]
[Route("[controller]")]
[Route("api/[controller]")]
public class TransferDataAPIController : ControllerBase
{
//private static readonly TransferDestination[] Names = new TransferDestination[]
@ -24,22 +29,87 @@ namespace TIAMWebApp.Server.Controllers
// new() { DestinationId = 5, DestinationName = "Heroes square", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
// new() { DestinationId = 6, DestinationName = "Gellert Hill", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f },
// new() { DestinationId = 6, DestinationName = "Margaret Island", DestinationDescription = "International airport of Budapest", DestinationLatitude = 42.234444f, DestinationLongitude = 39.100010f }
//};
private readonly TransferDestinationDal _transferDestinationDal;
private readonly AdminDal _adminDal;
private readonly ILogger<TransferDataAPIController> _logger;
public TransferDataAPIController(ILogger<TransferDataAPIController> logger, TransferDestinationDal transferDestinationDal)
public TransferDataAPIController(ILogger<TransferDataAPIController> logger, TransferDestinationDal transferDestinationDal, AdminDal adminDal)
{
_logger = logger;
_transferDestinationDal = transferDestinationDal;
_adminDal = adminDal;
}
[AllowAnonymous]
[HttpGet]
public async Task<IEnumerable<TransferDestination>> Get()
[Route("GetTransferDestinations")]
public async Task<IEnumerable<TransferDestination>> GetTransferDestinations()
{
return await _transferDestinationDal.Ctx.TransferDestinations.ToListAsync();
}
[AllowAnonymous]
[HttpGet]
[Route("GetTransferDestinationByCoordinates")]
public async Task<TransferDestination?> GetTransferDestinationByCoordinates(double latitude, double longitude)
{
return await _transferDestinationDal.Ctx.TransferDestinations.FirstOrDefaultAsync(x => x.Latitude == latitude && x.Longitude == longitude);
}
[AllowAnonymous]
[HttpGet]
[Route("GetTransferDestinationByAddress")]
public async Task<TransferDestination?> GetTransferDestinationByAddress(string address)
{
return await _transferDestinationDal.Ctx.TransferDestinations.FirstOrDefaultAsync(x => x.Address == address);
}
[AllowAnonymous]
[HttpPost]
[Route("CreateTransferDestination")]
public async Task<IActionResult> CreateTransferDestination([FromBody] JsonElement SerializedTransferDestinationModel)
{
Console.WriteLine("CreateTransferDestination called!");
if (string.IsNullOrEmpty(SerializedTransferDestinationModel.GetRawText()))
{
return BadRequest("SerializedLoginModel is required");
}
else
{
TransferDestination? transferDestination = JObject.Parse(SerializedTransferDestinationModel.GetRawText()).ToObject<TransferDestination>();
if (transferDestination != null)
{
var Id = Guid.NewGuid();
double Latitude = transferDestination.Latitude;
double Longitude = transferDestination.Longitude;
string Address = transferDestination.Address;
if (Id == null || Latitude == null || Longitude == null || Address == null)
{
return BadRequest("Invalid request");
}
else
{
Console.WriteLine($"TransferDestination to be created: {Id}");
Console.WriteLine($"TransferDestination to be created: {Latitude}");
Console.WriteLine($"TransferDestination to be created: {Longitude}");
Console.WriteLine($"TransferDestination to be created: {Address}");
await _transferDestinationDal.Ctx.TransferDestinations.AddRangeAsync(transferDestination);
}
}
return Ok("yes");
}
}
}
}

View File

@ -17,12 +17,14 @@ 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]
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class UserAPIController : ControllerBase
@ -83,61 +85,73 @@ namespace TIAMWebApp.Server.Controllers
}*/
[AllowAnonymous]
[HttpPost("AuthenticateUser")]
[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);
//mocking
var user = users.FirstOrDefault(x => x.Email == authenticateUser.Email);
//check if password is valid
//bool isValidUser = await _userManager.CheckPasswordAsync(userModel, authenticateUser.Password);
//mocking
bool isValidUser = false;
if (user.Password == authenticateUser.Password)
{
isValidUser = true;
}
if (isValidUser)
{
Console.WriteLine("UserModel authenticated, let's start JWT");
string accessToken = GenerateAccessToken(user);
Console.WriteLine("Generate refresh token");
var refreshToken = GenerateRefreshToken();
user.RefreshToken = refreshToken;
//Update userModel with refreshToken!!
//await _userManager.UpdateAsync(userModel);
var response = new MainResponse
{
Content = new AuthenticationResponse
{
RefreshToken = refreshToken,
AccessToken = accessToken
},
IsSuccess = true,
ErrorMessage = ""
};
return Ok(response);
}
else
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(UserModel userModel)
private string GenerateAccessToken(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var token = new JwtSecurityToken();
@ -147,8 +161,8 @@ namespace TIAMWebApp.Server.Controllers
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, userModel.Id.ToString()),
new Claim(ClaimTypes.Email, userModel.Email)
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Email, user.Email)
};
var tokenDescriptor = new SecurityTokenDescriptor
@ -166,12 +180,15 @@ namespace TIAMWebApp.Server.Controllers
}
[AllowAnonymous]
[HttpPost("RefreshToken")]
[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);
}
@ -180,23 +197,33 @@ namespace TIAMWebApp.Server.Controllers
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);
var user = users.FirstOrDefault(x => x.Email == 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);
}
if (user is null || user.RefreshToken != refreshTokenRequest.RefreshToken)
//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(user);
string newAccessToken = GenerateAccessToken(dbUser);
string refreshToken = GenerateRefreshToken();
//mocking - update userModel with new refreshToken
user.RefreshToken = refreshToken;
dbUser.RefreshToken = refreshToken;
//await _userManager.UpdateAsync(userModel);
response.IsSuccess = true;
@ -209,6 +236,7 @@ namespace TIAMWebApp.Server.Controllers
}
else
{
Console.WriteLine("Principal is null");
return NotFound("Invalid Token Found");
}
@ -251,29 +279,53 @@ namespace TIAMWebApp.Server.Controllers
}
[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
{
var user = JObject.Parse(SerializedRegistrationModel.GetRawText()).ToObject<RegistrationModel>();
RegistrationModel? user = JObject.Parse(SerializedRegistrationModel.GetRawText()).ToObject<RegistrationModel>();
if (users != 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);
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");
}
else
{
return Ok("no");
return NotFound("no");
}
}
@ -296,21 +348,22 @@ namespace TIAMWebApp.Server.Controllers
}
[AllowAnonymous]
[HttpGet]
[Route("GetUsers")]
public Task<List<User?>> GetUsers()
public Task<List<User>> GetUsers()
{
//var users = await _userDal.Ctx.Users.ToListAsync();//.GetUsersAsync();
//return users;
return _userDal.GetUsersAsync();
}
[AllowAnonymous]
[HttpGet]
[Route("GetUserByEmail")]
public Task<User?> GetUserByEmail(string email)
public async Task<User?> GetUserByEmail(string email)
{
return _userDal.GetUserByEmailAsync(email);
return await _userDal.GetUserByEmailAsync(email);
}
private bool VerifyPassword(string password, string hashedPassword)

View File

@ -4,7 +4,7 @@ using TIAMWebApp.Shared.Application.Models;
namespace TIAMWebApp.Server.Controllers
{
[ApiController]
[Route("[controller]")]
[Route("api/[controller]")]
public class WeatherForecastAPIController : ControllerBase
{
private static readonly string[] Summaries = new[]

View File

@ -21,7 +21,7 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
//builder.Services.AddDbContext<TransferDestinationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DeveloperDbConnection")));;
builder.Services.AddScoped<UserDal>();
builder.Services.AddScoped<AdminDal>();
builder.Services.AddScoped<TransferDestinationDal>();
builder.Services.AddSwaggerGen(swagger =>

View File

@ -47,6 +47,9 @@
<Reference Include="AyCode.Interfaces.Server">
<HintPath>..\..\..\AyCode.Core\AyCode.Database\bin\Debug\net7.0\AyCode.Interfaces.Server.dll</HintPath>
</Reference>
<Reference Include="AyCode.Utils">
<HintPath>..\..\..\AyCode.Core\AyCode.Utils\bin\Debug\net7.0\AyCode.Utils.dll</HintPath>
</Reference>
</ItemGroup>

View File

@ -10,5 +10,8 @@ namespace TIAMWebApp.Shared.Application.Interfaces
{
public Task SaveToSecureStorageAsync(string key, string value);
public Task<string> GetFromSecureStorageAsync(string key);
public Task DeleteFromSecureStorageAsync(string key);
public Task ClearAllSecureStorageAsync();
}
}

View File

@ -13,8 +13,9 @@ namespace TIAMWebApp.Shared.Application.Models
public const string GetUsers = "api/UserAPI/GetUsers";
public const string AuthenticateUser = "api/UserAPI/AuthenticateUser";
public const string CreateUser = "api/UserAPI/CreateUser";
public const string RefreshToken = "api/UserAPI/RefreshToken";
public const string WeatherForecast = "WeatherForecastAPI";
public const string RefreshToken = "/api/UserAPI/RefreshToken";
public const string WeatherForecast = "api/WeatherForecastAPI";
public const string PopulationStructure = "PopulationStructureAPI";
public const string GetTransferDestinations = "api/GetTransferDestinations";
}
}

View File

@ -9,5 +9,6 @@ namespace TIAMWebApp.Shared.Application.Models.ClientSide
public class Setting
{
public static UserBasicDetails UserBasicDetails { get; set; }
public const string BaseUrl = "https://localhost:7116";
}
}

View File

@ -4,7 +4,12 @@ namespace TIAMWebApp.Shared.Application.Utility
{
public class LogToBrowserConsole
{
private readonly JSRuntime jsRuntime;
private readonly IJSRuntime jsRuntime;
public LogToBrowserConsole(IJSRuntime jsRuntime)
{
this.jsRuntime = jsRuntime;
}
public void LogToBC(string message)
{

View File

@ -1,48 +0,0 @@
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using System.Security.Cryptography;
public class PasswordHasher
{
public string HashPassword(string password)
{
// Generate a random salt
byte[] salt = new byte[16];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
// Hash the password with the salt
string hashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA512,
iterationCount: 10000,
numBytesRequested: 32));
// Combine the salt and hashed password
string combinedHash = $"$bcrypt$v=1$salt={Convert.ToBase64String(salt)}$hash={hashedPassword}";
return combinedHash;
}
public bool VerifyPassword(string password, string hashedPassword)
{
// Extract the salt and hashed password from the combined hash
string[] parts = hashedPassword.Split('$');
byte[] salt = Convert.FromBase64String(parts[3]);
string storedHash = parts[5];
// Hash the provided password with the extracted salt
string hashedProvidedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
salt: salt,
prf: KeyDerivationPrf.HMACSHA512,
iterationCount: 10000,
numBytesRequested: 32));
// Compare the hashed passwords
return storedHash == hashedProvidedPassword;
}
}