Giới thiệu

JSON Web Token (JWT) là chuẩn phổ biến để thực hiện xác thực không trạng thái (stateless authentication) cho các API RESTful. Khi kết hợp với Strapi v5, bạn có thể xây dựng hệ thống đăng nhập, cấp token và bảo vệ các route một cách nhanh chóng mà không cần viết quá nhiều mã.

Tổng quan về JWT và Strapi

JWT gồm ba phần: header, payload và signature. Khi người dùng đăng nhập thành công, Strapi sẽ ký payload (thông tin người dùng) bằng secret key và trả về token. Các request tiếp theo chỉ cần gửi token trong header Authorization: Bearer <token> để Strapi xác thực.

Cấu hình plugin Users & Permissions

Plugin Users & Permissions là nền tảng quản lý người dùng trong Strapi. Để sử dụng JWT, bạn chỉ cần bật tùy chọn Enable JWT authentication trong mục Settings > Users & Permissions Plugin. Sau khi bật, Strapi sẽ tự động cung cấp các service jwt.issuejwt.verify.

Bật chế độ JWT

Truy cập /admin/settings/users-permissions, bật Enable JWT authentication và lưu lại. Bạn có thể tùy chỉnh thời gian sống (expiration) của token trong file config/plugins.js:

module.exports = ({ env }) => ({
  'users-permissions': {
    config: {
      jwt: {
        expiresIn: '7d', // token sẽ hết hạn sau 7 ngày
      },
    },
  },
});

Tạo endpoint đăng nhập tùy chỉnh

Mặc dù Strapi đã có endpoint /auth/local, trong nhiều dự án bạn muốn kiểm soát logic trả về hoặc tích hợp các trường bổ sung. Dưới đây là một controller tùy chỉnh đặt trong src/api/auth/controllers/custom.js:

module.exports = {
  async login(ctx) {
    const { identifier, password } = ctx.request.body;
    const user = await strapi
      .plugin('users-permissions')
      .service('user')
      .findOne({ where: { email: identifier } });

    if (!user) {
      return ctx.badRequest('Invalid credentials');
    }

    const valid = await strapi
      .plugin('users-permissions')
      .service('user')
      .validatePassword(password, user.password);

    if (!valid) {
      return ctx.badRequest('Invalid credentials');
    }

    const jwt = strapi
      .plugin('users-permissions')
      .service('jwt')
      .issue({ id: user.id });

    ctx.send({
      jwt,
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
      },
    });
  },
};

Đừng quên khai báo route trong src/api/auth/routes/custom.js:

module.exports = {
  routes: [
    {
      method: 'POST',
      path: '/login',
      handler: 'custom.login',
      config: {
        policies: [],
        middlewares: [],
      },
    },
  ],
};

Kiểm tra token trong middleware

Để bảo vệ các route, bạn có thể viết một middleware kiểm tra token và gán thông tin người dùng vào ctx.state.user. Middleware này được đặt trong src/middlewares/jwt-auth.js:

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

    const token = authHeader.split(' ')[1];
    try {
      const payload = await strapi
        .plugin('users-permissions')
        .service('jwt')
        .verify(token);
      ctx.state.user = await strapi
        .query('plugin::users-permissions.user')
        .findOne({ where: { id: payload.id } });
    } catch (err) {
      return ctx.unauthorized('Invalid token');
    }

    await next();
  };
};

Sau khi tạo, đăng ký middleware trong config/middlewares.js và gắn vào các route cần bảo vệ:

module.exports = [
  'strapi::errors',
  'strapi::security',
  'strapi::cors',
  'strapi::poweredBy',
  'strapi::logger',
  'strapi::query',
  'strapi::body',
  'strapi::session',
  'strapi::favicon',
  'strapi::public',
  {
    name: 'global::jwt-auth',
    config: {},
  },
];

Quản lý role & permission cho các route bảo vệ

Strapi cho phép gán quyền truy cập dựa trên role. Khi middleware đã xác thực người dùng, bạn chỉ cần cấu hình Permissions trong admin để cho phép hoặc từ chối truy cập tới các API. Ví dụ, để chỉ cho phép role Authenticated truy cập /api/articles, vào Settings > Roles & Permissions và bật quyền find, findOne cho role này.

Kết luận

Với các bước trên, bạn đã có một hệ thống Authentication dựa trên JWT hoàn chỉnh trong Strapi v5: cấu hình plugin, tạo endpoint đăng nhập tùy chỉnh, viết middleware xác thực và quản lý quyền truy cập. Khi muốn nâng cao hơn, bạn có thể tích hợp OAuth2, refresh token hoặc giới hạn tốc độ (rate‑limit) cho các endpoint.

Để nắm vững toàn bộ quy trình và mở rộng kiến thức, Tham khảo khóa học "Xây dựng Back-End Nodejs bằng Strapi CMS" tại đây.