Giới thiệu

Strapi v5 cung cấp cơ chế mở rộng mạnh mẽ thông qua middlewarecontroller tùy chỉnh. Khi xây dựng các API nội bộ hoặc cho các ứng dụng di động, việc bảo vệ endpoint bằng JSON Web Token (JWT) là một yêu cầu phổ biến. Bài viết này sẽ hướng dẫn chi tiết cách tạo middleware xác thực JWT, tích hợp vào route và xây dựng controller trả về dữ liệu bảo vệ.

Tạo middleware xác thực JWT

1. Cài đặt thư viện jsonwebtoken

Trước tiên, cần cài đặt gói jsonwebtoken để tạo và xác thực token.

npm install jsonwebtoken --save

2. Tạo file middleware

Trong thư mục src/middlewares (hoặc ./src/middlewares tùy cấu trúc dự án), tạo file jwt-auth.js và viết logic kiểm tra token.

const jwt = require('jsonwebtoken');

module.exports = (config, { strapi }) => {
  return async (ctx, next) => {
    const authHeader = ctx.request.headers['authorization'];
    if (!authHeader) {
      ctx.throw(401, 'Missing Authorization header');
    }

    const token = authHeader.split(' ')[1]; // Expected format: Bearer <token>
    if (!token) {
      ctx.throw(401, 'Token not provided');
    }

    try {
      const payload = jwt.verify(token, process.env.JWT_SECRET);
      // Gắn thông tin người dùng vào ctx.state để các controller có thể dùng
      ctx.state.user = payload;
    } catch (err) {
      ctx.throw(401, 'Invalid or expired token');
    }

    await next();
  };
};

Trong đoạn code trên, process.env.JWT_SECRET là khóa bí mật được lưu trong biến môi trường, giúp tăng tính bảo mật.

Đăng ký middleware trong Strapi

Để Strapi nhận biết middleware mới, mở file config/middlewares.js (hoặc ./src/config/middlewares.js) và thêm cấu hình sau:

module.exports = [
  'strapi::errors',
  'strapi::security',
  'strapi::cors',
  'strapi::poweredBy',
  'strapi::logger',
  'strapi::query',
  'strapi::body',
  'strapi::session',
  // Middleware tùy chỉnh
  {
    name: 'global::jwt-auth',
    config: {},
  },
];

Với cấu hình global::jwt-auth, middleware sẽ được áp dụng cho mọi route. Nếu muốn chỉ áp dụng cho một số route, có thể khai báo trong src/api/[api-name]/routes/*.js bằng cách thêm config: { middlewares: ['global::jwt-auth'] }.

Tạo controller tùy chỉnh trả về dữ liệu bảo vệ

Giả sử chúng ta muốn xây dựng một endpoint /api/secure-data chỉ trả về dữ liệu khi token hợp lệ. Tạo controller trong src/api/secure-data/controllers/secure-data.js:

module.exports = {
  async find(ctx) {
    // Dữ liệu người dùng đã được gắn vào ctx.state.user bởi middleware
    const user = ctx.state.user;
    if (!user) {
      ctx.throw(401, 'User not authenticated');
    }

    // Ví dụ trả về thông tin cơ bản của người dùng
    ctx.body = {
      message: 'Access granted',
      userId: user.id,
      email: user.email,
    };
  },
};

Tiếp theo, định nghĩa route trong src/api/secure-data/routes/secure-data.js để liên kết controller và middleware.

module.exports = {
  routes: [
    {
      method: 'GET',
      path: '/secure-data',
      handler: 'secure-data.find',
      config: {
        policies: [],
        middlewares: ['global::jwt-auth'],
      },
    },
  ],
};

Kiểm tra API bằng Postman hoặc curl

Đầu tiên, tạo token bằng một endpoint đăng nhập (hoặc dùng jwt.sign trực tiếp). Sau đó, gửi yêu cầu:

curl -H "Authorization: Bearer <your_jwt_token>" http://localhost:1337/api/secure-data

Nếu token hợp lệ, phản hồi sẽ là:

{
  "message": "Access granted",
  "userId": 12,
  "email": "[email protected]"
}

Kết luận

Việc triển khai middleware JWT trong Strapi v5 cho phép bạn bảo vệ các endpoint một cách linh hoạt, đồng thời giữ cho logic xác thực tách biệt khỏi controller. Khi cần mở rộng, bạn có thể thêm các policy hoặc role‑based access control dựa trên ctx.state.user. Tham khảo khóa học "Xây dựng Back-End Nodejs bằng Strapi CMS" tại đây để nắm vững toàn bộ quy trình phát triển API-first với Strapi.