This commit is contained in:
2024-01-23 15:41:59 +01:00
Unverified
parent 5d5a69ccf7
commit 3b2b4c9b7e
76 changed files with 4100 additions and 888 deletions

View File

@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using SecureBank.Common;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -31,28 +32,32 @@ namespace SecureBank.Website.API
#region PUBLIC METHODS
public async Task<APIResponse<TResponse>> SendAsync<TResponse>(APIMethodType type, string url)
public async Task<APIResponse<TResponse>> SendAsync<TResponse>(APIMethodType type, string url, Dictionary<string, string>? query = null)
{
return await SendRequestAsync<APIResponse<TResponse>>(type, url, null);
url = AddQuery(url, query);
return await SendRequestAndParseBodyAsync<TResponse>(type, url, null);
}
public async Task<APIResponse> SendAsync(APIMethodType type, string url)
public async Task<APIResponse> SendAsync(APIMethodType type, string url, Dictionary<string, string>? query = null)
{
return await SendRequestAsync<APIResponse>(type, url, null);
url = AddQuery(url, query);
return await SendRequestAndParseBodyAsync(type, url, null);
}
public async Task<APIResponse<TResponse>> SendAsync<TResponse, TBody>(APIMethodType type, string url, TBody body)
public async Task<APIResponse<TResponse>> SendAsync<TResponse, TBody>(APIMethodType type, string url, TBody body, Dictionary<string, string>? query = null)
{
url = AddQuery(url, query);
HttpContent content = PrepareBody(body);
return await SendRequestAsync<APIResponse<TResponse>>(type, url, content);
return await SendRequestAndParseBodyAsync<TResponse>(type, url, content);
}
public async Task<APIResponse> SendAsync<TBody>(APIMethodType type, string url, TBody body)
public async Task<APIResponse> SendAsync<TBody>(APIMethodType type, string url, TBody body, Dictionary<string, string>? query = null)
{
url = AddQuery(url, query);
HttpContent content = PrepareBody(body);
return await SendRequestAsync<APIResponse>(type, url, content);
return await SendRequestAndParseBodyAsync(type, url, content);
}
#endregion
@@ -61,6 +66,25 @@ namespace SecureBank.Website.API
#region PRIVATE METHODS
private string AddQuery(string url, Dictionary<string, string>? query)
{
if (query is not null && query.Count > 0)
{
Dictionary<string, string> queryNew = query.ToDictionary();
StringBuilder sb = new StringBuilder(url);
KeyValuePair<string, string> item = queryNew.ElementAt(0);
queryNew.Remove(item.Key);
sb.Append($"?{item.Key}={item.Value}");
foreach (KeyValuePair<string, string> item2 in queryNew)
{
sb.Append($"&{item2.Key}={item2.Value}");
}
return sb.ToString();
}
return url;
}
private HttpContent PrepareBody<T>(T body)
{
string json = JsonConvert.SerializeObject(body);
@@ -71,37 +95,103 @@ namespace SecureBank.Website.API
return content;
}
private async Task<T> SendRequestAsync<T>(APIMethodType type, string url, HttpContent? content)
private async Task<APIResponse> SendRequestAndParseBodyAsync(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()
};
HttpResponseMessage response = await SendRequestAsync(type, url, content);
string stringResponse = await response.Content.ReadAsStringAsync();
string responseBodyString = await response.Content.ReadAsStringAsync();
T? responseBodyObject = JsonConvert.DeserializeObject<T>(responseBodyString);
APIResponse? responseBodyObject = JsonConvert.DeserializeObject<APIResponse>(stringResponse);
if (responseBodyObject is null)
{
throw new Exception($"Wrong response type. Response: {responseBodyString}; {response.StatusCode}");
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
return new APIResponse
{
Status = ResponseStatus.Unauthorized,
Message = $"You do not have permission"
};
}
else
{
return new APIResponse
{
Status = ResponseStatus.BadRequest,
Message = $"Wrong response type. Response: {stringResponse}; {response.StatusCode}"
};
}
}
return responseBodyObject;
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
return new APIResponse
{
Status = ResponseStatus.BadRequest,
Message = ex.Message
};
}
}
private async Task<APIResponse<T>> SendRequestAndParseBodyAsync<T>(APIMethodType type, string url, HttpContent? content)
{
try
{
HttpResponseMessage response = await SendRequestAsync(type, url, content);
string stringResponse = await response.Content.ReadAsStringAsync();
APIResponse<T>? responseBodyObject = JsonConvert.DeserializeObject<APIResponse<T>>(stringResponse);
if (responseBodyObject is null)
{
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
return new APIResponse<T>
{
Status = ResponseStatus.Unauthorized,
Message = $"You do not have permission"
};
}
else
{
return new APIResponse<T>
{
Status = ResponseStatus.BadRequest,
Message = $"Wrong response type. Response: {stringResponse}; {response.StatusCode}"
};
}
}
return responseBodyObject;
}
catch (Exception ex)
{
return new APIResponse<T>
{
Status = ResponseStatus.BadRequest,
Message = ex.Message
};
}
}
private async Task<HttpResponseMessage> SendRequestAsync(APIMethodType type, string url, HttpContent? content)
{
return type switch
{
APIMethodType.GET => await _httpClient.GetAsync(url),
APIMethodType.POST => await _httpClient.PostAsync(url, content),
APIMethodType.PUT => await _httpClient.PutAsync(url, content),
APIMethodType.PATCH => await _httpClient.PatchAsync(url, content),
APIMethodType.DELETE => await _httpClient.DeleteAsync(url),
_ => throw new NotImplementedException()
};
}
#endregion
}
}

View File

@@ -16,9 +16,25 @@ namespace SecureBank.Website.API
// Accounts
public string AccountsBase { get; private set; }
public string AccountsCreateAccount { get; private set; }
public string AccountsChangePassword { get; private set; }
public string AccountsGetPasswordVariant { get; private set; }
public string AccountsAuthentication { get; private set; }
public string AccountsAuthenticationRefresh { get; private set; }
public string AccountsGetAccounts { get; private set; }
public string AccountsResetPassword { get; private set; }
public string AccountsUnlockAccount { get; private set; }
// Balance
public string BalanceBase { get; private set; }
public string BalanceGetAccountBalance { get; private set; }
public string BalanceGetBalance { get; private set; }
// Transfers
public string TransfersBase { get; private set; }
public string TransfersGetUserTransfers { get; private set; }
public string TransfersGetTransfers { get; private set; }
public string TransfersCreateAdminTransfer { get; private set; }
public string TransfersCreateUserTransfer { get; private set; }
#endregion
@@ -32,9 +48,23 @@ namespace SecureBank.Website.API
AccountsBase = $"{Base}{configuration.GetSection("Endpoints").GetSection("Accounts")["Base"]}";
AccountsCreateAccount = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["CreateAccount"]}";
AccountsChangePassword = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["ChangePassword"]}";
AccountsGetPasswordVariant = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["GetPasswordVariant"]}";
AccountsAuthentication = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["Authentication"]}";
AccountsAuthenticationRefresh = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["AuthenticationRefresh"]}";
AccountsGetAccounts = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["GetAccounts"]}";
AccountsResetPassword = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["ResetPassword"]}";
AccountsUnlockAccount = $"{AccountsBase}{configuration.GetSection("Endpoints").GetSection("Accounts")["UnlockAccount"]}";
BalanceBase = $"{Base}{configuration.GetSection("Endpoints").GetSection("Balance")["Base"]}";
BalanceGetAccountBalance = $"{BalanceBase}{configuration.GetSection("Endpoints").GetSection("Balance")["GetAccountBalance"]}";
BalanceGetBalance = $"{BalanceBase}{configuration.GetSection("Endpoints").GetSection("Balance")["GetBalance"]}";
TransfersBase = $"{Base}{configuration.GetSection("Endpoints").GetSection("Transfers")["Base"]}";
TransfersGetTransfers = $"{TransfersBase}{configuration.GetSection("Endpoints").GetSection("Transfers")["GetTransfers"]}";
TransfersGetUserTransfers = $"{TransfersBase}{configuration.GetSection("Endpoints").GetSection("Transfers")["GetUserTransfers"]}";
TransfersCreateAdminTransfer = $"{TransfersBase}{configuration.GetSection("Endpoints").GetSection("Transfers")["CreateAdminTransfer"]}";
TransfersCreateUserTransfer = $"{TransfersBase}{configuration.GetSection("Endpoints").GetSection("Transfers")["CreateUserTransfer"]}";
}
#endregion

View File

@@ -11,6 +11,7 @@ namespace SecureBank.Website.API
GET,
POST,
PUT,
PATCH,
DELETE
}
}

View File

@@ -9,10 +9,10 @@
<ItemGroup>
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\SecureBank.Helpers\SecureBank.Helpers.csproj" />
<ProjectReference Include="..\SecureBank.Website.Services\SecureBank.Website.Services.csproj" />
</ItemGroup>

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using System.Threading.Tasks;
@@ -27,8 +28,8 @@ namespace SecureBank.Website.Authentication
#region CONSTRUCTORS
public TokenAuthenticationStateProvider(IAccountsService accountsService, AuthenticationHelper authenticationHelper, HttpClient httpClient)
{
public TokenAuthenticationStateProvider(IAccountsService accountsService, AuthenticationHelper authenticationHelper, HttpClient httpClient)
{
_accountsService = accountsService;
_authenticationHelper = authenticationHelper;
_httpClient = httpClient;
@@ -56,16 +57,22 @@ namespace SecureBank.Website.Authentication
APIResponse<string> refreshResponse = await _accountsService.AuthenticationRefresh();
if (!refreshResponse.Success)
if (refreshResponse.Status != ResponseStatus.Ok)
{
await _authenticationHelper.RemoveToken();
_httpClient.DefaultRequestHeaders.Authorization = null;
return state;
}
token = refreshResponse.Data;
await _authenticationHelper.SaveToken(token);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
state = new AuthenticationState(new ClaimsPrincipal()); //TODO: Add claims
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
JwtSecurityToken tokenParsed = tokenHandler.ReadJwtToken(token);
state = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(tokenParsed.Claims)));
return state;
}

View File

@@ -15,6 +15,10 @@ namespace SecureBank.Website.Services
Task<APIResponse<GetPasswordVariantResponse>> GetPasswordVariant(int accountId);
Task<APIResponse<string>> Authentication(int accountId, AuthenticationRequest data);
Task<APIResponse<string>> AuthenticationRefresh();
Task<APIResponse> ChangePassword(ChangePasswordRequest data);
Task<APIResponse<IEnumerable<AccountResponse>>> GetAccounts(int? id = null, string? iban = null);
Task<APIResponse> ResetPassword(int accountId);
Task<APIResponse> UnlockAccount(int accountId);
}
@@ -57,8 +61,7 @@ namespace SecureBank.Website.Services
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);
return await _apiClient.SendAsync<string, AuthenticationRequest>(APIMethodType.POST, _configuration.AccountsAuthentication, data);
}
public async Task<APIResponse<string>> AuthenticationRefresh()
@@ -66,6 +69,37 @@ namespace SecureBank.Website.Services
return await _apiClient.SendAsync<string>(APIMethodType.POST, _configuration.AccountsAuthenticationRefresh);
}
public async Task<APIResponse> ChangePassword(ChangePasswordRequest data)
{
return await _apiClient.SendAsync(APIMethodType.PATCH, _configuration.AccountsChangePassword, data);
}
public async Task<APIResponse<IEnumerable<AccountResponse>>> GetAccounts(int? id = null, string? iban = null)
{
Dictionary<string, string> query = new Dictionary<string, string>();
if (id.HasValue)
{
query.Add("id", id.Value.ToString());
}
if (iban is not null)
{
query.Add("iban", iban);
}
return await _apiClient.SendAsync<IEnumerable<AccountResponse>>(APIMethodType.GET, _configuration.AccountsGetAccounts, query);
}
public async Task<APIResponse> ResetPassword(int accountId)
{
string url = string.Format(_configuration.AccountsResetPassword, accountId);
return await _apiClient.SendAsync(APIMethodType.PATCH, url);
}
public async Task<APIResponse> UnlockAccount(int accountId)
{
string url = string.Format(_configuration.AccountsUnlockAccount, accountId);
return await _apiClient.SendAsync(APIMethodType.PATCH, url);
}
#endregion
}
}

View File

@@ -0,0 +1,58 @@
using SecureBank.Common.Accounts;
using SecureBank.Common;
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 IBalanceService
{
Task<APIResponse<decimal>> GetAccountBalance(int accountId);
Task<APIResponse<decimal>> GetBalance();
}
public class BalanceService : IBalanceService
{
#region FIELDS
private readonly APIClient _apiClient;
private readonly APIEndpointsConfiguration _configuration;
#endregion
#region CONSTRUCTORS
public BalanceService(APIClient apiClient, APIEndpointsConfiguration configuration)
{
_apiClient = apiClient;
_configuration = configuration;
}
#endregion
#region METHODS
public async Task<APIResponse<decimal>> GetAccountBalance(int accountId)
{
string url = string.Format(_configuration.BalanceGetAccountBalance, accountId);
return await _apiClient.SendAsync<decimal>(APIMethodType.GET, url);
}
public async Task<APIResponse<decimal>> GetBalance()
{
return await _apiClient.SendAsync<decimal>(APIMethodType.GET, _configuration.BalanceGetBalance);
}
#endregion
}
}

View File

@@ -0,0 +1,72 @@
using SecureBank.Common.Accounts;
using SecureBank.Common;
using SecureBank.Website.API;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SecureBank.Common.Transfers;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace SecureBank.Website.Services
{
public interface ITransfersService
{
Task<APIResponse> CreateAdminTransfer(CreateAdminTransferRequest data);
Task<APIResponse> CreateUserTransfer(CreateUserTransferRequest data);
Task<APIResponse<IEnumerable<TransferResponse>>> GetTransfers();
Task<APIResponse<IEnumerable<TransferResponse>>> GetUserTransfers(int accountId);
}
public class TransfersService : ITransfersService
{
#region FIELDS
private readonly APIClient _apiClient;
private readonly APIEndpointsConfiguration _configuration;
#endregion
#region CONSTRUCTORS
public TransfersService(APIClient apiClient, APIEndpointsConfiguration configuration)
{
_apiClient = apiClient;
_configuration = configuration;
}
#endregion
#region METHODS
public async Task<APIResponse<IEnumerable<TransferResponse>>> GetTransfers()
{
return await _apiClient.SendAsync<IEnumerable<TransferResponse>>(APIMethodType.GET, _configuration.TransfersGetTransfers);
}
public async Task<APIResponse<IEnumerable<TransferResponse>>> GetUserTransfers(int accountId)
{
string url = string.Format(_configuration.TransfersGetUserTransfers, accountId);
return await _apiClient.SendAsync<IEnumerable<TransferResponse>>(APIMethodType.GET, url);
}
public async Task<APIResponse> CreateAdminTransfer(CreateAdminTransferRequest data)
{
return await _apiClient.SendAsync(APIMethodType.POST, _configuration.TransfersCreateAdminTransfer, data);
}
public async Task<APIResponse> CreateUserTransfer(CreateUserTransferRequest data)
{
return await _apiClient.SendAsync(APIMethodType.POST, _configuration.TransfersCreateUserTransfer, data);
}
#endregion
}
}