How to redirect view to homepage - ASP.NET Core MVC

Viewed 4614

This is my first ASP.NET Core MVC project and first C# experience too. I am working on creating a web app that mimics ubereats/doordash.

Right now, I am coding the register/login system and incorporating that with a SQL database. The register/create account function is working great but now I need to figure out how to authenticate someone when they are logging in.

So, the way I wrote my algorithm is:

  1. User creates account - database is updated (working great).
  2. User clicks login hyperlink - takes them to login page (also working)
  3. User enters email and password and presses submit (I don't receive any errors here but I don't think I created the form/authenticated correctly).
  4. Controller takes user entered email and password - if the database finds the email, then check if password is correct.
  5. if correct - redirect user to the homepage else refresh and present the login form again.

I need help going through and retrieving items in the database and then verifying if they are correct.

I also need help redirecting the user to the homepage (which is inside of the "Home" folder in views) if the login is successful. C# and asp.net seems very advanced so I'm wondering if there is an easy function that I don't know about that could be useful.

Can someone help me getting the login portion working?

This specific part of the login controller is the issue I think:

// GET: Logins/Create
public IActionResult LoginPortal()
{
    return View();
}

[HttpPost]
public async Task<IActionResult> LoginPortal(int id)
{
        var movie = await _context.Login.FindAsync(id);

        if (movie == null)
        {
            return View();
        }

        return View("Home/Index");
}

Here is what I have so far:

LoginsController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;                             //including necessary directories 
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using EasyEats.Data;
using EasyEats.Models;

namespace EasyEats.Controllers
{
    public class LoginsController : Controller                      //log-in & register controller 
    {
        private readonly EasyEatsContext _context;

        public LoginsController(EasyEatsContext context)
        {
            _context = context;
        }

        // GET: Logins
        public async Task<IActionResult> Index()
        {
            return View(await _context.Login.ToListAsync());
        }

        // GET: Logins/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var login = await _context.Login
                .FirstOrDefaultAsync(m => m.ID == id);
            if (login == null)
            {
                return NotFound();
            }

            return View(login);
        }

        // GET: Logins/Create
        public IActionResult Create()
        {
            return View();
        }

        // POST: Logins/Create
        // To protect from overposting attacks, enable the specific properties you want to bind to, for 
        // more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("ID,FirstName,LastName,Address,Email,PhoneNumber,Password")] Login login)
        {
            if (ModelState.IsValid)
            {
                _context.Add(login);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(login);
        }


        // GET: Logins/Create
        public IActionResult LoginPortal()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> LoginPortal(int id)
        {
            var movie = await _context.Login.FindAsync(id);

            if (movie == null)
            {
                return View();
            }

            return View("Home/Index");
        }

        // POST: Logins/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to, for 
        // more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("ID,FirstName,LastName,Address,Email,PhoneNumber,Password")] Login login)
        {
            if (id != login.ID)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(login);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!LoginExists(login.ID))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(login);
        }

        // GET: Logins/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var login = await _context.Login
                .FirstOrDefaultAsync(m => m.ID == id);
            if (login == null)
            {
                return NotFound();
            }

            return View(login);
        }

        // POST: Logins/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var login = await _context.Login.FindAsync(id);
            _context.Login.Remove(login);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool LoginExists(int id)
        {
            return _context.Login.Any(e => e.ID == id);
        }
    }
}

Login.cs (model)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace EasyEats.Models
{
    public class Login                      //class for customer log-in & registration information 
    {
        public int ID { get; set; }

        [Required]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Required]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Required]
        public string Address { get; set; }

        [Required]
        public string Email { get; set; }

        [Required]
        [Display(Name = "Phone Number")]
        public int PhoneNumber { get; set; }

        [Required]
        public string Password { get; set; }
    }
}

Inside my "Views" folder: I have a Home folder, Logins folder and Shared folder

Index.cshtml (inside "Home" folder of Views)

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

LoginPortal.cshtml (Inside "Logins" folder in Views)

@model EasyEats.Models.Login

@{
    ViewData["Title"] = "Create";
}

<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="LoginPortal">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Email" class="control-label"></label>
                <input asp-for="Email" class="form-control" />
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Password" class="control-label"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Log in" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

_Layout.cshtml (inside shared folder)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - EasyEats</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">EasyEats</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <partial name="_LoginPartial" />
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - EasyEats - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>

_LoginPartial.cshtml (inside shared folder)

<ul class="navbar-nav">
    <li class="nav-item">
        <a class="nav-link text-dark" asp-controller="Logins"
           asp-action="Create">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-controller="Logins"
           asp-action="LoginPortal">Login</a>
    </li>
</ul> 

Here are some pictures: Homepage

Create Account page Login Page

1 Answers

I need help going through and retrieving items in the database and then verifying if they are correct.

You could find the model in the database where its email is equal to the email you posted from the form.Then check the password of the model you find.

I also need help redirecting the user to the homepage (which is inside of the "Home" folder in views) if the login is successful.

You could use return RedirectToAction("Index", "Home");.

Here is a working demo:

Controller:

public IActionResult LoginPortal()
{
    return View();
}

[HttpPost]
public async Task<IActionResult> LoginPortal(Login login)
{
    //for easy testing,i just hardcode the list
    var list = new List<Login>() {
    new Login(){Email="a",Password="123"},
    new Login(){Email="b",Password="111"}
    };
    //you could find it in the database
    //var movie = _context.Login.Where(a => a.Email == login.Email).FirstOrDefault();

    var movie = list.Where(a => a.Email == login.Email).FirstOrDefault();
    if (movie == null)
    {
        return View(login);
    }
    if (movie.Password==login.Password)
    {
        return RedirectToAction("Index", "Home");
    }
    return View();
}

Result: enter image description here

Update:

You could set ModelState error like below:

[HttpPost]
public async Task<IActionResult> LoginPortal(Login login)
{
    //...
    if (movie == null)
    {
        ModelState.AddModelError("Email", "Do not find such email");
        return View(login);
    }
    if (movie.Password==login.Password)
    {
        return RedirectToAction("Index", "Home");
    }
    ModelState.AddModelError(string.Empty, "invalid login attempt");
    return View();
}
Related