Giao diện
TascoLoginForm
Form đăng nhập first-party của framework: chọn ứng dụng, tên đăng nhập, mật khẩu, OTP. Gửi credential thẳng tới BFF, không bao giờ đi qua JavaScript của bên thứ ba.
Component nằm ở @tasco/nuxt-layer-base (không phải @tasco/ui) và được auto-import trong app đã extends layer. Trang /auth/login mặc định chỉ là vỏ mỏng bọc nó.
Dùng khi: dự án muốn giao diện đăng nhập riêng nhưng giữ nguyên luồng xác thực.
Không dùng khi: dùng luôn trang mặc định — không phải viết gì cả.
Dùng
vue
<!-- app/pages/auth/login.vue trong dự án -->
<script setup lang="ts">
definePageMeta({ auth: false, layout: false })
const route = useRoute()
</script>
<template>
<div class="login-page">
<TascoLoginForm
title="ONE AUTO"
subtitle="Hệ thống quản lý đơn hàng"
logo="/logo.svg"
:methods="['google']"
:show-client-select="false"
default-client-code="WP_HRM"
@success="navigateTo(String(route.query.redirect ?? '/'))"
/>
</div>
</template>definePageMeta({ auth: false }) là bắt buộc: thiếu nó thì middleware đẩy người dùng vòng lại chính trang đăng nhập.
Props
| Prop | Kiểu | Mặc định | Ý nghĩa |
|---|---|---|---|
title | string | Đăng nhập | Tiêu đề trên form |
subtitle | string | rỗng | Dòng phụ |
logo | string | rỗng | Đường dẫn ảnh logo |
methods | ('google' | 'telegram')[] | theo public.auth.methods | Phương thức xác thực hiện trên form |
showClientSelect | boolean | theo public.auth.showClientSelect | Dropdown "Chọn ứng dụng" |
defaultClientCode | string | theo public.auth.defaultClientCode | Mã ứng dụng cố định |
Prop nào bỏ trống thì lấy từ runtimeConfig.public.auth — nghĩa là cấu hình bằng biến môi trường cho cả hệ thống, chỉ truyền prop khi một trang cần khác biệt.
Sự kiện
| Sự kiện | Khi nào |
|---|---|
@success | Đăng nhập thành công, session đã được tạo — trang tự điều hướng |
Không bắt @success thì trang mặc định của layer đưa người dùng về redirect trong query string.
Hai phương thức xác thực
| Phương thức | Luồng |
|---|---|
| Google Authentication | Người dùng mở app Authenticator, nhập mã vào ô OTP |
| Telegram | Bấm "Gửi mã" → POST /auth/otp/send → nhận transactionId → form gửi kèm khi đăng nhập; có đếm ngược 60 giây |
Chỉ bật phương thức mà IAM của dự án thực sự hỗ trợ. Endpoint gửi OTP để rỗng (NUXT_AUTH_ENDPOINTS_OTP_SEND=) là tắt hẳn tính năng Telegram.
Dropdown chọn ứng dụng
IAM định danh ứng dụng bằng mã (WP_HRM), không phải uuid. Form gọi GET /auth/clients qua BFF và chỉ hiện client có tên.
Dự án chỉ phục vụ một ứng dụng:
bash
NUXT_PUBLIC_AUTH_SHOW_CLIENT_SELECT=false
NUXT_PUBLIC_AUTH_DEFAULT_CLIENT_CODE=WP_HRMTự dựng form hoàn toàn
ts
const { loginWithPassword } = useAuth()
const { $tascoError } = useNuxtApp()
try {
await loginWithPassword({ clientId: 'WP_HRM', username, password, method: 'google', otp })
await navigateTo('/')
} catch (error) {
$tascoError(error)
}Đừng gọi thẳng $fetch('/auth/login'): loginWithPassword còn cập nhật state người dùng dùng chung.
Lưu ý
- Mật khẩu và OTP chỉ đi từ trình duyệt tới Nitro của chính app qua HTTPS.
- Thông báo lỗi hiện trên form là chuỗi IAM trả về (sai mật khẩu, sai OTP, tài khoản bị khoá) — không tự viết lại thông báo, người quản trị IAM cần nhận ra đúng lỗi.
- Trang đăng nhập nên đặt
layout: falseđể không hiện sidebar của người chưa đăng nhập.
Liên quan
- Form đăng nhập — hướng dẫn đầy đủ.
- Phiên đăng nhập — chuyện xảy ra sau khi form thành công.
- Cấu hình IAM — endpoint và mapping.