Replace custom socket implementation with SignalR.
Replace MSAL and custom cookie auth with Microsoft.Identity.EntityFramework Also some UI redesign to accommodate different login experience.
This commit is contained in:
72
Shogi.UI/Pages/Identity/LoginPage.razor
Normal file
72
Shogi.UI/Pages/Identity/LoginPage.razor
Normal file
@@ -0,0 +1,72 @@
|
||||
@page "/login"
|
||||
@inject IAccountManagement Acct
|
||||
@inject NavigationManager navigator
|
||||
|
||||
<main class="PrimaryTheme">
|
||||
<h1>Login</h1>
|
||||
|
||||
<section class="LoginForm">
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<div>You're logged in as @context.User.Identity?.Name.</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
@if (errorList.Length > 0)
|
||||
{
|
||||
<ul class="Errors" style="grid-area: errors">
|
||||
@foreach (var error in errorList)
|
||||
{
|
||||
<li>@error</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
<label for="email" style="grid-area: emailLabel">Email</label>
|
||||
<input required id="email" name="emailInput" type="email" style="grid-area: emailControl" @bind-value="email" />
|
||||
|
||||
<label for="password" style="grid-area: passLabel">Password</label>
|
||||
<input required id="password" name="passwordInput" type="password" style="grid-area: passControl" @bind-value="password" />
|
||||
|
||||
<button style="grid-area: button" @onclick="DoLoginAsync">Login</button>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
@code {
|
||||
private string email = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string[] errorList = [];
|
||||
|
||||
public async Task DoLoginAsync()
|
||||
{
|
||||
errorList = [];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
errorList = ["Email is required."];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
errorList = ["Password is required."];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await Acct.LoginAsync(email, password);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
email = password = string.Empty;
|
||||
navigator.NavigateTo("/");
|
||||
}
|
||||
else
|
||||
{
|
||||
errorList = result.ErrorList;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Shogi.UI/Pages/Identity/LoginPage.razor.css
Normal file
28
Shogi.UI/Pages/Identity/LoginPage.razor.css
Normal file
@@ -0,0 +1,28 @@
|
||||
main {
|
||||
/*display: grid;
|
||||
grid-template-areas:
|
||||
"header header header"
|
||||
". form ."
|
||||
". . .";
|
||||
grid-template-rows: auto 1fr 1fr;
|
||||
|
||||
place-items: center;
|
||||
*/
|
||||
}
|
||||
|
||||
.LoginForm {
|
||||
grid-area: form;
|
||||
|
||||
display: inline-grid;
|
||||
grid-template-areas:
|
||||
"errors errors"
|
||||
"emailLabel emailControl"
|
||||
"passLabel passControl"
|
||||
"button button";
|
||||
gap: 0.5rem 3rem;
|
||||
}
|
||||
|
||||
.LoginForm .Errors {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
30
Shogi.UI/Pages/Identity/LogoutPage.razor
Normal file
30
Shogi.UI/Pages/Identity/LogoutPage.razor
Normal file
@@ -0,0 +1,30 @@
|
||||
@page "/logout"
|
||||
@inject IAccountManagement Acct
|
||||
|
||||
<main class="PrimaryTheme">
|
||||
<h1>Logout</h1>
|
||||
|
||||
<AuthorizeView @ref="authView">
|
||||
<Authorized>
|
||||
<div class="alert alert-info">Logging you out...</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<p>Thanks for playing!</p>
|
||||
<div class="alert alert-success">You're logged out. <a href="/login">Log in.</a></div>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</main>
|
||||
|
||||
@code {
|
||||
private AuthorizeView? authView;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (await Acct.CheckAuthenticatedAsync())
|
||||
{
|
||||
await Acct.LogoutAsync();
|
||||
}
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
}
|
||||
93
Shogi.UI/Pages/Identity/RegisterPage.razor
Normal file
93
Shogi.UI/Pages/Identity/RegisterPage.razor
Normal file
@@ -0,0 +1,93 @@
|
||||
@page "/register"
|
||||
@inject IAccountManagement Acct
|
||||
|
||||
<main class="PrimaryTheme">
|
||||
<h1>Register</h1>
|
||||
|
||||
<section class="LoginForm">
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<div class="alert alert-success">You're already logged in as @context.User.Identity?.Name.</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
@if (showNextSteps)
|
||||
{
|
||||
<p>Thank you for joining! You will receive an email asking to confirm you own this email address.</p>
|
||||
}
|
||||
@if (errorList.Length > 0)
|
||||
{
|
||||
<ul class="Errors" style="grid-area: errors">
|
||||
@foreach (var error in errorList)
|
||||
{
|
||||
<li>@error</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
<label for="email" style="grid-area: emailLabel">Email</label>
|
||||
<input autofocus autocomplete="on" required id="email" name="emailInput" type="email" style="grid-area: emailControl" @bind-value="email" />
|
||||
|
||||
<label for="password" style="grid-area: passLabel">Password</label>
|
||||
<input required id="password" name="passwordInput" type="password" style="grid-area: passControl" @bind-value="password" /><br />
|
||||
|
||||
<label for="confirmPassword" style="grid-area: confirmLabel">Retype password</label>
|
||||
<input required id="confirmPassword" name="confirmPasswordInput" type="password" style="grid-area: confirmControl" @bind-value="confirmPassword" />
|
||||
|
||||
<button style="grid-area: button" @onclick="DoRegisterAsync">Register</button>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@code {
|
||||
private bool showNextSteps;
|
||||
private string email = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string confirmPassword = string.Empty;
|
||||
private string[] errorList = [];
|
||||
|
||||
public async Task DoRegisterAsync()
|
||||
{
|
||||
errorList = [];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
errorList = ["Email is required."];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
errorList = ["Password is required."];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(confirmPassword))
|
||||
{
|
||||
errorList = ["Please confirm your password."];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (password != confirmPassword)
|
||||
{
|
||||
errorList = ["Passwords don't match."];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await Acct.RegisterAsync(email, password);
|
||||
|
||||
if (result.Succeeded)
|
||||
{
|
||||
email = password = confirmPassword = string.Empty;
|
||||
showNextSteps = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorList = result.ErrorList;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Shogi.UI/Pages/Identity/RegisterPage.razor.css
Normal file
15
Shogi.UI/Pages/Identity/RegisterPage.razor.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.LoginForm {
|
||||
grid-area: form;
|
||||
display: inline-grid;
|
||||
grid-template-areas:
|
||||
"errors errors"
|
||||
"emailLabel emailControl"
|
||||
"passLabel passControl"
|
||||
"confirmLabel confirmControl"
|
||||
"button button";
|
||||
gap: 0.5rem 3rem;
|
||||
}
|
||||
|
||||
.LoginForm .Errors {
|
||||
color: darkred;
|
||||
}
|
||||
Reference in New Issue
Block a user