RivaLMS
Bảo mật

Xác thực

RivaLMS dùng Auth.js (NextAuth v5) với phiên JWT. Tài khoản do nhà trường cấp: người dùng đăng nhập bằng email và mật khẩu do Quản lý đào tạo hoặc Quản trị hệ thống tạo.

Cấu hình NextAuth

Cấu hình nằm trong src/lib/auth.ts.

Cấu hình chính

// src/lib/auth.ts
import NextAuth from "next-auth";
import { PrismaAdapter } from "@auth/prisma-adapter";

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" },
  pages: {
    signIn: "/login",
    error: "/login",
  },
  providers: [
    Google({ ... }),
    GitHub({ ... }),
    Credentials({ ... }),
  ],
  callbacks: {
    async signIn({ user, account }) { ... },
    async jwt({ token, user, trigger, session }) { ... },
    async session({ session, token }) { ... },
  },
});
  • Vai trò và cờ bắt buộc đổi mật khẩu được lưu trong JWT và đọc ra ở session.user.
  • Cứ 5 phút, phiên đọc lại trạng thái tài khoản từ cơ sở dữ liệu, nên tài khoản bị khóa mất phiên trong tối đa 5 phút.
  • src/middleware.ts đọc JWT để chặn các trang theo vai trò (xem trang Vai trò & phân quyền).

Đăng nhập bằng mật khẩu

Người dùng đăng nhập bằng email và mật khẩu; mật khẩu được băm bằng bcrypt (cost 12).

Kiểm tra đăng nhập

async authorize(credentials) {
  const user = await prisma.user.findUnique({
    where: { email: credentials.email },
    include: { role: true },
  });

  // Tài khoản bị khóa nhận cùng lỗi như sai mật khẩu
  if (!user || !user.password || !user.isActive) return null;

  const isValid = await bcrypt.compare(credentials.password, user.password);
  if (!isValid) return null;

  return {
    id: user.id,
    email: user.email,
    name: user.name,
    role: user.role.name,
    mustChangePassword: user.mustChangePassword,
  };
}

Cấp tài khoản và mật khẩu

  • Quản lý đào tạo tạo tài khoản Học viên và Giảng viên; Quản trị hệ thống tạo được tài khoản mọi vai trò.
  • Tài khoản mới nhận một mật khẩu tạm, chỉ hiển thị một lần. Ở lần đăng nhập đầu, người dùng phải đổi mật khẩu tại /change-password rồi mới vào được hệ thống.
  • Khi đặt lại mật khẩu, người quản lý nhận một mật khẩu tạm mới và người dùng lại phải đổi mật khẩu ở lần đăng nhập sau.
  • Mật khẩu mới có ít nhất 10 ký tự.
  • Tự đăng ký tắt mặc định (ALLOW_SELF_REGISTER=false): /register và POST /api/auth/register trả 404.

Nhà cung cấp OAuth

Nút Google và GitHub trên trang đăng nhập chỉ hoạt động khi bạn đặt AUTH_GOOGLE_ID/AUTH_GOOGLE_SECRET hoặc AUTH_GITHUB_ID/AUTH_GITHUB_SECRET. Khai báo URL callback sau với nhà cung cấp:

${AUTH_URL}/api/auth/callback/google
${AUTH_URL}/api/auth/callback/github

Cân nhắc trước khi bật

Người đăng nhập bằng OAuth lần đầu được tự tạo tài khoản Học viên, bỏ qua quy trình cấp tài khoản của nhà trường. Đăng nhập SSO bằng tài khoản Microsoft 365 hoặc Google Workspace của trường đang được lên kế hoạch (FR-AUTH-03).