Auth and error handling components
This commit is contained in:
@@ -1,12 +1,16 @@
|
|||||||
<Router AppAssembly="@typeof(App).Assembly">
|
@using BlazorWebAssemblyVisaApiClient.ErrorHandling
|
||||||
<Found Context="routeData">
|
|
||||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
<GlobalErrorHandler >
|
||||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
<Router AppAssembly="@typeof(App).Assembly">
|
||||||
</Found>
|
<Found Context="routeData">
|
||||||
<NotFound>
|
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||||
<PageTitle>Not found</PageTitle>
|
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||||
<LayoutView Layout="@typeof(MainLayout)">
|
</Found>
|
||||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
<NotFound>
|
||||||
</LayoutView>
|
<PageTitle>Not found</PageTitle>
|
||||||
</NotFound>
|
<LayoutView Layout="@typeof(MainLayout)">
|
||||||
</Router>
|
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||||
|
</LayoutView>
|
||||||
|
</NotFound>
|
||||||
|
</Router>
|
||||||
|
</GlobalErrorHandler>
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace BlazorWebAssemblyVisaApiClient.Common
|
||||||
|
{
|
||||||
|
public class BlazorClientException(string message) : Exception(message);
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
@using System.Net
|
||||||
|
@using BlazorWebAssemblyVisaApiClient.Components.Auth.Exceptions
|
||||||
|
@using BlazorWebAssemblyVisaApiClient.ErrorHandling
|
||||||
|
@using VisaApiClient
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public static bool LoggedIn;
|
||||||
|
private static AuthData savedData = null!;
|
||||||
|
|
||||||
|
[CascadingParameter] private GlobalErrorHandler ErrorHandler { get; set; } = null!;
|
||||||
|
|
||||||
|
[CascadingParameter] private Status? Status { get; set; }
|
||||||
|
|
||||||
|
[Inject] private Client Client { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject] private NavigationManager Nav { get; set; } = null!;
|
||||||
|
|
||||||
|
///Authorize with email and password
|
||||||
|
/// <returns>Message to user</returns>
|
||||||
|
public async Task TryAuthorize(AuthData authData)
|
||||||
|
{
|
||||||
|
Status?.SetMessage("Wait...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var token = await Client.LoginAsync(authData.Email, authData.Password);
|
||||||
|
Client.SetAuthToken(token);
|
||||||
|
savedData = authData;
|
||||||
|
|
||||||
|
Status?.SetSucces("Logged in successfully.");
|
||||||
|
}
|
||||||
|
catch (ApiException<ProblemDetails> e)
|
||||||
|
{
|
||||||
|
if (e.Result.Status == (int)HttpStatusCode.Forbidden)
|
||||||
|
{
|
||||||
|
Status?.SetError(e.Result.Detail!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status?.SetError("Error occured");
|
||||||
|
ErrorHandler.Handle(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Status?.SetError("Error occured");
|
||||||
|
ErrorHandler.Handle(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///Re-auth if token expired or something
|
||||||
|
public async Task ReAuthenticate(bool redirectOnFailure = true)
|
||||||
|
{
|
||||||
|
if (!LoggedIn)
|
||||||
|
{
|
||||||
|
if (redirectOnFailure)
|
||||||
|
{
|
||||||
|
Nav.NavigateTo("/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotLoggedInException();
|
||||||
|
}
|
||||||
|
|
||||||
|
await TryAuthorize(savedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using BlazorWebAssemblyVisaApiClient.Common;
|
||||||
|
using VisaApiClient;
|
||||||
|
|
||||||
|
namespace BlazorWebAssemblyVisaApiClient.Components.Auth.Exceptions
|
||||||
|
{
|
||||||
|
public class NotLoggedInException() : BlazorClientException("User is not logged in");
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@using BlazorWebAssemblyVisaApiClient.ErrorHandling
|
||||||
|
@using VisaApiClient
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[CascadingParameter] protected GlobalErrorHandler ErrorHandler { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject] protected Client Client { get; set; } = null!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<p class="@statusClass">@((MarkupString)StatusText)</p>
|
||||||
|
<CascadingValue Value="this">
|
||||||
|
@ChildContent
|
||||||
|
</CascadingValue>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string statusClass = string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public RenderFragment? ChildContent { get; set; }
|
||||||
|
|
||||||
|
public string StatusText { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public void SetMessage(string message)
|
||||||
|
{
|
||||||
|
statusClass = string.Empty;
|
||||||
|
StatusText = message;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetError(string message)
|
||||||
|
{
|
||||||
|
statusClass = "validation-message";
|
||||||
|
StatusText = message;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSucces(string message)
|
||||||
|
{
|
||||||
|
statusClass = "text-success";
|
||||||
|
StatusText = message;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<CascadingValue Value="this">
|
||||||
|
@ChildContent
|
||||||
|
</CascadingValue>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public RenderFragment? ChildContent { get; set; }
|
||||||
|
|
||||||
|
public void Handle(Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
|
@using System.Net
|
||||||
|
@using BlazorWebAssemblyVisaApiClient.Components.Auth
|
||||||
@using VisaApiClient
|
@using VisaApiClient
|
||||||
@using BlazorWebAssemblyVisaApiClient.Components.FormComponents.Applicants
|
@using BlazorWebAssemblyVisaApiClient.Components.FormComponents.Applicants
|
||||||
|
@using BlazorWebAssemblyVisaApiClient.Components
|
||||||
|
@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase
|
||||||
|
|
||||||
<PageTitle>Authentication</PageTitle>
|
<PageTitle>Authentication</PageTitle>
|
||||||
|
|
||||||
@@ -13,30 +17,17 @@
|
|||||||
<input class="btn-outline-primary rounded" type="submit" value="Login"/>
|
<input class="btn-outline-primary rounded" type="submit" value="Login"/>
|
||||||
or
|
or
|
||||||
<NavLink href="register">Register</NavLink >
|
<NavLink href="register">Register</NavLink >
|
||||||
<p>@loginResult</p>
|
<Status><AuthComponent @ref="auth"/></Status>
|
||||||
</EditForm>
|
</EditForm>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private AuthData loginData = new();
|
private AuthData loginData = new();
|
||||||
private string loginResult = string.Empty;
|
private AuthComponent auth = null!;
|
||||||
|
|
||||||
[Inject] private Client Client { get; set; } = null!;
|
|
||||||
|
|
||||||
private async Task TryLogin()
|
private async Task TryLogin()
|
||||||
{
|
{
|
||||||
loginResult = "Wait...";
|
await auth.TryAuthorize(loginData);
|
||||||
StateHasChanged();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var token = await Client.LoginAsync(loginData.Email, loginData.Password);
|
|
||||||
Client.SetAuthToken(token);
|
|
||||||
loginResult = "Logged in successfully.";
|
|
||||||
}
|
|
||||||
catch (ApiException<ProblemDetails> e)
|
|
||||||
{
|
|
||||||
loginResult = e.Result.Detail!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
@using global::FluentValidation
|
@using global::FluentValidation
|
||||||
@using Newtonsoft.Json
|
@using Newtonsoft.Json
|
||||||
@using Newtonsoft.Json.Linq
|
@using Newtonsoft.Json.Linq
|
||||||
|
@using BlazorWebAssemblyVisaApiClient.Components
|
||||||
|
@inherits BlazorWebAssemblyVisaApiClient.Components.Base.VisaClientComponentBase
|
||||||
|
|
||||||
<PageTitle>Registration</PageTitle>
|
<PageTitle>Registration</PageTitle>
|
||||||
|
|
||||||
@@ -122,17 +124,14 @@
|
|||||||
</div><br/>
|
</div><br/>
|
||||||
|
|
||||||
<input type="submit" class="btn-outline-primary" value="Register"/>
|
<input type="submit" class="btn-outline-primary" value="Register"/>
|
||||||
<p class="@requestResultClass">@((MarkupString)requestResult)</p>
|
<Status @ref="status"/>
|
||||||
</EditForm>
|
</EditForm>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private RegisterApplicantRequestModel requestModel = new();
|
private RegisterApplicantRequestModel requestModel = new();
|
||||||
private string requestResult = string.Empty;
|
private Status status = null!;
|
||||||
private string requestResultClass = string.Empty;
|
|
||||||
|
|
||||||
[Inject] public Client Client { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject] IValidator<RegisterApplicantRequestModel> RegisterApplicantRequestValidator { get; set; } = null!;
|
[Inject] IValidator<RegisterApplicantRequestModel> RegisterApplicantRequestValidator { get; set; } = null!;
|
||||||
|
|
||||||
@@ -145,27 +144,6 @@
|
|||||||
requestModel.BirthDate = DateTime.Now;
|
requestModel.BirthDate = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetRequestResultMessage(string message)
|
|
||||||
{
|
|
||||||
requestResult = message;
|
|
||||||
requestResultClass = string.Empty;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetRequestResultSuccess(string message)
|
|
||||||
{
|
|
||||||
requestResult = message;
|
|
||||||
requestResultClass = "text-success";
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetRequestResultError(string message)
|
|
||||||
{
|
|
||||||
requestResult = message;
|
|
||||||
requestResultClass = "validation-message";
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ErrorsToString(IEnumerable<string> errors)
|
private string ErrorsToString(IEnumerable<string> errors)
|
||||||
{
|
{
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
@@ -183,18 +161,18 @@
|
|||||||
if (!validationResult.IsValid)
|
if (!validationResult.IsValid)
|
||||||
{
|
{
|
||||||
var errorsString = ErrorsToString(validationResult.Errors.Select(e => e.ErrorMessage));
|
var errorsString = ErrorsToString(validationResult.Errors.Select(e => e.ErrorMessage));
|
||||||
SetRequestResultError(errorsString);
|
status.SetError(errorsString);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRequestResultMessage("Wait...");
|
status.SetMessage("Wait...");
|
||||||
|
|
||||||
var request = Mapper.Map<RegisterApplicantRequest>(requestModel);
|
var request = Mapper.Map<RegisterApplicantRequest>(requestModel);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Client.RegisterAsync(request);
|
await Client.RegisterAsync(request);
|
||||||
SetRequestResultSuccess("Register successful. Now log in.");
|
status.SetSucces("Register successful. Now log in.");
|
||||||
}
|
}
|
||||||
catch (ApiException<ProblemDetails> e)
|
catch (ApiException<ProblemDetails> e)
|
||||||
{
|
{
|
||||||
@@ -204,15 +182,21 @@
|
|||||||
var errorsList = ((JArray)errors).ToObject<List<string>>();
|
var errorsList = ((JArray)errors).ToObject<List<string>>();
|
||||||
if (errorsList is null)
|
if (errorsList is null)
|
||||||
{
|
{
|
||||||
throw new JsonException();
|
ErrorHandler.Handle(new JsonException("Can't convert validation errors to list"));
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRequestResultError(ErrorsToString(errorsList));
|
status.SetError(ErrorsToString(errorsList));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetRequestResultError(e.Result.Detail!);
|
ErrorHandler.Handle(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ErrorHandler.Handle(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user