Bài viết hôm nay tiếp tục làm việc trên project People# và mình sẽ giới thiệu đến các bạn cách tạo lập các API liên quan đến tài khoản người dùng như đăng nhập (login), đăng ký (register) và cách bảo vệ các API khác qua cơ chế xác thực với JWT token.

Bước 1: Cài đặt thêm các thư viện cần thiết

Mở tập tin project.json trong Project People.Service và thêm 2 thư viện mới như bên dưới:

Bước 2: Tạo Membership Database

Bài viết này mình sử dụng bộ thư viện Microsoft.AspNetCore.Identity, thư viện này tạo sẵn cấu trúc database và các cơ chế xác thực thông tin người dùng, như:

  • Tạo tài khoản
  • Mã hóa mật khẩu
  • Kiểm tra đăng nhập
  • Khôi phục mật khẩu
  • Xác thực email, số điện thoại
  • Cơ chế đăng nhập xác thực 2 lần – two factor authentication (2FA)

Ta bắt đầu bằng việc tạo thêm class ApplicationUser trong thư mục Model kế thừa từ class IdentityUser như sau:

Tìm đến class PeopleDbContext và chỉnh lại parent class từ DbContext thành IdentityDbContext<ApplicationUser>

Mở Command Prompt, trỏ đến thư mục Project.Service và chạy lần lượt các lệnh Migration sau:

auth-2Sau khi chạy các lệnh migration, database của bạn sẽ được cập nhật thêm một số table như sau:

auth-3Bạn có thể tham khảo bài viết trước để biết cách rename lại các table này: Tại đây

Trong file class Startup, thêm vào phương thức ConfigureServices đoạn cấu hình cho ASP.NET Identity như sau:

Nhớ using các namespace cần thiết như:

Bước 3: Tạo API đăng ký tài khoản

Tạo thêm thư mục ViewModel, và thêm class RegisterViewModel có nội dung như sau

Các class trong ViewModel sẽ chịu trách nhiệm Bind dữ liệu từ các request HTTP, vd với RegisterViewModel thì tương ứng với dữ liệu gửi lên ở dạng json như sau:

Tiếp theo ta tạo AccountController, trong thư mục Controllers, Controller này sẽ có một action Register với nhiệm vụ xử lý thông tin được gửi lên và tạo tài khoản dựa vào thông tin đó bằng cách sử dụng một đối tượng thuộc class UserManager đã được cài đặt sẵn:

* Tạm thời mình chưa handle lỗi trong lúc tạo user (như lỗi nhập sai email, lỗi không gửi username, hay lỗi mật khẩu quá ngắn,…)

Bạn có thể kiểm thử bằng cách chạy chương trình và dùng các phần mềm hỗ trợ gửi http request để test thử, ở đây mình sử dụng Postman như sau:

auth-4

Như vậy ta đã tạo được API đăng ký đơn giản, và thêm được 1 user vào hệ thống, ta có thể kiểm tra lại trên database, bạn sẽ có các thông tin như sau

auth-5

Bước 4: Cấu hình “bảo vệ” các API với cơ chế JWT

Chuẩn bị

Bạn cần có một tập tin certificate dùng để chạy thuật toán mã hóa dữ liệu cho việc tạo token JWT (tìm hiểu thêm tại: jwt.io), trên môi trường thử nghiệm bạn có thể tạo certificate bằng bộ công cụ OpenSSL, ở đây mình sử dụng OpenSSL để tạo certificate và export ra một tập tin mã hóa “pkcs12” tên là people.pfx, bạn có thể xem hướng dẫn cách tạo bên dưới cuối bài.

Sau đó bạn vào class Startup và thêm vào các lệnh tạo SecurityKey với tập tin certificate của bạn

Cấu hình

Tạo thư mục Options, sau đó thêm một class mới, tên là JwtIssuerOptions như sau:

Class này chứa các thuộc tính sẽ mang giá trị cấu hình cho việc khởi tạo JWT, ví dụ ở đây ta có thời hạn cho một token mặc định là 5 phút (300 giây)

Vào tập tin appsettings.json, thêm vào các giá trị như sau

Các giá trị nãy sẽ được gán cho đối tượng của class JwtIssuerOptions với thuộc tính tương ứng, ở đây ta có Audience sẽ bằng với đường dẫn truy cập root của ứng dụng ASP.NET Core của bạn, mà bạn thấy lúc chạy thử hoặc trong tập tin launchSettings.json.

Ngoài ra bạn phải sử lại từ localhost thành địa chỉ host của bạn khi deploy lên môi trường Production. Tham khảo bài viết tạo settings theo từng môi trường tại đây

Thêm phần config options vào cuối của ConfigureServices như sau:

Tương tự trong phương thức Configure

Bước 4: Tạo API login

Thêm các field JwtIssuerOptionsSignInManager vào class AccountController

Tạo View Model LoginViewModel trong thư mục ViewModel

Tạo action Login trong AccountController sử dụng SignInManager để xác thực tại khoản đúng với username và password

Sử dụng SignInManager để tạo các Claims cần thiết chứa thông tin cơ bản của user dùng để tạo JWT, sau đó dùng JwtSecurityTokenHandler để tạo một token dạng chuổi và trả kết quả kèm với thời hạn của token

Kiểm tra lại với tại khoản đã tạo lúc trước, bạn sẽ được kết quả như sau:

auth-6Ta có thể dùng công cụ debuger từ trang jwt.to để kiểm tra lại token

auth-7Bước 5: Bảo vệ API của bạn

Đối với các API yêu cầu phải xác thực người dụng trước mới có thê sử dụng được như các API có các lệnh yêu cầu dữ liệu của chính người dùng hiện tại (ví dụ như API về Profile, đổi mật khẩu, lấy danh sách các contact của user,…). Cụ thể, khi sử dụng JWT bạn phải gửi kèm access token lấy được sau khi đăng nhập thành công kèm heo các API đang được “bảo vệ”.

Bài trước chung ta đã tạo api lấy danh sách toàn bộ contact như sau, api này có thể gọi và trả về kết quả bất cự lúc nào.

auth-8Trường hợp này mình muốn chỉ có khi xác thực và có access token mới lấy được dữ liệu từ API này.

Đầu tiên ta chỉ cần thêm attribute [Authorize] lên cả controller hoặc các action cần được bảo vệ như sau:

Như vậy khi ta gọi lại API trên mà không truyền thêm bất kỳ tham số nào thì kết quả sẽ trả về lỗi 401 Unauthorized

Vậy để gọi được API và trả về đúng dữ liệu như mong muốn bạn phải thêm vào header một trường mới với key name và value như sau Authorization: Bearer {{access_token}}, đây là kết quả:

auth-9Vậy là ta tạo thành công cấu hình cho web api sử dụng jwt để xác thực các request từ người dụng qua các API hỗ trợ việc đăng nhập và đăng ký.

Bạn có thể tham khảo Source code ở đây: https://github.com/KhuongNtrd/People

Phụ lục: Hướng dẫn tạo certificate với OpenSSL trên Windows

  • Bước 1. Download Win32OpenSSL 1.0.2 tại http://slproweb.com/products/Win32OpenSSL.html
  • Bước 2. Cài đặt Win32OpenSSL vào thư mục C:\Tools\OpenSSL-Win32
  • Bước 3. Mở Command Prompt trỏ tới thư mục private của bạn, có thể dụng lệnh cd hoặc giữ phím Shift + Right Click -> Open Command Prompt
  • Bước 4. Nhập lệnh:  set OPENSSL_CONF=C:\Tools\OpenSSL-Win32\bin\openssl.cfg
  • Bước 5. Nhập lệnh:  c:\Tools\OpenSSL-Win32\bin\openssl.exe
  • Bước 6. Nhập lệnh: genrsa -out ca.key 4096
  • Bước 7. Nhập lệnh: req -new -x509 -days 1826 -key ca.key -out ca.crt, và nhập các thông tin cho cert.
  • Bước 8. Nhập lệnh: genrsa -out ia.key 4096
  • Bước 9. Nhập lệnh: req -new -key ia.key -out ia.csr, nhập thông tin cho cert. Mục Common Name phải nhập khác với Common Name đã nhập trước đó.
  • Bước 10. Nhập lệnh: rpkcs12 -export -out people.pfx -inkey ca.key -in ca.crt -certfile ia.crt, bạn sẽ được file people.pfx