ASP.NET Core - Đăng nhập và đăng xuất

Sau đây, NET Core VN xin giới thiệu 2 chức năng đăng nhập và đăng xuất trong ASP.NET Core.

Trong bài này, chúng ta sẽ xây dụng trang đang nhập và đăng xuất trong ASP.NET Core. Với 2 chức năng này, thực sự các bạn có thể mặc định của ASP.NET Core Web Application khi ta tạo dự án và chọn Authentication thì mặc định đã được khởi tạo những chức năng cần thiết về đăng nhập và đăng xuất...

Mình sử dụng namespace bên dưới để thực hiện 2 chức năng trên:

namespace: Microsoft.AspNetCore.Identity
assembly: Microsoft.AspNetCore.Identity, Microsoft.AspNetCore.Identity.Core

Các bạn cũng có thể sử dụng namespace System.Security.Claims để làm.

Sau đây, mình sẽ hướng dẫn xây dựng chực năng hiện đang có trên .NET Core VN mà các bạn đăng xem:

1. Bạn xây dựng thanh menu hoặc liên kết để hiển thị đường dẫn đăng nhập và đăng xuất khi bạn chưa có quyền trên website:

@using Core.Model
@using Microsoft.AspNetCore.Identity

@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
@{
    @if (SignInManager.IsSignedIn(User))
    {
        <li class="nav-item text-nowrap pr-3">
            <a class="nav-link text-white" target="_blank" href="/"><i class="fa fa-arrow-left"></i> Live</a>
        </li>
        @if (User.IsInRole("Admin"))
        {
            <li class="nav-item nav-link text-nowrap text-white">
                <i class="fa fa-user"></i> Chào quản trị <a asp-controller="Account" asp-action="Index" title="Account"> @UserManager.GetUserName(User)</a>
            </li>
        }
        else if (User.IsInRole("Editor"))
        {
            <li class="nav-item nav-link text-nowrap text-white">
                <i class="fa fa-user"></i> Chào biên tập <a asp-controller="Account" asp-action="Index" title="Account"> @UserManager.GetUserName(User)</a>
            </li>
        }
        <li class="nav-item text-nowrap">
            <form asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm" class="">
                <button type="submit" class="btn btn-link text-white"><i class="fa fa-sign-out"></i> Đăng xuất</button>
            </form>
        </li>
    }
    else
    {
        <li class="nav-item text-nowrap left">
<a class="nav-link" asp-controller="Account" asp-action="Login" title="Sign in">
<i class="fa fa-user-circle" aria-hidden="true"></i> Sign in &nbsp;</a></li>
        <li class="nav-item text-nowrap">
<a class="nav-link" asp-controller="Account" asp-action="Register" title="Register">
<i class="fa fa-ban"></i> Register</a></li>
    }
}

2. Mình xây dựng 3 model để thực hiện

public class User: IdentityUser
    {
        [StringLength(255)]
        [Required]
        public string Name { get; set; }

        [StringLength(500)]
        public string NickName { get; set; }

        [NotMapped]
        public string UserPassword { get; set; }

        [StringLength(450)]
        public string Teaser { get; set; }

        [StringLength(1000)]
        public string Description { get; set; }

        public DateTime Birthday { get; set; }

        [DefaultValue(false)]
        public bool IsDeleted { get; set; }

        public DateTime? LatestLogin { get; set; }
    }

Model User kế thừa từ IdentityUser của Microsoft.AspNetCore.Identity để sử dụng các chức năng của nó.

public class LoginViewModel
    {
        [Required(ErrorMessage = "The Email field is required.")]
        [EmailAddress(ErrorMessage = "The Email field is not a valid e-mail address.")]
        [Display(Name = "E-mail")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Mật khẩu")]
        public string Password { get; set; }

        [Display(Name = "Lưu thông tin tài khoản?")]
        public bool RememberMe { get; set; }

        [Display(Name = "Đăng nhập nhanh")]
        public bool LoginFast { get; set; }

        public string ReturnUrl { get; set; }
    }

Model LoginViewModel để lấy thông tin từ form đăng nhập và validation các thuộc tính trong model.

public class RegisterViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "E-mail")]
        public string Email { get; set; }

        [Required]
        [Display(Name = "Tên")]
        public string FullName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 4)]
        [DataType(DataType.Password)]
        [Display(Name = "Mật khẩu")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Xác nhận mật khẩu")]
        [Compare("Password", ErrorMessage = "Xác nhận mật khẩu không chính xác.")]
        public string ConfirmPassword { get; set; }

        public string ReturnUrl { get; set; }
    }

Model RegisterViewModel để lấy thông tin từ form đăng ký và validation các thuộc tính trong model.

3. Chức năng đăng xuất khá đơn giản, vì vậy mình sẽ làm trước:

[HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> LogOff()
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation(4, "User logged out.");
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }

_signInManager được gọi từ SignInManager class được viết theo Dependency Injection.

4. Chức năng đăng ký trong controller

[HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = new User { UserName = model.Email, Email = model.Email, Name = model.FullName };
                var result = await _userManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    _logger.LogInformation(3, "User created a new account with password.");
                    return RedirectToAction(nameof(HomeController.Index), "Home");
                }
                AddErrors(result);
            }

            return View(model);
        }

CreateAsync của UserManager là 1 function sẽ giúp tạo một tài khoản từ trong tin user model và password, nếu tài khoản đạt yêu cầu như email là duy nhất... thì thuộc tính Succeeded sẽ trả ra bằng true, bạn sẽ xử lý tiếp phần tự động đăng nhập với SignInAsync của SignInManager.

5. Chức năng đăng nhập trong controller

[HttpGet]
        [AllowAnonymous]
        public IActionResult Login([FromRoute] string returnUrl = "")
        {
            var model = new LoginViewModel { ReturnUrl = returnUrl };
            return View(model);
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Login(LoginViewModel model, [FromRoute] string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;
            if (ModelState.IsValid)
            {
                var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
                if (result.Succeeded)
                {
                    //update LatestLogin
                    var user = await _userManager.FindByEmailAsync(model.Email);
                    user.LatestLogin = DateTime.Now;
                    await _userManager.UpdateAsync(user);

                    _logger.LogInformation(1, "User logged in.");
                    return RedirectToLocal(returnUrl);
                }
                if (result.RequiresTwoFactor)
                {
                    return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                }
                if (result.IsLockedOut)
                {
                    _logger.LogWarning(2, "User account locked out.");
                    return View("Lockout");
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return View(model);
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

ValidateAntiForgeryToken được sử dụng để tranh được những request giả mạo từ form gửi đi, trong ASP.NET Core, ở View được tính hợp mặc định AntiForgeryToken trong form nen mình không cân khai báo như ASP.NET MVC.

AllowAnonymous cho phép người dùng truy cập vào mà không cần quyền vì trên class của AccountController mình có sử dụng [Authorize(Roles = "Admin, Editor")].

PasswordSignInAsync trong SignInManager là một function dùng đề kiểm tra thông tin đăng nhập từ tài khoản và mật khẩu của người dùng, trong đây thì tài khoản được dùng như email.

FindByEmailAsync trong UserManager tìm được trong tin của User dựa vào email sau khi đã xác nhận tài khoản này đúng.

Chúc các bạn học ASP.NET Core từ A đến Z thành công.

Bài viết liên quan

+61404577839