# 门户登录基座应用 - 开发计划 ## 项目概述 建立一个门户登录的基座应用,提供基础的用户认证功能,采用前后端分离架构,最终打包为单个Docker镜像部署。 --- ## 技术栈 ### 后端 - **框架**: Node.js + Koa (ES Modules) - **ORM**: Prisma v5.22 - **数据库**: SQLite - **认证**: OAuth 2.0 / OIDC (对接 Casdoor v3.18.0) - **JWT**: jsonwebtoken v9 ### 前端 - **框架**: Next.js 16 (App Router) - **React**: v19 - **TypeScript**: v5 - **UI组件库**: Radix UI + Lucide Icons + TailwindCSS v4 - **状态管理**: Zustand v5 - **HTTP客户端**: Axios ### 部署 - **容器化**: Docker (多阶段构建) - **反向代理**: Nginx - **认证服务**: Casdoor v3.18.0 (本地Docker部署) --- ## 项目结构 ``` base-imtim/ ├── backend/ # Koa后端服务 │ ├── prisma/ # Prisma ORM配置 │ │ ├── migrations/ # 数据库迁移历史 │ │ └── schema.prisma # 数据模型定义 │ └── src/ │ ├── config/ # 配置文件 │ ├── controllers/ # 控制器 │ ├── middleware/ # 中间件(认证、日志等) │ ├── routes/ # 路由定义 │ ├── services/ # 业务逻辑 │ └── index.js # 入口文件 ├── frontend/ # Next.js前端应用 │ └── src/ │ ├── app/ # App Router页面 │ │ ├── api/ # API代理路由 │ │ ├── dashboard/ # 仪表板(需认证) │ │ ├── login/ # 登录页 │ │ └── page.tsx # 首页 │ ├── components/ # React组件 │ │ ├── header.tsx # 导航栏 │ │ ├── layout.tsx # 布局组件 │ │ └── protected-route.tsx # 路由守卫 │ └── lib/ │ ├── api.ts # HTTP客户端 │ └── auth-store.ts # 认证状态管理 ├── docker/ # Docker配置 │ ├── Dockerfile # 多阶段构建定义 │ ├── nginx.conf # Nginx反向代理配置 │ └── start.sh # 容器启动脚本 ├── docs/ # 文档 │ └── casdoor-setup.md # Casdoor配置手册 ├── .gitignore # Git忽略规则 ├── docker-compose.yml # 开发环境编排 ├── PLAN.md # 本文件 └── README.md ``` --- ## 功能模块 ### 1. 后端 (Koa) #### 1.1 核心功能 - [x] 项目初始化 (Koa + 中间件) - [x] 数据库配置 (SQLite + Prisma) - [x] 用户模型设计 - `id`: UUID - `username`: 用户名 - `email`: 邮箱 - `avatar`: 头像URL - `casdoorId`: Casdoor用户ID - `createdAt`: 创建时间 - `updatedAt`: 更新时间 #### 1.2 认证模块 - [x] Casdoor OAuth 2.0 集成 - `/api/auth/login` - 生成Casdoor登录链接 - `/api/auth/callback` - 处理Casdoor回调 - `/api/auth/logout` - 登出 - `/api/auth/user` - 获取当前用户信息 - [x] JWT Token管理 - [x] 认证中间件 #### 1.3 API路由 ``` POST /api/auth/login # 获取登录URL GET /api/auth/callback # OAuth回调 POST /api/auth/logout # 登出 GET /api/auth/user # 获取用户信息 (需认证) GET /api/health # 健康检查 ``` #### 1.4 中间件 - [x] 认证中间件 (验证JWT) - [x] 错误处理中间件 - [x] 日志中间件 - [x] CORS中间件 ### 2. 前端 (Next.js) #### 2.1 页面结构 - [x] 首页 (`/`) - [x] 登录页 (`/login`) - [x] 仪表板 (`/dashboard`) - 登录后可见 - [x] API代理路由 (`/api/*`) #### 2.2 核心组件 - [x] Layout (布局组件) - Header (导航栏 + 用户菜单) - Footer (页脚) - [x] LoginButton (登录按钮) - [x] UserMenu (用户菜单 - Radix Dropdown) - [x] ProtectedRoute (受保护路由) #### 2.3 功能实现 - [x] 与后端API对接 (Axios) - [x] 认证状态管理 (Zustand + localStorage) - [x] 路由守卫 (未登录跳转) - [x] 响应式设计 (TailwindCSS v4) - [x] OAuth回调Token处理 --- ## 开发步骤 ### Phase 1: 项目初始化 ✅ #### 1.1 后端初始化 ```bash cd backend npm init -y npm install koa koa-router koa-bodyparser koa-cors npm install @prisma/client prisma npm install jsonwebtoken axios dotenv ``` 初始化Prisma: ```bash npx prisma init ``` #### 1.2 前端初始化 ```bash npx create-next-app@latest frontend --typescript --tailwind --app --src-dir cd frontend npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu npm install @radix-ui/react-avatar @radix-ui/react-separator npm install axios zustand lucide-react ``` ### Phase 2: 数据库与认证 ✅ #### 2.1 数据库模型 `backend/prisma/schema.prisma`: ```prisma datasource db { provider = "sqlite" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id String @id @default(uuid()) username String @unique email String? @unique avatar String? casdoorId String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } ``` 运行迁移: ```bash npx prisma migrate dev npx prisma generate ``` #### 2.2 Casdoor集成 环境变量配置 (`backend/.env`): ```env CASDOOR_SERVER_URL=http://localhost:8000 CASDOOR_CLIENT_ID=your-client-id CASDOOR_CLIENT_SECRET=your-client-secret CASDOOR_ORG_NAME=imtim CASDOOR_APP_NAME=base-imtim CASDOOR_REDIRECT_URI=http://localhost:3000/api/auth/callback JWT_SECRET=your-jwt-secret-key APP_PORT=3001 ``` ### Phase 3: 后端API开发 ✅ #### 3.1 认证流程实现 ``` 1. 用户访问 /login → 点击登录 2. 前端请求后端获取Casdoor登录URL 3. 用户跳转到Casdoor登录 4. 登录成功后Casdoor回调 /api/auth/callback 5. Next.js API路由重定向到后端处理 6. 后端用code换取token,获取用户信息 7. 创建/更新本地用户记录 8. 生成JWT token 9. 重定向到前端dashboard,携带token 10. 前端存储token到localStorage ``` #### 3.2 核心服务 `backend/src/services/auth.service.js`: - `getLoginUrl()` - 生成Casdoor授权URL - `handleCallback(code, redirectUri)` - 处理OAuth回调 - `verifyToken(token)` - 验证JWT ### Phase 4: 前端开发 ✅ #### 4.1 认证状态管理 `frontend/src/lib/auth-store.ts`: ```typescript import { create } from 'zustand'; interface AuthState { user: User | null; token: string | null; isAuthenticated: boolean; login: (token: string, user: User) => void; logout: () => void; initialize: () => void; } ``` #### 4.2 API代理路由 `frontend/src/app/api/auth/*/route.ts`: - `/api/auth/login` - POST - 获取登录URL - `/api/auth/callback` - GET - OAuth回调重定向 - `/api/auth/user` - GET - 获取用户信息 - `/api/auth/logout` - POST - 登出 #### 4.3 受保护路由 `frontend/src/app/dashboard/page.tsx`: - 使用 Suspense 包裹 useSearchParams - Token从URL参数传递到API请求 - 成功后存储到localStorage ### Phase 5: Docker化部署 ✅ #### 5.1 Dockerfile (多阶段构建) ```dockerfile # 阶段1: 构建前端 FROM node:20-alpine AS frontend-builder WORKDIR /app/frontend COPY frontend/package*.json ./ RUN npm ci COPY frontend/ ./ RUN npm run build # 阶段2: 构建后端 FROM node:20-alpine AS backend-builder WORKDIR /app/backend COPY backend/package*.json ./ RUN npm ci COPY backend/ ./ RUN npx prisma generate # 阶段3: 生产环境 FROM node:20-alpine AS production WORKDIR /app RUN apk add --no-cache nginx # 复制后端和前端构建 COPY --from=backend-builder /app/backend ./backend COPY --from=frontend-builder /app/frontend/.next ./frontend/.next # 安装生产依赖、配置nginx、启动脚本 # ... ``` #### 5.2 Nginx配置 反向代理配置: - `/` → Next.js (3002) - `/api/` → Koa (3001) --- ## 开发状态 | 阶段 | 任务 | 状态 | |------|------|------| | Phase 1 | 项目初始化 | ✅ 已完成 | | Phase 2 | 数据库与认证配置 | ✅ 已完成 | | Phase 3 | 后端API开发 | ✅ 已完成 | | Phase 4 | 前端开发 | ✅ 已完成 | | Phase 5 | Docker化部署 | ✅ 已完成 | | **总计** | | **✅ 基座功能已完成** | --- ## 注意事项 1. **Casdoor版本**: 确保使用v3.18.0,API可能与其他版本不兼容 2. **回调URL**: Casdoor配置的重定向URL必须为 `http://localhost:3000/api/auth/callback` 3. **Casdoor用户信息端点**: v3.x 使用 `/api/get-account` 而非 `/api/userinfo` 4. **网络配置**: Docker容器间通信需要使用服务名而非localhost 5. **数据持久化**: SQLite数据库文件需要挂载volume以防数据丢失 6. **useSearchParams**: 必须包裹在 Suspense 边界内 --- ## 后续扩展 - [ ] 角色权限管理 (RBAC) - [ ] 多租户支持 - [ ] 第三方登录 (GitHub, Google等) - [ ] 用户资料编辑 - [ ] 审计日志 - [ ] API限流 - [ ] 监控与告警 - [ ] 国际化 (i18n) --- ## 参考资源 - [Koa文档](https://koajs.com/) - [Next.js文档](https://nextjs.org/docs) - [Radix UI文档](https://www.radix-ui.com/) - [Casdoor文档](https://casdoor.org/docs/overview) - [Prisma文档](https://www.prisma.io/docs) - [Docker文档](https://docs.docker.com/)