Skip to content

Commit

Permalink
improve login, register and delete flows
Browse files Browse the repository at this point in the history
  • Loading branch information
NielsPilgaard committed Jul 30, 2024
1 parent 4173223 commit 0939e20
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public static IEndpointConventionBuilder MapAdditionalIdentityEndpoints(this IEn
[FromForm] string returnUrl) =>
{
await signInManager.SignOutAsync();
return TypedResults.LocalRedirect($"~/{returnUrl}");
return TypedResults.LocalRedirect(string.IsNullOrEmpty(returnUrl)
? "~/"
: returnUrl);
});

var manageGroup = accountGroup.MapGroup("/Manage").RequireAuthorization();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal sealed class IdentityRedirectManager(NavigationManager navigationManage
};

[DoesNotReturn]
public void RedirectTo(string? uri)
public void RedirectTo(string? uri, bool forceLoad = false)
{
uri ??= "";

Expand All @@ -29,7 +29,7 @@ public void RedirectTo(string? uri)

// During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect.
// So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown.
navigationManager.NavigateTo(uri);
navigationManager.NavigateTo(uri, forceLoad);
throw new InvalidOperationException($"{nameof(IdentityRedirectManager)} can only be used during static rendering.");
}

Expand Down Expand Up @@ -60,7 +60,7 @@ public void RedirectToWithStatus(string uri, AlertMessage? message, HttpContext
private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path);

[DoesNotReturn]
public void RedirectToCurrentPage() => RedirectTo(CurrentPath);
public void RedirectToCurrentPage(bool forceLoad = false) => RedirectTo(CurrentPath, forceLoad);

[DoesNotReturn]
public void RedirectToCurrentPageWithStatus(string message, HttpContext context)
Expand Down
12 changes: 10 additions & 2 deletions src/web/Jordnaer/Components/Account/Pages/ConfirmEmail.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@using System.Text
@using Microsoft.AspNetCore.WebUtilities

@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IdentityRedirectManager RedirectManager

Expand All @@ -23,6 +24,9 @@
[SupplyParameterFromQuery]
private string? Code { get; set; }

[SupplyParameterFromQuery]
private string? ReturnUrl { get; set; }

protected override async Task OnInitializedAsync()
{
if (UserId is null || Code is null)
Expand All @@ -34,15 +38,19 @@
if (user is null)
{
HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
_statusMessage = new AlertMessage("Fejl ved indlæsning af bruger med ID {UserId}", true);
_statusMessage = new AlertMessage($"Fejl ved indlæsning af bruger med ID {UserId}", true);
}
else
{
var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code));
var result = await UserManager.ConfirmEmailAsync(user, code);
if (result.Succeeded)
{
_statusMessage = new AlertMessage("Tak fordi du bekræftede din email.");
_statusMessage = new AlertMessage("Tak fordi du bekræftede din email, du bliver nu logget ind.");

await SignInManager.SignInAsync(user, isPersistent: true);

RedirectManager.RedirectTo(ReturnUrl ?? "/profile", forceLoad: true);
}
else
{
Expand Down
6 changes: 3 additions & 3 deletions src/web/Jordnaer/Components/Account/Pages/ExternalLogin.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@inject JordnaerDbContext Context
@inject IMediator Mediator

<MetadataComponent Title="Registrér"/>
<MetadataComponent Title="Registrér" />

<StatusMessage Message="@_message" />
<h1>Registrér</h1>
Expand Down Expand Up @@ -150,7 +150,7 @@
var result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
_message = new AlertMessage(result.Errors.Select(error => error.Description), true);
_message = new AlertMessage(result.Errors.Select(error => error.Description), true);
return;
}

Expand All @@ -175,7 +175,7 @@
// If account confirmation is required, we need to show the link if we don't have a real email sender
if (UserManager.Options.SignIn.RequireConfirmedAccount)
{
RedirectManager.RedirectTo("Account/RegisterConfirmation", new() { ["email"] = Input.Email });
RedirectManager.RedirectTo("Account/RegisterConfirmation", queryParameters: new() { ["email"] = Input.Email });
}

await SignInManager.SignInAsync(user, isPersistent: false, _externalLoginInfo.LoginProvider);
Expand Down
40 changes: 21 additions & 19 deletions src/web/Jordnaer/Components/Account/Pages/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,45 @@
@inject SignInManager<ApplicationUser> SignInManager
@inject ILogger<Login> Logger
@inject IdentityRedirectManager RedirectManager
@inject ILocalStorageService LocalStorage

<MudContainer MaxWidth="MaxWidth.Small">
<MudPaper Elevation="3" Class="pa-4">
<EditForm Model="Input" OnValidSubmit="LoginUser" FormName="login">

<StatusMessage Message="@_errorMessage"/>

<h2 class="font-open-sans-medium" style="@($"color: {JordnaerPalette.RedHeader}")">Log ind</h2>
<hr />

<div class="form-floating mb-3">
<InputText @bind-Value="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="[email protected]" />
<InputText @bind-Value="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="[email protected]"/>
<label for="email" class="form-label">Email</label>
<ValidationMessage For="() => Input.Email" class="text-danger" />
<ValidationMessage For="() => Input.Email" class="text-danger"/>
</div>

<div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="adgangskode" />
<InputText type="password" @bind-Value="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="adgangskode"/>
<label for="password" class="form-label">Adgangskode</label>
<ValidationMessage For="() => Input.Password" class="text-danger" />
</div>
<div class="checkbox mb-3">
<label class="form-label">
<InputCheckbox @bind-Value="Input.RememberMe" class="darker-border-checkbox form-check-input" />
Husk mig
</label>
<ValidationMessage For="() => Input.Password" class="text-danger"/>
</div>

<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Info" FullWidth>
Log ind
</MudButton>

<MudDivider DividerType="DividerType.FullWidth" Class="my-3"/>
<MudStack>
<MudLink Href="/Account/ForgotPassword">Glemt din adgangskode?</MudLink>
<MudLink Href="/Account/ResendEmailConfirmation">Gensend emailbekræftelse</MudLink>
<MudButton ButtonType="ButtonType.Button"
Variant="Variant.Filled"
Color="Color.Success"
<MudButton ButtonType="ButtonType.Button"
Variant="Variant.Filled"
Color="Color.Success"
FullWidth
Href="/Account/Register">
Opret ny konto
</MudButton>
</MudStack>

</EditForm>
</MudPaper>
<MudPaper Elevation="3" Class="pa-4 mt-4">
Expand Down Expand Up @@ -70,7 +72,10 @@

public async Task LoginUser()
{
var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);
var result = await SignInManager.PasswordSignInAsync(Input.Email,
Input.Password,
isPersistent: true,
lockoutOnFailure: true);
if (result.Succeeded)
{
Logger.LogInformation("User logged in.");
Expand All @@ -81,7 +86,7 @@
{
RedirectManager.RedirectTo(
"Account/LoginWith2fa",
new Dictionary<string, object?> { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe });
new Dictionary<string, object?> { ["returnUrl"] = ReturnUrl, ["rememberMe"] = true });
}
else if (result.IsLockedOut)
{
Expand All @@ -104,8 +109,5 @@
[DataType(DataType.Password)]
[Display(Name = "Adgangskode")]
public string Password { get; set; } = "";

[Display(Name = "Husk mig?")]
public bool RememberMe { get; set; }
}
}
8 changes: 4 additions & 4 deletions src/web/Jordnaer/Components/Account/Pages/Register.razor
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@

<div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="" />
<label for="password">Kodeord</label>
<label for="password">Adgangskode</label>
<ValidationMessage For="() => Input.Password" class="text-danger" />
</div>

<div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="" />
<label for="confirm-password">Bekræft kodeord</label>
<label for="confirm-password">Bekræft adgangskode</label>
<ValidationMessage For="() => Input.ConfirmPassword" class="text-danger" />
</div>

<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Success" FullWidth>Opret</MudButton>

<div class="d-flex justify-center">
<MudButton Href="/Account/Login" Class="mt-4" ButtonType="ButtonType.Button" Variant="Variant.Text" Color="Color.Info">
Login med eksisterende konto
Log ind med eksisterende konto
</MudButton>
</div>
</EditForm>
Expand Down Expand Up @@ -104,7 +104,7 @@
{
RedirectManager.RedirectTo(
"Account/RegisterConfirmation",
new() { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl });
queryParameters: new() { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl });
}

await SignInManager.SignInAsync(user, isPersistent: false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
@page "/Account/RegisterConfirmation"

@inject UserManager<ApplicationUser> UserManager
@inject IEmailSender<ApplicationUser> EmailSender
@inject NavigationManager NavigationManager
@inject IdentityRedirectManager RedirectManager

<MetadataComponent Title="Registreringsbekræftelse" />

<h1>Registreringsbekræftelse</h1>
<h2 class="font-open-sans-light">Registreringsbekræftelse</h2>

<StatusMessage Message="@_statusMessage" />

@*TODO: Opdater denne side, når emailen er bekræftet*@
<p>Check venligst din email for at bekræfte din konto.</p>
@*TODO: Allow resending email after 30 seconds in case it never arrives*@
<p>Check venligst din email for at bekræfte din konto. Du kan lukke denne side.</p>

@code {
private AlertMessage? _statusMessage;
Expand All @@ -31,7 +27,7 @@
{
if (Email is null)
{
RedirectManager.RedirectTo("");
RedirectManager.RedirectTo(ReturnUrl ?? "");
}

var user = await UserManager.FindByEmailAsync(Email);
Expand Down
3 changes: 2 additions & 1 deletion src/web/Jordnaer/Consumers/SendEmailConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ public async Task Consume(ConsumeContext<SendEmail> consumeContext)
}
else
{
logger.LogInformation("Email sent to {@Recipient}. Subject: {Subject}", message.To, message.Subject);
logger.LogInformation("Email sent to {@Recipient}. Subject: {Subject}",
message.To?.Select(x => x.Email), message.Subject);
}
}
}
16 changes: 0 additions & 16 deletions src/web/Jordnaer/Features/Authentication/EmailConfirmed.cs

This file was deleted.

Loading

0 comments on commit 0939e20

Please sign in to comment.