You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2.8 KiB

Registration Page Design

Overview

Add a registration page at /register with username, password, confirm password, and SVG captcha. On success, redirect to /login with a query param. Login page is out of scope.

Stack

  • Nuxt 4.4 + Nuxt UI 4.6 + Tailwind v4
  • Drizzle ORM + SQLite (users table already exists)
  • bcryptjs (already installed), svg-captcha, zod (already installed)

Files

New

File Purpose
app/pages/register.vue Registration page component
server/api/auth/captcha.get.ts Generate SVG captcha, return token + svg
server/api/auth/register.post.ts Validate input, create user
server/utils/auth/captcha.ts Server-side captcha generation/validation
server/utils/auth/validation.ts Zod schemas for registration input

Modified

File Change
app/layouts/default.vue Wire header button to /register

API Endpoints

GET /api/auth/captcha

Generates a captcha, stores token→text in a server-side Map (5-min expiry), returns the SVG and token.

Response: { code: 0, data: { token: "uuid", svg: "<svg>...</svg>" } }

POST /api/auth/register

Request:  { username, password, confirmPassword, captchaToken, captchaText }
Response: { code: 0, data: { id: 1, username: "foo" } }

Steps:

  1. Zod validation (username 3-30, password 8+, passwords match)
  2. Verify captcha: lookup token in Map, compare text case-insensitive, delete on match
  3. Check username uniqueness in DB
  4. bcryptjs hash password (salt rounds 10)
  5. Insert into users table with role="user", status="active"
  6. Return success — no auto-login

Data Flow

  1. Page mounts → GET /api/auth/captcha → render SVG
  2. User submits → client Zod validation → POST /api/auth/register
  3. On success → navigateTo('/login?registered=1')
  4. On error → show toast, keep form state; if captcha fail, auto-refresh captcha

Error Handling

Client-side: UForm + Zod validation for empty fields, length, password match.

Server-side:

Case Message
Zod validation fail "密码至少需要8个字符"
Captcha wrong "验证码错误"
Captcha expired "验证码已过期"
Username taken "用户名已存在"
Server error "注册失败,请稍后重试"

Captcha is consumed (deleted from Map) on match to prevent replay. If registration fails after captcha check, a new captcha is fetched.

Form Fields

  • Username — required, 3-30 characters, unique in DB
  • Password — required, min 8 characters, masked input with toggle
  • Confirm Password — required, must match password
  • Captcha — SVG image + text input, refresh button

Layout

Card-centered form (380px max-width), single column. Header already has the "登录/注册" button. Form shows a "Already have an account? Log in" link at the bottom.