This commit is contained in:
2024-01-19 17:25:56 +01:00
Unverified
parent ab9be442ee
commit 5d5a69ccf7
69 changed files with 3769 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
using Newtonsoft.Json;
using SecureBank.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SecureBank.Website.API
{
public class APIClient
{
#region FIELDS
private readonly HttpClient _httpClient;
#endregion
#region CONSTRUCTORS
public APIClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
#endregion
#region PUBLIC METHODS
public async Task<APIResponse<TResponse>> SendAsync<TResponse>(APIMethodType type, string url)
{
return await SendRequestAsync<APIResponse<TResponse>>(type, url, null);
}
public async Task<APIResponse> SendAsync(APIMethodType type, string url)
{
return await SendRequestAsync<APIResponse>(type, url, null);
}
public async Task<APIResponse<TResponse>> SendAsync<TResponse, TBody>(APIMethodType type, string url, TBody body)
{
HttpContent content = PrepareBody(body);
return await SendRequestAsync<APIResponse<TResponse>>(type, url, content);
}
public async Task<APIResponse> SendAsync<TBody>(APIMethodType type, string url, TBody body)
{
HttpContent content = PrepareBody(body);
return await SendRequestAsync<APIResponse>(type, url, content);
}
#endregion
#region PRIVATE METHODS
private HttpContent PrepareBody<T>(T body)
{
string json = JsonConvert.SerializeObject(body);
HttpContent content = new StringContent(json);
content.Headers.ContentType.MediaType = "application/json";
return content;
}
private async Task<T> SendRequestAsync<T>(APIMethodType type, string url, HttpContent? content)
{
try
{
HttpResponseMessage response = type switch
{
APIMethodType.GET => await _httpClient.GetAsync(url),
APIMethodType.POST => await _httpClient.PostAsync(url, content),
APIMethodType.PUT => await _httpClient.PutAsync(url, content),
APIMethodType.DELETE => await _httpClient.DeleteAsync(url),
_ => throw new NotImplementedException()
};
string responseBodyString = await response.Content.ReadAsStringAsync();
T? responseBodyObject = JsonConvert.DeserializeObject<T>(responseBodyString);
if (responseBodyObject is null)
{
throw new Exception($"Wrong response type. Response: {responseBodyString}; {response.StatusCode}");
}
return responseBodyObject;
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
#endregion
}
}

View File

@@ -0,0 +1,42 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SecureBank.Website.API
{
public class APIEndpointsConfiguration
{
#region PROPERTIES
public string Base { get; private set; }
// Accounts
public string AccountsBase { get; private set; }
public string AccountsCreateAccount { get; private set; }
public string AccountsGetPasswordVariant { get; private set; }
public string AccountsAuthentication { get; private set; }
public string AccountsAuthenticationRefresh { get; private set; }
#endregion
#region CONSTRUCTORS
public APIEndpointsConfiguration(IConfiguration configuration)
{
Base = configuration.GetSection("Endpoints")["Base"];
AccountsBase = $"{Base}{configuration.GetSection("Endpoints").GetSection("Accounts")["Base"]}";
AccountsCreateAccount = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["CreateAccount"]}";
AccountsGetPasswordVariant = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["GetPasswordVariant"]}";
AccountsAuthentication = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["Authentication"]}";
AccountsAuthenticationRefresh = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["AuthenticationRefresh"]}";
}
#endregion
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SecureBank.Website.API
{
public enum APIMethodType
{
GET,
POST,
PUT,
DELETE
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\SecureBank.Common\SecureBank.Common.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,49 @@
using Blazored.SessionStorage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SecureBank.Website.Authentication
{
public class AuthenticationHelper
{
#region CONSTANTS
private const string TOKEN_KEY = "token";
#endregion
#region SERVICES
private readonly ISessionStorageService _sessionStorageService;
#endregion
#region CONSTRUCTIONS
public AuthenticationHelper(ISessionStorageService sessionStorageService)
{
_sessionStorageService = sessionStorageService;
}
#endregion
#region PUBLIC METHODS
public async Task<string> GetToken() => await _sessionStorageService.GetItemAsync<string>(TOKEN_KEY);
public async Task SaveToken(string token) => await _sessionStorageService.SetItemAsync(TOKEN_KEY, token);
public async Task RemoveToken() => await _sessionStorageService.RemoveItemAsync(TOKEN_KEY);
#endregion
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\SecureBank.Helpers\SecureBank.Helpers.csproj" />
<ProjectReference Include="..\SecureBank.Website.Services\SecureBank.Website.Services.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,75 @@
using Microsoft.AspNetCore.Components.Authorization;
using SecureBank.Common;
using SecureBank.Website.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace SecureBank.Website.Authentication
{
public class TokenAuthenticationStateProvider : AuthenticationStateProvider
{
#region SERVICES
private readonly IAccountsService _accountsService;
private readonly AuthenticationHelper _authenticationHelper;
private readonly HttpClient _httpClient;
#endregion
#region CONSTRUCTORS
public TokenAuthenticationStateProvider(IAccountsService accountsService, AuthenticationHelper authenticationHelper, HttpClient httpClient)
{
_accountsService = accountsService;
_authenticationHelper = authenticationHelper;
_httpClient = httpClient;
}
#endregion
#region PUBLIC METHODS
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
_httpClient.DefaultRequestHeaders.Authorization = null;
AuthenticationState state = new AuthenticationState(new ClaimsPrincipal());
string token = await _authenticationHelper.GetToken();
if (string.IsNullOrWhiteSpace(token))
{
return state;
}
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
APIResponse<string> refreshResponse = await _accountsService.AuthenticationRefresh();
if (!refreshResponse.Success)
{
_httpClient.DefaultRequestHeaders.Authorization = null;
return state;
}
token = refreshResponse.Data;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
state = new AuthenticationState(new ClaimsPrincipal()); //TODO: Add claims
return state;
}
#endregion
}
}

View File

@@ -0,0 +1,71 @@
using SecureBank.Common;
using SecureBank.Common.Accounts;
using SecureBank.Website.API;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SecureBank.Website.Services
{
public interface IAccountsService
{
Task<APIResponse<int>> CreateAccount(CreateAccountRequest data);
Task<APIResponse<GetPasswordVariantResponse>> GetPasswordVariant(int accountId);
Task<APIResponse<string>> Authentication(int accountId, AuthenticationRequest data);
Task<APIResponse<string>> AuthenticationRefresh();
}
public class AccountsService : IAccountsService
{
#region FIELDS
private readonly APIClient _apiClient;
private readonly APIEndpointsConfiguration _configuration;
#endregion
#region CONSTRUCTORS
public AccountsService(APIClient apiClient, APIEndpointsConfiguration configuration)
{
_apiClient = apiClient;
_configuration = configuration;
}
#endregion
#region METHODS
public async Task<APIResponse<int>> CreateAccount(CreateAccountRequest data)
{
return await _apiClient.SendAsync<int, CreateAccountRequest>(APIMethodType.POST, _configuration.AccountsCreateAccount, data);
}
public async Task<APIResponse<GetPasswordVariantResponse>> GetPasswordVariant(int accountId)
{
string url = string.Format(_configuration.AccountsGetPasswordVariant, accountId);
return await _apiClient.SendAsync<GetPasswordVariantResponse>(APIMethodType.GET, url);
}
public async Task<APIResponse<string>> Authentication(int accountId, AuthenticationRequest data)
{
string url = string.Format(_configuration.AccountsAuthentication, accountId);
return await _apiClient.SendAsync<string, AuthenticationRequest>(APIMethodType.POST, url, data);
}
public async Task<APIResponse<string>> AuthenticationRefresh()
{
return await _apiClient.SendAsync<string>(APIMethodType.POST, _configuration.AccountsAuthenticationRefresh);
}
#endregion
}
}

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\SecureBank.Common\SecureBank.Common.csproj" />
<ProjectReference Include="..\SecureBank.Website.API\SecureBank.Website.API.csproj" />
</ItemGroup>
</Project>