Chuyển đến nội dung chính

ASP.NET Identity: Thêm Login và Register page - Part 2

Trong bài viết này, mình sẽ hướng dẫn các bạn setup Login, Register và Logout page.

Để dễ dàng tiếp cận, mình sẽ chia ra làm 3 phần:

  • Setup Login, Register Model và View
  • Setup AspNet Identity
  • Implement Login và Register logic

Setup Model và View

Register page

Tạo Register model

public class RegisterModel
{
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public string Email { get; set; }
	[DataType(DataType.Password)]
	public string Password { get; set; }
	[DataType(DataType.Password)]
	public string ConfirmPassword { get; set; }
	public string ReturnUrl { get; set; }
}
Register.cshtml
@model ClaimExample.Models.RegisterModel;

<div class="row">
    <div class="col-md-4">
        <form asp-route-returnUrl="ReturnUrl" method="post">
            <h4>Create a new account.</h4>
            <hr />
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="FirstName"></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"></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"></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"></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"></label>
                <input asp-for="ConfirmPassword" class="form-control" />
                <span asp-validation-for="ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Register</button>
        </form>
    </div>
</div>

Login page

Tương tự các bạn tạo LoginModel

public class LoginModel
{
	public string Email { get; set; }
	[DataType(DataType.Password)]
	public string Password { get; set; }
	public bool RememberMe { get; set; }
}
Login.cshtml
@model ClaimExample.Models.LoginModel;

<div class="row">
    <div class="col-md-4">
        <section>
            <form id="account" method="post">
                <h4>Use a local account to log in.</h4>
                <hr />
                <div asp-validation-summary="All" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="Email"></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"></label>
                    <input asp-for="Password" class="form-control" />
                    <span asp-validation-for="Password" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-primary">Log in</button>
                </div>
            </form>
        </section>
    </div>
</div>

Setup AspNet Identity

ASP.NET Core Identity là một thành phần (built-in) của ASP.NET Core, nó cung cấp cho bạn các tính năng đầy đủ và đa dạng về authentication. Bạn có thể tạo tài khoản, login, logout, update user profile, quản lý role...

Để sử dụng ASPNET Identity, bạn cần cài đặt các thư viện: 

  • Microsoft.AspNetCore.Identity
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.AspNetCore.Identity
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Install-package Microsoft.EntityFrameworkCore.SqlServer
Trong appSettings.json, bạn thêm đoạn kết nối xuống Database
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Initial Catalog=TestDb;Persist Security Info=False;User ID=sa;Password=Nhatkyhoctap@@@123456789;TrustServerCertificate=True;MultipleActiveResultSets=False;Connection Timeout=30;"
  }
}

Identity Model

Namespace Microsoft.AspNetCore.Identity chứa Identity Models bao gồm các class sau:

  1. IdentityRole
  2. IdentityRoleClaim
  3. IdentityUser
  4. IdentityUserClaim
  5. IdentityUserLogin
  6. IdentityUserRole
  7. IdentityUserToken
Ví dụ với IdentityUser, source code như sau:
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
{

	[PersonalData]
	public virtual TKey Id { get; set; }
	public virtual string UserName { get; set; }
	public virtual string NormalizedUserName { get; set; }

	[ProtectedPersonalData]
	public virtual string Email { get; set; }
	public virtual string NormalizedEmail { get; set; }

	[PersonalData]
	public virtual bool EmailConfirmed { get; set; }
	public virtual string PasswordHash { get; set; }

	public virtual string SecurityStamp { get; set; }
	public virtual string ConcurrencyStamp { get; set; }

	[ProtectedPersonalData]
	public virtual string PhoneNumber { get; set; }

	[PersonalData]
	public virtual bool PhoneNumberConfirmed { get; set; }

	[PersonalData]
	public virtual bool TwoFactorEnabled { get; set; }

	public virtual DateTimeOffset? LockoutEnd { get; set; }

	public virtual bool LockoutEnabled { get; set; }

	public virtual int AccessFailedCount { get; set; }
}
Bạn có thể override lại bằng cách tạo class ApplicationUser và thêm thuộc tính mới
public class ApplicationUser : IdentityUser
{
	public string FirstName { get; set; }
	public string LastName { get; set; }
}

Khai báo Database Context

IdentityDbContext là một base class được sử dụng cho identity.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole, string>
{
	public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
	{
	}
}

Đăng ký DbContext trong Startup

ASP.NET Core sử dụng framework Dependency Injection. Bạn có thể dễ dàng đăng ký trước khi webapp khởi động trong file Program.cs

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
Trường hợp bạn chứa DbContext khác với Project bạn dự định sử dụng Migration (giả sử Project Name của bạn là Project A, bạn sử dụng đoạn code sau:
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString, option => option.MigrationsAssembly("ProjectA")));

Migration

Mở Package Manager Console
Add-Migration <Migration name>
=> tạo ra tập tin Migration mới trong thư mục Migrations
Migrations folder tên sẽ được tạo trong Project. Trong folder đó chứa 2 file:
  • Configuration.cs: Đây là lớp dùng để cấu hình Migration. Bạn không cần chỉnh sửa file này.
  • Tập tin <timestamp>_InitialCreate.cs: Đây là tập tin Migration đầu tiên của chương trình.
Để update Database schema với file Migration vừa tạo, bạn dùng lệnh
Update-Database
add-migration InitialSchema
update-database

 

Migration Tables Digram
Migration Tables Diagram
Dưới đây là bảng giải thích ý nghĩa của từng table:
Entity Table Name Remarks
IdentityUser AspNetUsers Primary table to store user information
IdentityUserClaim AspNetUserClaims Tables holds the claims associated with the user.
IdentityUserLogin AspNetUserLogins Table holds the information about 3rd party/external logins
IdentityUserToken AspNetUserTokens is for storing tokens received from the external login providers.
IdentityUserRole AspNetUserRoles Table contains the roles assigned to the user
IdentityRole AspNetRoles Tables to store the roles
IdentityRoleClaim AspNetRoleClaims The claims that are assigned to the Role

Đăng ký Identity Services

Chúng ta cần đăng ký Identity Services trong Startup của Application.
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddIdentity<ApplicationUser, IdentityRole>(
        options => {
            options.SignIn.RequireConfirmedAccount = false;
            options.Password.RequiredLength = 4;
            options.Password.RequireDigit = false;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
            //Other options go here
        }
        )
    .AddEntityFrameworkStores<ApplicationDbContext>();

Phương thức AddIdentity đăng ký sử dụng User (ApplicationUser)Roles (IdentityRole). Ngoài ra phương thức này cũng đăng ký các service khác như UserValidator, PasswordValidator, PasswordHasher, UserManager, Cookie-based authentication schemes. SignInManager, ...

Bạn có thể gọi các service đó thông qua Depedency Injection

Authentication Middleware

Authentication Middleware đọc authentication cookies từ request, xây dựng ClaimsPrincipal và cập nhật đối tượng User trong HttpContext. Mọi thứ được cập nhật sau method UseAuthentication()

Chúng ta phải gọi UseAuthentication

  • Sau UseRouting, để thông tin routing có sẵn cho các quyết định xác thực.
  • Trước UseEndpoints & UseAuthorization, để người dùng được xác thực trước khi truy cập các điểm cuối.
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
	name: "default",
	pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

Implement Login và Register logic

Quay lại HomeController, chúng ta thêm đoạn xử lý Login và Register:
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;

public HomeController(ILogger<HomeController> logger, UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
{
	_logger = logger;
	_userManager = userManager;
	_signInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Login(LoginModel model)
{
	if (!ModelState.IsValid)
	{
		return View(model);
	}
	var findUser = await _userManager.FindByEmailAsync(model.Email);
	if (findUser != null)
	{
		var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
		if (result.Succeeded)
		{
			return RedirectToAction("Secret");
		}
		if (result.IsLockedOut)
		{
			return RedirectToAction("Index");
		}
		if (result.IsNotAllowed)
		{
			return RedirectToAction("Index");
		}
		else
		{
			ModelState.AddModelError(string.Empty, "Invalid login attempt.");
			return View(model);
		}
	}
	return View();
}

public async Task<IActionResult> Register()
{
	return View();
}

[HttpPost]
public async Task<IActionResult> Register(RegisterModel model)
{
	if (ModelState.IsValid)
	{
		var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FirstName = model.FirstName, LastName = model.LastName };
		var result = await _userManager.CreateAsync(user, model.Password);
		if (result.Succeeded)
		{
			_logger.LogInformation("User created a new account with password.");

			await _signInManager.SignInAsync(user, isPersistent: false);
			return RedirectToAction("Secret");
		}
		foreach (var error in result.Errors)
		{
			ModelState.AddModelError(string.Empty, error.Description);
		}
	}
	return View();
}
Thêm hàm Signout:
public async Task<IActionResult> LogOut()
{
	await _signInManager.SignOutAsync();
	//Redirect to home page    
	return RedirectToAction("Index");
}

Source code: https://github.com/anbinhtrong/AuthenticationAndAuthorization/releases/tag/claims_declaration_v2.0

Hi vọng qua bài viết này, các bạn sẽ xây dựng nhanh chóng trang Login và Register.

Nhatkyhoctap's blog

Nhận xét

Đăng nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.