authentication

Toàn tập Authentication trong Backend & Microservices

Bài viết này sẽ chia sẻ chi tiết, chuyên sâu về các phương pháp xác thực (authentication) phổ biến trong backend và kiến trúc microservices, bao gồm:

  • Session–Cookie
  • JWT (JSON Web Token)
  • OAuth & OAuth 2.0
  • Basic Authentication
  • Public/Private Key Authentication (Asymmetric Cryptography)

Mỗi phương pháp sẽ có lý thuyết, ưu & nhược điểm, ứng dụng thực tế, và ví dụ code song song với NestJS & FastAPI để bạn dễ áp dụng.


1. Session–Cookie Authentication

Lý thuyết

  • Session: Dữ liệu phiên lưu trên server để ghi nhớ người dùng đã đăng nhập.
  • Cookie: File nhỏ lưu trên trình duyệt chứa session ID.
  • Server dùng session ID từ cookie để tìm thông tin session và xác thực người dùng.

Ưu điểm

  • Dữ liệu nhạy cảm không rời server.
  • Thu hồi quyền ngay lập tức.
  • Đơn giản để triển khai.

Nhược điểm

  • Stateful, cần lưu session.
  • Khó scale nếu không có session store.
  • Có nguy cơ CSRF.

NestJS Example

// main.ts
import * as session from 'express-session';
import * as cookieParser from 'cookie-parser';

app.use(cookieParser());
app.use(session({
  secret: 'my-secret',
  resave: false,
  saveUninitialized: false,
  cookie: { httpOnly: true, secure: false }
}));

FastAPI Example

from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware

app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="my-secret")

@app.post("/login")
async def login(request: Request):
    request.session["user"] = {"username": "admin"}
    return {"message": "Logged in"}

2. JWT (JSON Web Token)

Lý thuyết

  • Token chứa dữ liệu (payload) + chữ ký số.
  • Server không lưu trạng thái, chỉ cần verify chữ ký.

Ưu điểm

  • Stateless, dễ scale.
  • Tích hợp tốt với microservices.

Nhược điểm

  • Khó thu hồi trước khi hết hạn.
  • Token dài hơn session ID.

NestJS Example

import { sign, verify } from 'jsonwebtoken';

const token = sign({ userId: 1 }, 'secret', { expiresIn: '1h' });
const decoded = verify(token, 'secret');

FastAPI Example

import jwt

token = jwt.encode({"user_id": 1}, "secret", algorithm="HS256")
decoded = jwt.decode(token, "secret", algorithms=["HS256"])

3. OAuth & OAuth 2.0

Lý thuyết

  • OAuth: Cho phép ứng dụng bên thứ ba truy cập tài nguyên thay mặt người dùng.
  • OAuth 2.0: Phiên bản hiện đại, hỗ trợ Access Token và Refresh Token.

Ưu điểm

  • Chuẩn công nghiệp cho social login, API integration.

Nhược điểm

  • Triển khai phức tạp.
  • Cần quản lý refresh token an toàn.

NestJS Example

(Sử dụng Passport.js)

// google.strategy.ts
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
  constructor() {
    super({
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: 'http://localhost:3000/auth/google/callback',
      scope: ['email', 'profile']
    });
  }
}

FastAPI Example

(Sử dụng Authlib)

from authlib.integrations.starlette_client import OAuth

oauth = OAuth()
oauth.register(
    name='google',
    client_id='GOOGLE_CLIENT_ID',
    client_secret='GOOGLE_CLIENT_SECRET',
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid email profile'}
)

4. Basic Authentication

Lý thuyết

  • Gửi username:password mã hóa Base64 trong header Authorization.
  • Ví dụ: Authorization: Basic dXNlcjpwYXNz.

Ưu điểm

  • Đơn giản.
  • Không cần cookie hoặc session.

Nhược điểm

  • Không an toàn nếu không có HTTPS.
  • Mỗi request phải gửi thông tin đăng nhập.

NestJS Example

// middleware.ts
const auth = (req, res, next) => {
  const header = req.headers['authorization'] || '';
  const [type, token] = header.split(' ');
  if (type === 'Basic') {
    const [user, pass] = Buffer.from(token, 'base64').toString().split(':');
    if (user === 'admin' && pass === '123') return next();
  }
  res.status(401).send('Unauthorized');
};

FastAPI Example

from fastapi import Depends, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials

security = HTTPBasic()

@app.get("/secure")
async def secure_route(credentials: HTTPBasicCredentials = Depends(security)):
    if credentials.username != "admin" or credentials.password != "123":
        raise HTTPException(status_code=401)
    return {"message": "OK"}

5. Public/Private Key Authentication (Asymmetric Cryptography)

Tên gọi đúng: Asymmetric Key Authentication hoặc Public Key Infrastructure (PKI)

Lý thuyết

  • Client và server dùng cặp khóa public–private.
  • Private key giữ bí mật, public key chia sẻ để xác thực chữ ký.

Ưu điểm

  • Bảo mật cao.
  • Không cần chia sẻ secret.

Nhược điểm

  • Quản lý khóa phức tạp.
  • Tốn CPU hơn so với symmetric key.

NestJS Example

import { generateKeyPairSync, sign, verify } from 'crypto';

const { publicKey, privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
const data = Buffer.from('hello');
const signature = sign('sha256', data, privateKey);
const isValid = verify('sha256', data, publicKey, signature);

FastAPI Example

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes

private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()

message = b"hello"
signature = private_key.sign(message, padding.PKCS1v15(), hashes.SHA256())
public_key.verify(signature, message, padding.PKCS1v15(), hashes.SHA256())

Kết luận & Lựa chọn phương pháp

  • Web app truyền thống: Session–Cookie.
  • SPA/Mobile/microservices: JWT hoặc OAuth 2.0.
  • Server-to-server nội bộ: Public/Private key hoặc mTLS.
  • API đơn giản: Basic Auth (có HTTPS).

Trong thực tế, các công ty lớn thường kết hợp nhiều phương pháp: Ví dụ: Google dùng OAuth 2.0 + OpenID Connect cho đăng nhập, JWT cho giao tiếp API, và mTLS giữa microservices.