Fixed login form, navigation
This commit is contained in:
parent
27aaee6293
commit
51766eca42
4 changed files with 175 additions and 182 deletions
|
@ -4,16 +4,16 @@
|
|||
ViewData["Title"] = "Authenticate";
|
||||
}
|
||||
|
||||
<div class="row" style="display: flex; flex-direction: row;">
|
||||
<div class="col-md-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<form method="post">
|
||||
<h4>Login</h4>
|
||||
<h4>Login or Register</h4>
|
||||
<hr />
|
||||
@if (Model.LoginErrorMessages != null && Model.LoginErrorMessages.Any())
|
||||
@if (Model.ErrorMessages != null && Model.ErrorMessages.Any())
|
||||
{
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger" role="alert">
|
||||
<div class="text-danger" role="alert">
|
||||
<ul>
|
||||
@foreach (var error in Model.LoginErrorMessages)
|
||||
@foreach (var error in Model.ErrorMessages)
|
||||
{
|
||||
<li>@error</li>
|
||||
}
|
||||
|
@ -21,52 +21,23 @@
|
|||
</div>
|
||||
}
|
||||
<div class="form-floating mb-3">
|
||||
<input asp-for="LoginInput.Username" class="form-control" autocomplete="username" aria-required="true" placeholder="username" />
|
||||
<label asp-for="LoginInput.Username">Username</label>
|
||||
<span asp-validation-for="LoginInput.Username" class="text-danger"></span>
|
||||
<input asp-for="Input.Username" class="form-control" autocomplete="username" aria-required="true" placeholder="username" />
|
||||
<label asp-for="Input.Username">Username</label>
|
||||
<span asp-validation-for="Input.Username" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input asp-for="LoginInput.Password" class="form-control" type="password" autocomplete="current-password" aria-required="true" placeholder="password" />
|
||||
<label asp-for="LoginInput.Password">Password</label>
|
||||
<span asp-validation-for="LoginInput.Password" class="text-danger"></span>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" asp-page-handler="Login" class="w-100 btn btn-lg btn-secondary">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<form method="post">
|
||||
<h4>Register</h4>
|
||||
<hr />
|
||||
@if (Model.RegisterErrorMessages != null && Model.RegisterErrorMessages.Any())
|
||||
{
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger" role="alert">
|
||||
<ul>
|
||||
@foreach (var error in Model.RegisterErrorMessages)
|
||||
{
|
||||
<li>@error</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<div class="form-floating mb-3">
|
||||
<input asp-for="RegisterInput.Username" class="form-control" autocomplete="username" aria-required="true" placeholder="username" />
|
||||
<label asp-for="RegisterInput.Username">Username</label>
|
||||
<span asp-validation-for="RegisterInput.Username" class="text-danger"></span>
|
||||
<input asp-for="Input.Password" class="form-control" type="password" autocomplete="current-password" aria-required="true" placeholder="password" />
|
||||
<label asp-for="Input.Password">Password</label>
|
||||
<span asp-validation-for="Input.Password" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input asp-for="RegisterInput.Email" class="form-control" autocomplete="email" placeholder="name@example.com" />
|
||||
<label asp-for="RegisterInput.Email">Email</label>
|
||||
<span asp-validation-for="RegisterInput.Email" class="text-danger"></span>
|
||||
<input asp-for="Input.Email" class="form-control" autocomplete="email" placeholder="name@example.com" id="Input_Email" />
|
||||
<label asp-for="Input.Email">Email (Optional for Login)</label>
|
||||
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input asp-for="RegisterInput.Password" class="form-control" type="password" autocomplete="current-password" aria-required="true" placeholder="password" />
|
||||
<label asp-for="RegisterInput.Password">Password</label>
|
||||
<span asp-validation-for="RegisterInput.Password" class="text-danger"></span>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" asp-page-handler="Register" class="w-100 btn btn-lg btn-primary">Login</button>
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-between">
|
||||
<button type="submit" asp-page-handler="Login" class="btn btn-lg btn-secondary flex-grow-1 me-2" id="loginButton">Login</button>
|
||||
<button type="submit" asp-page-handler="Register" class="btn btn-lg btn-primary flex-grow-1 ms-2">Register</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -76,13 +47,19 @@
|
|||
<partial name="_ValidationScriptsPartial" />
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// when login button is clicked, remove validation from email field
|
||||
$("button[asp-page-handler='Login']").click(function() {
|
||||
$("#Input_Email").removeAttr("data-val");
|
||||
$("#Input_Email").removeAttr("data-val-required");
|
||||
// revalidate the form to clear error
|
||||
$("form").validate().element("#Input_Email");
|
||||
return true;
|
||||
// When the login button is clicked
|
||||
$("#loginButton").click(function() {
|
||||
var emailInput = $("#Input_Email");
|
||||
var form = $("#authForm");
|
||||
|
||||
// Remove the data-val-required attribute for client-side validation
|
||||
emailInput.removeAttr("data-val-required");
|
||||
|
||||
// If jQuery Validate has already initialized the form,
|
||||
// re-parse the validation for the email field to reflect the change.
|
||||
if (form.data('validator')) {
|
||||
form.validate().element(emailInput);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,56 +7,32 @@ using System.Threading.Tasks;
|
|||
using CSR.Application.Interfaces;
|
||||
using CSR.Domain.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using System.Security.Claims;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// If you are using ASP.NET Core Identity for sign-in management, you might need:
|
||||
// using Microsoft.AspNetCore.Identity;
|
||||
// using System.Security.Claims;
|
||||
|
||||
public class AuthModel(IUserService userService) : PageModel
|
||||
{
|
||||
private readonly IUserService _userService = userService;
|
||||
|
||||
[BindProperty]
|
||||
public LoginModel LoginInput { get; set; } = new();
|
||||
public InputModel Input { get; set; } = new();
|
||||
|
||||
[BindProperty]
|
||||
public RegisterModel RegisterInput { get; set; } = new();
|
||||
public List<string> ErrorMessages { get; set; } = [];
|
||||
|
||||
public List<string> LoginErrorMessages { get; set; } = [];
|
||||
public List<string> RegisterErrorMessages { get; set; } = [];
|
||||
|
||||
public class LoginModel
|
||||
{
|
||||
[Required(ErrorMessage = "Username is required.")]
|
||||
[Display(Name = "Username")]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class RegisterModel
|
||||
public class InputModel
|
||||
{
|
||||
[Required(ErrorMessage = "Username is required.")]
|
||||
[Display(Name = "Username")]
|
||||
[StringLength(32, ErrorMessage = "Username cannot be longer than 32 characters.")]
|
||||
[RegularExpression(@"^[a-zA-Z0-9_]+$", ErrorMessage = "Username can only contain letters, numbers and underscore.")]
|
||||
[DataType(DataType.Text)]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Email is required for registration.")]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string? Email { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[Required(ErrorMessage = "Password is required.")]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
@ -64,62 +40,32 @@ public class AuthModel(IUserService userService) : PageModel
|
|||
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostRegisterAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
RegisterErrorMessages.Add("Please correct the form errors.");
|
||||
return Page();
|
||||
}
|
||||
|
||||
// Email is required for registration
|
||||
if (string.IsNullOrWhiteSpace(RegisterInput.Email))
|
||||
{
|
||||
RegisterErrorMessages.Add("Email is required for registration.");
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
||||
var result = await _userService.RegisterNewUser(RegisterInput.Username, RegisterInput.Email, RegisterInput.Password);
|
||||
|
||||
if (result.User != null)
|
||||
{
|
||||
// Registration successful
|
||||
await _userService.Login(RegisterInput.Username, RegisterInput.Password);
|
||||
|
||||
await SendCookies(result.User.Username, result.User.Role.Name);
|
||||
|
||||
return RedirectToPageBasedOnRole(result.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Errors != null)
|
||||
{
|
||||
RegisterErrorMessages.AddRange(result.Errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
RegisterErrorMessages.Add("An unknown error occurred during registration.");
|
||||
}
|
||||
return Page();
|
||||
}
|
||||
ErrorMessages.Clear();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostLoginAsync()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(LoginInput.Username) || string.IsNullOrWhiteSpace(LoginInput.Password))
|
||||
// Clear any previous registration errors
|
||||
ModelState.Remove("Input.Email");
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
LoginErrorMessages.Add("Username and Password are required.");
|
||||
foreach (var modelState in ModelState.Values)
|
||||
{
|
||||
foreach (var e in modelState.Errors)
|
||||
{
|
||||
ErrorMessages.Add(e.ErrorMessage);
|
||||
}
|
||||
}
|
||||
return Page();
|
||||
}
|
||||
|
||||
var (user, error) = await _userService.Login(LoginInput.Username, LoginInput.Password);
|
||||
var (user, error) = await _userService.Login(Input.Username, Input.Password);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
LoginErrorMessages.Add(error ?? "Login failed.");
|
||||
ErrorMessages.Add(error ?? "Login failed.");
|
||||
Console.WriteLine(error);
|
||||
return Page();
|
||||
}
|
||||
|
||||
|
@ -128,6 +74,54 @@ public class AuthModel(IUserService userService) : PageModel
|
|||
return RedirectToPageBasedOnRole(user);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostLogoutAsync()
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return RedirectToPage("/Index"); // Redirect to home page after logout
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostRegisterAsync()
|
||||
{
|
||||
// Email is required for registration, so add a validation error if it's missing
|
||||
if (string.IsNullOrWhiteSpace(Input.Email))
|
||||
{
|
||||
ModelState.AddModelError("Input.Email", "Email is required for registration.");
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
foreach (var modelState in ModelState.Values)
|
||||
{
|
||||
foreach (var error in modelState.Errors)
|
||||
{
|
||||
ErrorMessages.Add(error.ErrorMessage);
|
||||
}
|
||||
}
|
||||
return Page();
|
||||
}
|
||||
|
||||
var result = await _userService.RegisterNewUser(Input.Username, Input.Email!, Input.Password);
|
||||
|
||||
if (result.User != null)
|
||||
{
|
||||
await _userService.Login(Input.Username, Input.Password);
|
||||
await SendCookies(result.User.Username, result.User.Role.Name);
|
||||
return RedirectToPageBasedOnRole(result.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Errors != null)
|
||||
{
|
||||
ErrorMessages.AddRange(result.Errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessages.Add("An unknown error occurred during registration.");
|
||||
}
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendCookies(string username, string role)
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
|
@ -152,7 +146,6 @@ public class AuthModel(IUserService userService) : PageModel
|
|||
{
|
||||
if (user == null || string.IsNullOrWhiteSpace(user.Role.Name))
|
||||
{
|
||||
// Default redirect if role is not defined or user is null
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,32 @@
|
|||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
@if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
if (User.IsInRole("Admin"))
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Auth">Login/Register</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Admin">[Admin Page]</a>
|
||||
</li>
|
||||
}
|
||||
if (User.IsInRole("User") || User.IsInRole("Admin"))
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/User">[User Profile]</a>
|
||||
</li>
|
||||
}
|
||||
<li class="nav-item">
|
||||
<form class="form-inline" asp-page="/Auth" asp-page-handler="Logout" method="post">
|
||||
<button type="submit" class="nav-link btn btn-link text-dark">[Logout]</button>
|
||||
</form>
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Auth">[Login or Register]</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
}
|
||||
},
|
||||
"Database": {
|
||||
"Path": "/home/danial23/Desktop/csr.db"
|
||||
"Path": "/home/danial23/dl/csr.db"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue