TL;DR

Tutorial của Prabodh Tuladhar trên freeCodeCamp hướng dẫn xây dựng API ghi chú cá nhân bảo mật với Django REST Framework (DRF) và SimpleJWT. Hai khái niệm cốt lõi: JWT authentication stateless giải quyết vấn đề cross-domain và mobile client, và scoping - đảm bảo mỗi user chỉ đọc được dữ liệu của chính mình, dù có cố đoán ID người khác. Kết quả là API đầy đủ CRUD với access token 30 phút, refresh token 1 ngày, bảo mật khỏi ID enumeration attack.

Tutorial: Scoped Note-Taking API với Django REST Framework và SimpleJWT

Session auth không còn đủ

Django mặc định dùng session-based authentication. Cách này hoạt động ổn khi frontend và backend cùng domain. Nhưng khi tách ra - React chạy trên Netlify, Django API trên PythonAnywhere - cookie bị trình duyệt chặn do quy tắc cross-domain. Workaround bằng CORS headers thêm độ phức tạp và dễ vỡ.

Vấn đề thứ hai là hiệu năng: 10.000 user đồng thời = 10.000 lần tra cứu database mỗi request chỉ để xác thực session. Khi ứng dụng scale, đây là bottleneck thật sự. Và mobile app không xử lý cookie như browser - thêm một lớp rắc rối nữa.

JWT giải quyết cả ba: server không lưu session, chỉ xác minh chữ ký cryptographic của token. Token gửi qua HTTP header - hoạt động trên mọi domain, mọi client. Stateless, scalable, universal.

Trước khi bắt đầu

  • Python 3.8+ và pip đã cài
  • Hiểu Django cơ bản: models, views, URLs, migrations
  • Quen với DRF: serializers, viewsets, request/response cycle
  • Postman hoặc curl để test endpoint

Cài đặt trong virtual environment: pip install django djangorestframework djangorestframework-simplejwt

10 bước xây dựng API

Tutorial chia thành 10 bước tuần tự:

  1. Setup dự án: tạo virtual env, cài 3 package, khởi tạo Django project và app notes, đăng ký vào INSTALLED_APPS
  2. Custom User Model: kế thừa AbstractUser, set AUTH_USER_MODEL = 'notes.CustomUser' trong settings - bắt buộc TRƯỚC khi chạy migration đầu tiên
  3. Note Model: định nghĩa model với owner = ForeignKey(CustomUser), migrate, đăng ký Admin
  4. Serializers: UserSerializer với password write_only=True và override create() dùng create_user(); NoteSerializer với owner = ReadOnlyField(source='owner.username')
  5. Cấu hình SimpleJWT: thêm JWTAuthentication vào DEFAULT_AUTHENTICATION_CLASSES, IsAuthenticated vào DEFAULT_PERMISSION_CLASSES, access 30 phút, refresh 1 ngày
  6. Auth Logic: RegisterView kế thừa generics.CreateAPIView, set permission_classes = [AllowAny] để public
  7. Scoped Views: NoteViewSet override get_queryset() filter theo user hiện tại, override perform_create() tự gán owner
  8. URL Config: nối app-level và project-level URLs, thêm endpoint /api/token//api/token/refresh/
  9. Test Postman: đăng ký user, lấy token, tạo note, kiểm tra scoping giữa 2 user
  10. Xử lý token hết hạn: gửi refresh token đến /api/token/refresh/ để lấy access token mới không cần đăng nhập lại

Bí kíp kỹ thuật cần nhớ

Ba pattern bảo mật then chốt trong tutorial này:

404 thay vì 403. Khi user B cố truy cập note của user A bằng cách đoán ID, API trả 404 Not Found thay vì 403 Forbidden. Lý do: 403 xác nhận "note này tồn tại nhưng bạn không có quyền" - tiết lộ thông tin cho attacker. 404 là bức tường trống - attacker không biết note có tồn tại không. Đây là cách chống ID enumeration attack chuẩn mực trong thiết kế API.

Owner tamper-proof. Serializer đặt owner = ReadOnlyField - user không thể tự set owner qua POST request. ViewSet gọi serializer.save(owner=self.request.user) - server tự gán. Hai lớp phối hợp: không thể giả mạo ownership dù gửi bất kỳ payload nào.

Custom User Model ngay từ đầu. Dùng default User model rồi sau đó muốn chuyển sang login bằng email - không làm được mà không phá migration. AbstractUser cho phép tùy chỉnh bất kỳ lúc nào sau này. Đây là best practice không nên bỏ qua dù dự án nhỏ.

Ai nên áp dụng ngay

Pattern JWT + scoping phù hợp với:

  • App multi-user với dữ liệu riêng tư: ghi chú, task manager, journal, bookmarks - mỗi user chỉ thấy dữ liệu của mình
  • Kiến trúc tách biệt frontend/backend: React/Vue/mobile app gọi Django API qua HTTP - JWT là lựa chọn tự nhiên
  • Hệ thống cần scale: stateless auth không bottleneck ở database session lookup khi concurrent users tăng cao
  • Role-based systems: clinic app với bác sĩ/bệnh nhân/lễ tân, scoping theo role thay vì chỉ theo user

Đi tiếp từ đây

Tutorial xây xong nền vững. Các bước tự nhiên tiếp theo author đề xuất:

  • Thêm search với DRF SearchFilterdjango-filter - hỗ trợ query ?search=meeting
  • Thêm categories/tags qua ForeignKey hoặc ManyToManyField
  • Bật token blacklisting của SimpleJWT để logout thực sự vô hiệu hóa refresh token (mặc định vẫn hợp lệ 24h sau khi user "logout")
  • Deploy lên PythonAnywhere, Railway, hoặc Render với PostgreSQL và HTTPS
  • Build React/Next.js frontend, implement automatic token refresh khi gặp 401

Đọc đầy đủ tutorial tại freeCodeCamp. Tham khảo thêm: Django REST Framework Authentication docsSimpleJWT Getting Started.