- vừa được xem lúc

Áp dụng Cookie Authentication trong ASP .NET Core không dùng Identity

0 0 63

Người đăng: Thịnh Lang

Theo Viblo Asia

Cookie là một tệp văn bản chứa dữ liệu mà các trình duyệt web có thể truy cập, thông thường là những dữ liệu thời gian ngắn. Cookie Authentication là một khái niệm trong đó một số ngữ cảnh đã được xác thực trong trình duyệt máy khách và sử dụng nó để quản lý các phiên người dùng trong ứng dụng. Hiểu đơn giản là cookie sẽ chứa đoạn mã (chìa khóa), đoạn mã sẽ được gửi lên server (ổ khóa) từ trình duyệt rồi sẽ được kiểm tra có hợp lệ hay không (chìa khớp ổ), nếu hợp lệ sẽ cho ban quyền cho người dùng truy cập vào trang (mở cửa ?).

Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết làm sao có thể sử dụng Cookie Authentication trong ASP .NET Core MVC. Let's go !!!

1. Tạo ứng dụng .NET

Mở Visual Studio và tạo một ứng dụng .Net Core đầu tiên, hiện tại mình đang xài phiên bản 3.1.

Sau khi tạo thành công, chúng ta đã có sẵn những setup cơ bản để có thể chạy được trang web đầu tiên.

Hàm ConfigureServices trong Startup.css, chúng ta thêm Authentication service, sau đó gọi hàm AddCookie() để có thể dùng được chứng thực bằng Cookie, nó sẽ thêm Authentication Scheme vào cấu hình cho ứng dụng của chúng ta (Authentication Scheme là cái tên dùng để chỉ cho ứng dụng nên thực hiện việc xác thực ra sao).

Ví dụ cho dễ hiểu bạn vào thư viện, thẻ thư viện dùng để xác thực (Authenticate) bạn là ai, bạn có thể vào thư viện hay không. Nhưng nếu bạn vào phòng gym thì bạn cần phải có thẻ gym. Có thể có rất nhiều cách để xác thực, cho nên mỗi khi cấu hình phương thức xác thực, bạn đều cần nêu và chỉ tên ra Authentication Scheme mà bạn chọn. Trong ví dụ của mình, mình không đặt tên cho nó vì theo mặc định tên sẽ là Cookies.

Còn nữa chúng ta phải cần chỉ ra Authentication Scheme mặc định cho ứng dụng trong việc xác thực sau này, bạn truyền kiểu string vào tham số đầu tiên của hàm AddAuthentication() là tên Authentication Scheme bạn chọn. Ở đây mình truyền 1 constant được cung cấp sẵn có giá trị là Cookies.

Vậy là bạn đã cấu hình xong, bước tiếp theo sẽ thêm nó vào pipeline của ứng dụng. Thứ tự thêm vào trong pipeline rất quan trọng, cho nó hãy đảm bảo đặt Authentication chính giữa UseRouting và UseEnpoints Middlewares để nó biết endpoints nào nên được truy cập, à mà hiển nhiên phải đặt trước UseAuthorization nha, vô được nhà rồi mới vô được phòng chứ hehe ?

Vậy việc cấu hình đã xong, chúng ta có thể thử bằng cách thêm thuộc tính [Authorize] trước HomeController và khởi động lại. Ứng dụng không cho chúng ta truy cập vào vì mình chưa xác thực cho nó và việc này sẽ thực hiện ngày phần tiếp theo ?

2. Đăng nhập, đăng xuất

Khi chưa được xác thực, ứng dụng tự redirect chúng ta về account/login kèm thèm query returnUrl. Bây giờ chúng ta sẽ tạo Model, Controller và View cho nó nhé.


namespace CookieAuthentication.Models
{ public class LoginModel { [Required] [Display(Name = "Username")] public string UserName { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } public bool RememberLogin { get; set; } public string ReturnUrl { get; set; } }
}
namespace CookieAuthentication.Controllers
{ [AllowAnonymous] public class AccountController : Controller { private readonly ILogger<AccountController> _logger; public AccountController(ILogger<AccountController> logger) { _logger = logger; } public IActionResult Login(string ReturnUrl = "") { LoginModel objLoginModel = new LoginModel(); objLoginModel.ReturnUrl = ReturnUrl; return View(objLoginModel); } public IActionResult Privacy() { return View(); } }
} 
@model CookieAuthentication.Models.LoginModel @{ ViewData["Title"] = "Login"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Login</h2> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Login"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> @if (!string.IsNullOrEmpty(ViewBag.Message)) { <span class="text-danger"> @ViewBag.Message </span> } @Html.HiddenFor(x => x.ReturnUrl) <div class="form-group"> <label asp-for="UserName" class="control-label"></label> <input asp-for="UserName" class="form-control" /> <span asp-validation-for="UserName" 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"> <div class="checkbox"> <label> <input asp-for="RememberLogin" /> @Html.DisplayNameFor(model => model.RememberLogin) </label> </div> </div> <div class="form-group"> <input type="submit" value="Login" class="btn btn-primary" /> </div> </form> </div> </div> 

Kết quả chúng ta có được trang sau đây:

Sau khi nhập thông tin và ấn login, bước xử lí tiếp theo sẽ được xử lý qua action Login với method POST truyền thêm LoginModel.

[HttpPost] [AllowAnonymous] public async Task<IActionResult> Login(LoginModel objLoginModel) { if (ModelState.IsValid) { var user = users.Where(x => x.Username == objLoginModel.UserName && x.Password == objLoginModel.Password).FirstOrDefault(); if (user != null) { //A claim is a statement about a subject by an issuer and //represent attributes of the subject that are useful in the context of authentication and authorization operations. var claims = new List<Claim>() { new Claim(ClaimTypes.Name, user.Username), new Claim(ClaimTypes.Role, user.Role), }; //Initialize a new instance of the ClaimsIdentity with the claims and authentication scheme var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); //Initialize a new instance of the ClaimsPrincipal with ClaimsIdentity var principal = new ClaimsPrincipal(identity); //SignInAsync is a Extension method for Sign in a principal for the specified scheme. await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties() { IsPersistent = objLoginModel.RememberLogin }); return LocalRedirect(objLoginModel.ReturnUrl); } else { ViewBag.Message = "Invalid Credential"; return View(user); } } return View(objLoginModel); }

Trong ví dụ này mình sử dụng in-memory cho ngắn gọn để lấy danh sách user, trong thực tế bạn có thể inject database hoặc một số cách khác:

Sau khi xác thực thông tin nhập tồn tại trong danh sách user chúng ta có, mình sẽ tạo ra danh sách các Claim, Claim là một đối tượng có các thuộc tính loại (Type) và giá trị (Value) chứa thông tin về User đó. Sau khi tạo list các Claim, mình sẽ tạo đối tượng ClaimIdentity từ List Claim đó và chuỗi Scheme mà identity này thuộc về, và cuối cùng mình sẽ tạo ra ClaimsPrincipal từ các ClaimIdentity vừa tạo. Nghe có vẻ hơi phức tạp xíu đúng không, để mình giải thích kĩ hơn ?

Nó nghe khá phức tạp nhưng cũng đơn giản như sau:

  1. Tạo Claims dựa trên thông tin xác thực người dùng
  2. Tạo ClaimsIdentity dựa theo các Claims
  3. Tạo ClaimsPrincipal cho Identity này
  4. Truyền ClaimPricipal đến hàm HttpContext.SignIn cùng với AuthenticationScheme, trong ví dụ của mình nó là "Cookies"

Trong ASP .NET Core, Đối tượng đại diện cho User là ClaimsPricipal, một ClaimsPrincipal có thể có nhiều ClaimsIdentity chứa các đối tượng Identity cho Authetication Scheme. Nếu ứng dụng có 1 Scheme thì ClaimsPrincipal sẽ có 1 đối tượng ClaimsIdentity nhưng nếu chúng ta có thêm nhưng Scheme khác như xác thực bằng Google (phần này mình sẽ trình bày trong phần tiếp theo) thì sẽ chứa thêm nữa.

Khi xác thực thành công, ứng dụng sẽ redirect chúng ta về trang mà chúng ta đặt default cho ReturnUrl trong LoginModel:

Vậy là chúng ta được phép truy cập vào ứng dụng rồi ? Để đăng xuất thì chỉ cần gọi hàm SignOutAsync(), ASP .NET sẽ lo những phần khác cho chúng ta:

public async Task < IActionResult > LogOut() { //SignOutAsync is Extension method for SignOut await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); //Redirect to home page return LocalRedirect("/"); } 

Đây là giá trị Cookie được lưu trữ trên trình duyệt, khi chúng ta logout ra khỏi ứng dụng Cookie cũng sẽ tự động bị xóa ra khỏi trình duyệt

Ngoài ra mình muốn show cho các bạn xem thêm về những thông tin Cookie này đang giữ cho chúng ta, mình sẽ để nó trang Home để có bạn có thấy giá trị được trữ trong Cookie

Và đây là kết quả, các bạn có thể đây là những giá trị chúng ta thêm vào Claims ở phần trên, bạn cũng có thể thêm bất cứ thông tin nào nếu muốn ?

Vậy phần này mình đã hướng dẫn khá chi tiết về cách xác thực bằng Cookie bằng thông tin người dùng được nhập, phần tiếp theo mình sẽ hướng dẫn cách đăng nhập bằng Google và cách kết hợp cả 2 cách vào dự án này nhè. Cảm ơn các bạn đã quan tâm.

Link tham khảo

Bình luận

Bài viết tương tự

- vừa được xem lúc

Session, Cookie và Cache, bạn đã thực sự hiểu chúng??

Session, Cookie, Cache có lẽ đây chính là 3 khái niệm được nhắc đến thường xuyên đối với các lập trình viên. Nào chúng ta cùng tìm hiểu các khái niệm này nhé. Session. Một session hay còn gọi là một phiên làm việc.

0 0 44

- vừa được xem lúc

What Is Session Fixation?

Session Fixation là một kỹ thuật tấn công web. Kẻ tấn công lừa người dùng sử dụng session ID đặc biệt.

0 0 32

- vừa được xem lúc

Session, cookie và ứng dụng vào bài toán login

Trong lập trình web, Session và Cookie là 2 khái niệm vô cùng quan trọng, được ứng dụng ở hầu hết các website. Bài viết này của mình sẽ giúp mọi người hiểu rõ hơn về 2 khái niệm này cũng như cách áp d

0 0 199

- vừa được xem lúc

Local Storage, Session Storage và Cookie

Sự khác nhau và cách sử dụng Local Storage, Session Storage và Cookie. Bạn bị lẫn lộn giữa session storage, local storage và cookies.

0 0 42

- vừa được xem lúc

Hack Facebook ! Why not ? Build fishing Facebook token in 24 hours

Mấy nay rôm rả chuyện cô Hằng nhờ "Hếch Cơ" nào đó có thể làm gì đó ... liên quan tới Facebook để lấy "1 tỏi" tiền tươi nghe có vẻ hấp dẫn Mình nảy ra 1 ý tưởng là mình muốn hếch thử Facebook honey củ

0 0 96

- vừa được xem lúc

Sự khác biệt giữa localStorage, sessionStorage và cookie

Trước hết chúng ta đều biết rằng, cả 3 thằng này đều là để lưu một ít thông tin ở trên trình duyệt để sau này có thể sử dụng dễ dàng hơn. Vậy hôm nay chúng ta tìm hiểu kỹ hơn về 3 khái niệm này và nêu

0 0 39