356 lines
9.1 KiB
Markdown
356 lines
9.1 KiB
Markdown
|
|
# 门户登录基座应用 - 开发计划
|
||
|
|
|
||
|
|
## 项目概述
|
||
|
|
|
||
|
|
建立一个门户登录的基座应用,提供基础的用户认证功能,采用前后端分离架构,最终打包为单个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/)
|