Authentication and Permission Based Authorization in Asp.Net 5 MVC – Part 02

In  this series, we learned till now

 

In previous article, we saw how to setup asp.net identity, initial configurations, database setup. In this article we will learn how login, register & basic authorization works.

Under Identity root project, create a folder and name it ViewModels. Create “RegisterUserViewModel” class in this folder. The content of RegisterUserViewModel.cs will be. The contents of this file are

using System.ComponentModel.DataAnnotations;

namespace Identity.ViewModels
{
    public class RegisterUserViewModel
    {
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

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

        [Required]
        [Display(Name = "Email")]
        [EmailAddress(ErrorMessage = "Invalid Email Address")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage =
            "The {0} must be at least {2} characters long.", MinimumLength = 4)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage =
            "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }
}

Under Controllers folder create a new class and name AccountController and paste the following code.

using Identity.Models;
using Identity.ViewModels;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace Identity.Controllers
{
    public class AccountController : Controller
    {
        private readonly UserManager<AppUser> _userManager;
        private readonly SignInManager<AppUser> _signInManager;

        public AccountController(UserManager<AppUser> userManager,
                                SignInManager<AppUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }
        [HttpGet]
        public IActionResult Register()
        {
            return View(new RegisterUserViewModel());
        }

        [HttpPost]
        public async Task<IActionResult> Register(RegisterUserViewModel model)
        {
            if (!ModelState.IsValid)
                return View(model);
            var user = new AppUser
            {
                FirstName = model.FirstName,
                LastName = model.LastName,
                UserName = model.Email,
                Email = model.Email
            }; var rs = await _userManager.CreateAsync(user, model.Password);
            
            switch (rs.Succeeded)
            {
                case true:
                    TempData["Message"] = "Registration successful";
                    return RedirectToAction("Index", "Home");
                default:
                    ModelState.AddModelError(string.Empty, rs.ToString());
                    return View(model);
            }
        }
    }
}

Now create Account folder under Views. There create add an empty view and name it Register.cshtml . Paste the following code on it.

@model Identity.ViewModels.RegisterUserViewModel
@{
    ViewData["Title"] = "Register";
}
<h1>Register</h1>
<hr />
<div class="row">
    <div class="col-md-3"></div>
    <div class="col-md-6">
        <form asp-action="Register" method="Post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="FirstName" class="control-label"></label>
                <input asp-for="FirstName" class="form-control" />
                <span asp-validation-for="FirstName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="LastName" class="control-label"></label>
                <input asp-for="LastName" class="form-control" />
                <span asp-validation-for="LastName" class="text-danger"></span>
            </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">
                <label asp-for="ConfirmPassword" class="control-label"></label>
                <input asp-for="ConfirmPassword" class="form-control" />
                <span asp-validation-for="ConfirmPassword" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Register" class="btn btn-primary" />
            </div>
        </form>
    </div>
    <div class="col-md-3"></div>
</div>

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

The registration process should be done with this. Now I will demonstrate how to implement login code. Create a new classs under ViewModels folder and name it LoginUserViewModel.cs and paste the following code.

using System.ComponentModel.DataAnnotations;

namespace Identity.ViewModels
{
    public class LoginUserViewModel
    {
        [Required]
        [Display(Name = "Email")]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }

        [Required]
        [Display(Name = "Password")]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        public bool RememberMe { get; set; }
    }
}

Add the following methods in AccountController.cs.

        [HttpGet]
        public IActionResult Login()
        {
            return View(new LoginUserViewModel());
        }

        [HttpPost]
        public async Task<IActionResult> Login(LoginUserViewModel model)
        {
            if (!ModelState.IsValid)
                return View(model);
            var user = await _userManager.FindByEmailAsync(model.Email);
            if (user == null)
            {
                ModelState.AddModelError(string.Empty, "The email is not correct!");
                return View(model);
            }

            var rs = await _signInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, false);
            switch (rs.Succeeded)
            {
                case true:
                    TempData["Message"] = "Login Success";
                    return RedirectToAction("Index", "Home");
                default:
                    ModelState.AddModelError(string.Empty, rs.ToString());
                    return View(model);
            }
        }

Under Account views, add an empty view and name it Login.cshtml and add the following code

@model Identity.ViewModels.LoginUserViewModel

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

<h1>Login</h1>

<hr />
<div class="row">
    <div class="col-md-3"></div>
    <div class="col-md-6">
        <form asp-action="Login" method="post">
            <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 form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="RememberMe" /> @Html.DisplayNameFor(model => model.RememberMe)
                </label>
            </div>
            <div class="form-group">
                <input type="submit" value="Login" class="btn btn-primary" />
            </div>
        </form>
    </div>
    <div class="col-md-3"></div>
</div>

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

Add following line inside HomeController.cs->Index method

ViewData["Message"] = TempData["Message"];

Add following line in Views->Home->Index.cshtml

<h3>@ViewData["Message"]</h3>

Lets implement logout functionality. Add following method in AccountController.cs

        [HttpPost]
        [Authorize]
        public async Task<IActionResult> LogOut(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            TempData["Message"] = "Logout Success";
            return RedirectToAction("Index", "Home");
        }

Add partial view under Views->Shared folder and name it _LoginPartial.cshtml

@using Microsoft.AspNetCore.Identity
@inject SignInManager<AppUser> SignInManager
@inject UserManager<AppUser> UserManager

<ul class="navbar-nav">
    @if (SignInManager.IsSignedIn(User))
    {
        <li class="nav-item">
            <div class="dropdown">
                <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                    @UserManager.GetUserName(User)
                </button>
                <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
                    @if (User.IsInRole("SuperAdmin"))
                    {
                        <a class="dropdown-item" asp-controller="User" asp-action="Index">Users</a>
                        <a class="dropdown-item" asp-controller="Role" asp-action="Index">Roles</a>
                    }                    
                    <a class="dropdown-item" onclick="event.preventDefault();document.getElementById('logoutForm').submit();" style="cursor: pointer;">Logout</a>
                    <form id="logoutForm" class="form-inline" asp-controller="Account" asp-action="Logout" method="POST">
                    </form>
                </div>
            </div>
        </li>
    }
    else
    {
        <li class="nav-item">
            <a class="nav-link text-dark" id="register" asp-controller="Account" asp-action="Register">Register</a>
        </li>
        <li class="nav-item">
            <a class="nav-link text-dark" id="login" asp-controller="Account" asp-action="Login">Login</a>
        </li>
    }
</ul>

In _Layout.cshtml inside div tag where css class name is container. At the end of this tag add following line.

@await Html.PartialAsync("_LoginPartial")

In this tutorial we learned implementing register, login and logout functionalities. Source code till now can be found here. This is the end of chapter 2. In next chapter we will learn how to seed super admin user with roles and how to assign roles to users, remove roles from users. Read the next part here.

Category:
ASP.Net

Leave a Comment