In Part 13, we move from account creation to the User Sign-In process. Before a customer can access their saved addresses or view their order history, they need a doorway into the system. The Login GET action is that doorway.
Step-by-Step Code Explanation
[HttpGet]Attribute: This decorator specifies that the method handles "Read" requests. When a user clicks your "Login" link or types/Account/Loginin the address bar, this is the code that responds.public IActionResult Login(): This is the action method. In a professional Model-View-Controller (MVC) architecture, the controller's job here is simple: find the right page and show it to the user.return View();: This command searches your project folders forViews/Account/Login.cshtml. It sends that HTML file to the user's browser so they can see the Email and Password text boxes.
[HttpGet]
public IActionResult Login()
{
return View();
}
We continue building our authentication system by creating the LoginViewModel. This class is a "Data Transfer Object" (DTO) specifically designed to handle the credentials entered on the login page. It ensures that our database models stay protected while we validate the user's input.
Step-by-Step Code Explanation
using System.ComponentModel.DataAnnotations;: We import this namespace to use validation attributes. This allows the server to automatically check if the user has left fields empty before even trying to search the database.[Required]: This attribute is applied to both the Username and Password. If a user clicks "Login" without typing anything, ASP.NET Core will automatically stop the process and show an error message.[DataType(DataType.Password)]: This is a UI hint. It tells the browser that this field is a password, so the characters should be hidden (masked with dots) while the user is typing.RememberMe: This boolean property is used to store the state of a "Remember Me" checkbox. It allows the system to decide whether to keep the user logged in even after they close their browser (using a persistent cookie).
using System.ComponentModel.DataAnnotations;
namespace FoodOrderingSystem.Models.ViewModels
{
public class LoginViewModel
{
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
}
We are creating the visual interface for our Login page. This is where the user enters their credentials to access their account. By using Bootstrap 5 and ASP.NET Core Tag Helpers, we ensure the form is both beautiful and functional.
Step-by-Step Code Explanation
Model Binding:
@model LoginViewModelconnects the view to our model. This allows us to use properties likeUsernameandPassworddirectly within our HTML elements.The Form Structure:
asp-action="Login": This tells the form to send the data back to theLoginmethod in theAccountController.method="post": This ensures the sensitive data (passwords) is sent securely in the request body rather than the URL.
Validation Summary:
<div asp-validation-summary="ModelOnly">is a placeholder that will display any general errors (like "Invalid Username or Password") that aren't tied to a specific text box.Tag Helpers:
asp-for: Automatically generates the correctidandnameattributes for the inputs.asp-validation-for: Displays specific error messages (like "Password is required") immediately below the input if validation fails.
Remember Me: The
form-checksection allows users to stay logged in across browser sessions, a standard feature for modern food ordering apps.
@model FoodOrderingSystem.Models.ViewModels.LoginViewModel
@{
ViewData["Title"] = "Login";
}
<div class="container my-5">
<div class="row justify-content-center">
<div class="col-md-4">
<div class="card shadow">
<div class="card-body">
<h3 class="text-center mb-4">Login</h3>
<form asp-action="Login" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="mb-3">
<label asp-for="Username" class="form-label"></label>
<input asp-for="Username" class="form-control" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Password" class="form-label"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="mb-3 form-check">
<input asp-for="RememberMe" class="form-check-input" />
<label asp-for="RememberMe" class="form-check-label"></label>
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
<hr />
<p class="text-center">Don't have an account? <a href="/Account/Register">Register</a></p>
</div>
</div>
</div>
</div>
</div>
We are reaching the most critical part of the authentication journey: the Login POST Action. This is where the magic happens. The code takes the credentials entered in the UI, verifies them against our database, and "remembers" the user using Sessions.
Step-by-Step Code Explanation
[HttpPost]Attribute: This ensures the method only runs when the user clicks the "Login" button. It handles the data sent from the form securely.Database Verification:
We use
_context.Users.FirstOrDefault()to search for a record where both the Username and Password match exactly what the user typed.
Session Management:
If a matching user is found (
user != null), we store their information in HttpContext.Session.SetInt32("UserId", ...): This is vital for tracking which user is placing an order later.SetString("IsAdmin", ...): This allows us to hide or show the "Admin Dashboard" based on the user's role.
The Redirect: Upon a successful login, the user is sent to the Home/Index page to start ordering food.
Error Handling: If the credentials are wrong,
ModelState.AddModelErroradds a message that appears in theasp-validation-summarywe added to our View, and the user stays on the login page to try again.
[HttpPost]
public IActionResult Login(LoginViewModel model)
{
var user = _context.Users.FirstOrDefault(u =>
u.Username == model.Username && u.Password == model.Password);
if (user != null)
{
HttpContext.Session.SetInt32("UserId", user.Id);
HttpContext.Session.SetString("Username", user.Username);
HttpContext.Session.SetString("IsAdmin", user.IsAdmin.ToString());
return RedirectToAction("Index", "Home");
}
ModelState.AddModelError("", "Invalid username or password");
return View(model);
}
We are putting the finishing touches on our user experience by updating the _Layout.cshtml file. This code is what makes your website feel "intelligent"—it recognizes whether a visitor is a guest or a logged-in customer and changes the navigation menu accordingly.
Step-by-Step Code Explanation
The Session Check (
@if):The code checks
Context.Session.GetString("Username"). If this is not null, it means the user has successfully logged in (using the POST action we wrote earlier).
The Dropdown Menu:
If the user is logged in, we replace the "Login" button with a professional Dropdown Menu.
@Context.Session.GetString("Username")is used to display the actual name of the user (e.g., "Hi, John") right in the navbar.
Personalized Links:
Inside the dropdown, we provide links to My Profile and My Orders. This is essential for a food ordering system so customers can track their deliveries.
The Logout Option:
We add a Logout link styled with
text-danger. This makes it stand out and provides a clear way for users to end their session securely.
The "Guest" State (
else):If no session is found, the navigation menu shows the standard Login and Register links, guiding new users to join the platform.
@if (Context.Session.GetString("Username") != null)
{
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
<i class="bi bi-person-circle"></i> @Context.Session.GetString("Username")
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a class="dropdown-item" href="#">
<i class="bi bi-person"></i> My Profile
</a>
</li>
<li>
<a class="dropdown-item" href="#">
<i class="bi bi-bag-check"></i> My Orders
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item text-danger" href="#">
<i class="bi bi-box-arrow-right"></i> Logout
</a>
</li>
</ul>
</li>
}
else
{
<li class="nav-item"><a class="nav-link" href="/Account/Login">Login</a></li>
<li class="nav-item"><a class="nav-link" href="/Account/Register">Register</a></li>
}
We complete the security cycle. Providing a Logout feature is just as important as the Login itself—it ensures that when a user is done ordering their food, they can safely clear their personal data from the browser session, especially on shared computers.
Step-by-Step Code Explanation
The Action Method:
public IActionResult Logout()is the endpoint that the "Logout" link in our navbar points to.HttpContext.Session.Clear(): This is the most critical line. It instantly wipes out every piece of data stored in the current user's session—including theirUserId,Username, andIsAdminstatus. Once this runs, the@ifcheck in our Layout page will fail, and the menu will hide the private links.The Redirect: After the session is destroyed,
RedirectToAction("Login")sends the user back to the Login screen. This gives them a clear confirmation that they have been signed out successfully.
public IActionResult Logout()
{
HttpContext.Session.Clear();
return RedirectToAction("Login");
}

Comments
Post a Comment