Tùy chỉnh cấu hình xác thực người dùng trong Django
Vấn đề
- Trong Django đã có sẵn một hệ thống đăng nhập mặc định (dùng tên đăng nhập và mật khẩu).
- Tuy nhiên với các bài toán khác nhau thì không phải lúc nào nó cũng đúng được (Ví dụ như đăng nhập bằng email, hoặc thêm bớt các field trong bảng users,...)
Cách giải quyết
-
Cũng có khá nhiều cách giải quyết. Bạn có thể không dùng ứng dụng django.contrib.auth và django.contrib.sessions, tự xây dựng một hệ thống xác thực riêng cho mình, một middleware để hỗ trợ parse user vào request. (Về cách này mình sẽ có một bài chi tiết về nó sau)
-
Trong bài viết này mình sẽ hướng dẫn bạn chỉnh lại User Model trong django.contrib.auth.models
Các bước thực hiện
#1. Tạo ra User Model
from django.contrib.auth.models import AbstractBaseUser
from django.db import models
class User(AbstractBaseUser):
# Authentication
username = None
email = models.EmailField(max_length=128, unique=True, db_index=True)
# Permission
is_staff = models.BooleanField(default=False)
# User information
name = models.CharField(max_length=128, default='User')
USERNAME_FIELD = "email"
class Meta:
db_table = "users"
Mình sẽ giải thích một tí về nó
-
Trước hết mình tạo ra một class User được thừa kế từ AbstractBaseUser để dùng lại được các phương thức liên quan đến mã hóa mật khẩu, quản lý session, ...
-
Mình không dùng username để đăng nhập nên mình xóa field đó đi bằng cách cho nó bằng None
-
Mình dùng email để đăng nhập nên mình tạo ra một field email với ràng buộc duy nhất (unique).
-
Mình cần tạo ra một tài khoản có thể login vào trang Django admin nên mình tạo ra field is_staff. Nếu nó bằng True thì sẽ cho phép truy cập.
- Tuy nhiên nếu bạn không dùng trang Django admin, bạn có thể bỏ qua nó
-
Mình thêm một vài thông tin người dùng như tên người dùng - field name
-
Để hệ thống biết được là mình sẽ đăng nhập bằng email chứ không phải username mình chỉ định
USERNAME_FIELD
-
Cuối cùng là mình chỉ định tên bảng sẽ là users ở tùy chọn db_table
-- Tuy nhiên mình lại custom hơi quá tay nên user manager mặc định không còn phù hợp nữa. Thế là mình chuyển qua bước 2.
#2. Tạo User Manager
from django.contrib.auth.models import BaseUserManager
class UserManager(BaseUserManager):
def create_user(self, email: str, password: str, **extra_fields):
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email: str, password: str, **extra_fields):
extra_fields.setdefault("is_staff", True)
return self.create_user(email=email, password=password, **extra_fields)
Ở đây mình có 2 hàm
-
create_user: Đây là hàm tạo user bình thường.
- Ban đầu mình mình khởi tạo một thực thể User (self.model) và gán email cùng extra_fields (những field còn lại không bắt buộc phải có)
- Tiếp đến mình dùng hàm set_password để mã hóa và gán mật khẩu đã mã hóa cho user
- Cuối cùng là mình sẽ commit với cơ sở dữ liệu và trả về user đã tạo
-
create_superuser: Đây là hàm tạo user với quyền quản trị
- Ở đây mình chỉ để đơn giản là quản trị viên được phép vô trang Django Admin nên mình set is_staff thành True trước kia tạo user.
- Tại đây bạn cũng có thể gán vài trò (role) và quyền hạn (permission) tùy theo nghiệp vụ dự án của bạn.
Sau khi tạo xong mình gán UserManager vào User Model
class User(AbstractBaseUser):
...
# Config
objects = UserManager()
...
#3. Tạo migrations và migrate database
-
Tạo migrations bằng lệnh
python manage.py makemigrations
-
Migrate bằng lệnh
python manage.py migrate
- Ở đây đôi khi sẽ xuất hiện lỗi conflic migrations và không thể migrate, vì bạn đã migrate model user cũ trước đó. Mình thường giải quyết quyết bằng cách xóa toàn bộ bảng trong database và tiến hành migrate lại.
#4. Đăng ký User Model mới với hệ thống
- Bạn mở file settings.py và thêm một tùy chọn
# Custom User Model AUTH_USER_MODEL = "<tên app>.User"
Kiểm tra kết quả
Giờ có thể vào database để xem cấu trúc bảng và chạy lệnh tạo superuser để kiểm tra kết quả
python manage.py createsuperuser
Tài liệu tham khảo
All rights reserved