702 lines
14 KiB
Markdown
702 lines
14 KiB
Markdown
# 用户管理API文档
|
||
|
||
## 概述
|
||
|
||
本文档描述了LingAdmin用户管理系统的API接口,包括用户注册、登录、认证和管理功能。
|
||
|
||
### 基础信息
|
||
|
||
- **基础URL**: `http://localhost:5000/api`
|
||
- **内容类型**: `application/json`
|
||
- **字符编码**: `UTF-8`
|
||
|
||
---
|
||
|
||
## 认证相关API
|
||
|
||
### 1. 用户注册
|
||
|
||
注册新用户账号。
|
||
|
||
**端点**: `POST /auth/register`
|
||
|
||
**请求体**:
|
||
```json
|
||
{
|
||
"name": "张三",
|
||
"email": "zhangsan@example.com",
|
||
"password": "Password123!",
|
||
"role": "User" // 可选: "Admin", "User", "Editor"
|
||
}
|
||
```
|
||
|
||
**成功响应** (201 Created):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"id": 11,
|
||
"name": "张三",
|
||
"email": "zhangsan@example.com",
|
||
"role": "User",
|
||
"status": "Active",
|
||
"createdAt": "2026-01-28T09:30:00Z",
|
||
"lastLoginAt": null
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应** (400 Bad Request):
|
||
```json
|
||
{
|
||
"code": 400,
|
||
"message": "User with this email already exists",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 用户登录
|
||
|
||
用户登录并获取JWT令牌。
|
||
|
||
**端点**: `POST /auth/login`
|
||
|
||
**请求体**:
|
||
```json
|
||
{
|
||
"email": "admin@example.com",
|
||
"password": "Admin123!"
|
||
}
|
||
```
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"user": {
|
||
"id": 1,
|
||
"name": "Admin User",
|
||
"email": "admin@example.com",
|
||
"role": "Admin",
|
||
"status": "Active",
|
||
"createdAt": "2026-01-28T09:00:00Z",
|
||
"lastLoginAt": "2026-01-28T09:30:00Z"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应** (401 Unauthorized):
|
||
```json
|
||
{
|
||
"code": 401,
|
||
"message": "Invalid email or password",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**注意**:
|
||
- 登录成功后返回的`token`需要保存在客户端(localStorage或sessionStorage)
|
||
- Token有效期为60分钟(可在appsettings.json中配置)
|
||
- 已有测试账号:`admin@example.com` / `Admin123!`
|
||
|
||
---
|
||
|
||
### 3. 获取用户资料
|
||
|
||
获取指定用户的详细信息。
|
||
|
||
**端点**: `GET /auth/profile/{id}`
|
||
|
||
**路径参数**:
|
||
- `id` (integer): 用户ID
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"id": 1,
|
||
"name": "Admin User",
|
||
"email": "admin@example.com",
|
||
"role": "Admin",
|
||
"status": "Active",
|
||
"createdAt": "2026-01-28T09:00:00Z",
|
||
"lastLoginAt": "2026-01-28T09:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 修改密码
|
||
|
||
修改当前用户的密码。
|
||
|
||
**端点**: `POST /auth/change-password/{id}`
|
||
|
||
**路径参数**:
|
||
- `id` (integer): 用户ID
|
||
|
||
**请求体**:
|
||
```json
|
||
{
|
||
"currentPassword": "OldPassword123!",
|
||
"newPassword": "NewPassword123!"
|
||
}
|
||
```
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"message": "Password changed successfully"
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应** (400 Bad Request):
|
||
```json
|
||
{
|
||
"code": 400,
|
||
"message": "Current password is incorrect",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 用户管理API
|
||
|
||
### 5. 获取用户列表
|
||
|
||
获取所有用户列表(管理员功能)。
|
||
|
||
**端点**: `GET /users`
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"name": "Admin User",
|
||
"email": "admin@example.com",
|
||
"role": "Admin",
|
||
"status": "Active",
|
||
"createdAt": "2026-01-28T09:00:00Z",
|
||
"lastLoginAt": "2026-01-28T09:30:00Z"
|
||
},
|
||
{
|
||
"id": 2,
|
||
"name": "测试用户",
|
||
"email": "test@example.com",
|
||
"role": "User",
|
||
"status": "Active",
|
||
"createdAt": "2026-01-28T10:00:00Z",
|
||
"lastLoginAt": null
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 6. 获取单个用户
|
||
|
||
获取指定用户的详细信息。
|
||
|
||
**端点**: `GET /users/{id}`
|
||
|
||
**路径参数**:
|
||
- `id` (integer): 用户ID
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"id": 1,
|
||
"name": "Admin User",
|
||
"email": "admin@example.com",
|
||
"role": "Admin",
|
||
"status": "Active",
|
||
"createdAt": "2026-01-28T09:00:00Z",
|
||
"lastLoginAt": "2026-01-28T09:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 7. 更新用户信息
|
||
|
||
更新用户的基本信息(部分更新)。
|
||
|
||
**端点**: `PUT /users/{id}`
|
||
|
||
**路径参数**:
|
||
- `id` (integer): 用户ID
|
||
|
||
**请求体** (所有字段可选):
|
||
```json
|
||
{
|
||
"name": "新名称",
|
||
"email": "newemail@example.com",
|
||
"role": "Editor",
|
||
"status": "Inactive"
|
||
}
|
||
```
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"id": 1,
|
||
"name": "新名称",
|
||
"email": "newemail@example.com",
|
||
"role": "Editor",
|
||
"status": "Inactive",
|
||
"createdAt": "2026-01-28T09:00:00Z",
|
||
"lastLoginAt": "2026-01-28T09:30:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
**注意**:
|
||
- 只需提供要更新的字段
|
||
- 邮箱更新时会检查是否已被其他用户使用
|
||
|
||
---
|
||
|
||
### 8. 删除用户
|
||
|
||
删除指定用户。
|
||
|
||
**端点**: `DELETE /users/{id}`
|
||
|
||
**路径参数**:
|
||
- `id` (integer): 用户ID
|
||
|
||
**成功响应** (200 OK):
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"message": "User deleted successfully"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 数据模型
|
||
|
||
### User (用户)
|
||
|
||
```typescript
|
||
interface User {
|
||
id: number; // 用户ID
|
||
name: string; // 用户名称
|
||
email: string; // 邮箱地址
|
||
role: string; // 角色: "Admin" | "User" | "Editor"
|
||
status: string; // 状态: "Active" | "Inactive"
|
||
createdAt: string; // 创建时间 (ISO 8601格式)
|
||
lastLoginAt: string | null; // 最后登录时间
|
||
}
|
||
```
|
||
|
||
### ApiResponse (统一响应格式)
|
||
|
||
```typescript
|
||
interface ApiResponse<T> {
|
||
code: number; // 状态码: 200=成功, 400=客户端错误, 401=未授权, 404=未找到, 500=服务器错误
|
||
message: string; // 响应消息
|
||
data: T | null; // 响应数据
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 前端集成示例
|
||
|
||
### React + TypeScript 示例
|
||
|
||
#### 1. 创建API服务
|
||
|
||
```typescript
|
||
// src/services/api.ts
|
||
import axios from 'axios';
|
||
|
||
const API_BASE_URL = 'http://localhost:5000/api';
|
||
|
||
// 创建axios实例
|
||
export const apiClient = axios.create({
|
||
baseURL: API_BASE_URL,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
});
|
||
|
||
// 请求拦截器 - 添加token
|
||
apiClient.interceptors.request.use(
|
||
(config) => {
|
||
const token = localStorage.getItem('authToken');
|
||
if (token) {
|
||
config.headers.Authorization = `Bearer ${token}`;
|
||
}
|
||
return config;
|
||
},
|
||
(error) => Promise.reject(error)
|
||
);
|
||
|
||
// 响应拦截器 - 处理错误
|
||
apiClient.interceptors.response.use(
|
||
(response) => response.data,
|
||
(error) => {
|
||
if (error.response?.status === 401) {
|
||
// 处理未授权 - 清除token并跳转到登录页
|
||
localStorage.removeItem('authToken');
|
||
window.location.href = '/login';
|
||
}
|
||
return Promise.reject(error.response?.data || error);
|
||
}
|
||
);
|
||
```
|
||
|
||
#### 2. 创建认证服务
|
||
|
||
```typescript
|
||
// src/services/auth.service.ts
|
||
import { apiClient } from './api';
|
||
|
||
interface LoginRequest {
|
||
email: string;
|
||
password: string;
|
||
}
|
||
|
||
interface RegisterRequest {
|
||
name: string;
|
||
email: string;
|
||
password: string;
|
||
role?: string;
|
||
}
|
||
|
||
interface LoginResponse {
|
||
token: string;
|
||
user: User;
|
||
}
|
||
|
||
export const authService = {
|
||
// 登录
|
||
async login(credentials: LoginRequest): Promise<LoginResponse> {
|
||
const response = await apiClient.post('/auth/login', credentials);
|
||
if (response.code === 200) {
|
||
localStorage.setItem('authToken', response.data.token);
|
||
localStorage.setItem('currentUser', JSON.stringify(response.data.user));
|
||
}
|
||
return response.data;
|
||
},
|
||
|
||
// 注册
|
||
async register(userData: RegisterRequest): Promise<User> {
|
||
const response = await apiClient.post('/auth/register', userData);
|
||
return response.data;
|
||
},
|
||
|
||
// 登出
|
||
logout() {
|
||
localStorage.removeItem('authToken');
|
||
localStorage.removeItem('currentUser');
|
||
},
|
||
|
||
// 获取当前用户
|
||
getCurrentUser(): User | null {
|
||
const userStr = localStorage.getItem('currentUser');
|
||
return userStr ? JSON.parse(userStr) : null;
|
||
},
|
||
|
||
// 修改密码
|
||
async changePassword(userId: number, passwords: { currentPassword: string; newPassword: string }) {
|
||
const response = await apiClient.post(`/auth/change-password/${userId}`, passwords);
|
||
return response.data;
|
||
},
|
||
};
|
||
```
|
||
|
||
#### 3. 创建用户服务
|
||
|
||
```typescript
|
||
// src/services/user.service.ts
|
||
import { apiClient } from './api';
|
||
|
||
interface UpdateUserRequest {
|
||
name?: string;
|
||
email?: string;
|
||
role?: string;
|
||
status?: string;
|
||
}
|
||
|
||
export const userService = {
|
||
// 获取所有用户
|
||
async getAllUsers(): Promise<User[]> {
|
||
const response = await apiClient.get('/users');
|
||
return response.data;
|
||
},
|
||
|
||
// 获取单个用户
|
||
async getUserById(id: number): Promise<User> {
|
||
const response = await apiClient.get(`/users/${id}`);
|
||
return response.data;
|
||
},
|
||
|
||
// 更新用户
|
||
async updateUser(id: number, userData: UpdateUserRequest): Promise<User> {
|
||
const response = await apiClient.put(`/users/${id}`, userData);
|
||
return response.data;
|
||
},
|
||
|
||
// 删除用户
|
||
async deleteUser(id: number): Promise<void> {
|
||
await apiClient.delete(`/users/${id}`);
|
||
},
|
||
};
|
||
```
|
||
|
||
#### 4. 登录组件示例
|
||
|
||
```typescript
|
||
// src/components/Login.tsx
|
||
import React, { useState } from 'react';
|
||
import { authService } from '../services/auth.service';
|
||
|
||
export const Login: React.FC = () => {
|
||
const [email, setEmail] = useState('');
|
||
const [password, setPassword] = useState('');
|
||
const [error, setError] = useState('');
|
||
const [loading, setLoading] = useState(false);
|
||
|
||
const handleLogin = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
setError('');
|
||
setLoading(true);
|
||
|
||
try {
|
||
const response = await authService.login({ email, password });
|
||
console.log('登录成功:', response.user);
|
||
// 跳转到主页
|
||
window.location.href = '/dashboard';
|
||
} catch (err: any) {
|
||
setError(err.message || '登录失败,请检查邮箱和密码');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<form onSubmit={handleLogin}>
|
||
<div>
|
||
<label>邮箱</label>
|
||
<input
|
||
type="email"
|
||
value={email}
|
||
onChange={(e) => setEmail(e.target.value)}
|
||
required
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label>密码</label>
|
||
<input
|
||
type="password"
|
||
value={password}
|
||
onChange={(e) => setPassword(e.target.value)}
|
||
required
|
||
/>
|
||
</div>
|
||
{error && <div className="error">{error}</div>}
|
||
<button type="submit" disabled={loading}>
|
||
{loading ? '登录中...' : '登录'}
|
||
</button>
|
||
</form>
|
||
);
|
||
};
|
||
```
|
||
|
||
#### 5. 用户列表组件示例
|
||
|
||
```typescript
|
||
// src/components/UserList.tsx
|
||
import React, { useEffect, useState } from 'react';
|
||
import { userService } from '../services/user.service';
|
||
|
||
export const UserList: React.FC = () => {
|
||
const [users, setUsers] = useState<User[]>([]);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
loadUsers();
|
||
}, []);
|
||
|
||
const loadUsers = async () => {
|
||
try {
|
||
const data = await userService.getAllUsers();
|
||
setUsers(data);
|
||
} catch (error) {
|
||
console.error('加载用户失败:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleDelete = async (id: number) => {
|
||
if (confirm('确定要删除此用户吗?')) {
|
||
try {
|
||
await userService.deleteUser(id);
|
||
setUsers(users.filter(u => u.id !== id));
|
||
} catch (error) {
|
||
console.error('删除失败:', error);
|
||
}
|
||
}
|
||
};
|
||
|
||
if (loading) return <div>加载中...</div>;
|
||
|
||
return (
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>姓名</th>
|
||
<th>邮箱</th>
|
||
<th>角色</th>
|
||
<th>状态</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{users.map((user) => (
|
||
<tr key={user.id}>
|
||
<td>{user.id}</td>
|
||
<td>{user.name}</td>
|
||
<td>{user.email}</td>
|
||
<td>{user.role}</td>
|
||
<td>{user.status}</td>
|
||
<td>
|
||
<button onClick={() => handleDelete(user.id)}>删除</button>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
);
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 错误处理
|
||
|
||
### 常见状态码
|
||
|
||
| 状态码 | 说明 | 处理建议 |
|
||
|--------|------|----------|
|
||
| 200 | 成功 | 正常处理响应数据 |
|
||
| 400 | 请求参数错误 | 检查请求参数格式 |
|
||
| 401 | 未授权 | 清除token,跳转到登录页 |
|
||
| 404 | 资源未找到 | 提示用户资源不存在 |
|
||
| 500 | 服务器错误 | 提示用户稍后重试 |
|
||
|
||
### 错误处理示例
|
||
|
||
```typescript
|
||
try {
|
||
const user = await userService.getUserById(id);
|
||
// 处理成功
|
||
} catch (error: any) {
|
||
if (error.code === 404) {
|
||
console.error('用户不存在');
|
||
} else if (error.code === 401) {
|
||
console.error('未授权,请重新登录');
|
||
authService.logout();
|
||
navigate('/login');
|
||
} else {
|
||
console.error('操作失败:', error.message);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 安全注意事项
|
||
|
||
1. **Token存储**: 建议使用`httpOnly` Cookie或`sessionStorage`,避免XSS攻击
|
||
2. **HTTPS**: 生产环境必须使用HTTPS协议
|
||
3. **密码强度**: 前端应验证密码强度(至少8位,包含大小写字母和数字)
|
||
4. **输入验证**: 前端和后端都应进行输入验证
|
||
5. **错误信息**: 避免在错误消息中泄露敏感信息
|
||
|
||
---
|
||
|
||
## 测试账号
|
||
|
||
系统提供以下测试账号用于开发测试:
|
||
|
||
| 邮箱 | 密码 | 角色 | 说明 |
|
||
|------|------|------|------|
|
||
| admin@example.com | Admin123! | Admin | 管理员账号(需要先注册创建) |
|
||
|
||
**注意**: 测试环境中的种子数据密码哈希存在问题,建议使用注册接口创建新用户进行测试。
|
||
|
||
---
|
||
|
||
## 更新日志
|
||
|
||
### v1.0.0 (2026-01-28)
|
||
- ✅ 实现用户注册功能
|
||
- ✅ 实现用户登录与JWT认证
|
||
- ✅ 实现用户信息CRUD操作
|
||
- ✅ 实现密码修改功能
|
||
- ✅ 集成Dapr事件发布
|
||
- ✅ 添加密码安全哈希(PBKDF2)
|
||
|
||
---
|
||
|
||
## 技术支持
|
||
|
||
如有问题,请联系开发团队或查看以下资源:
|
||
|
||
- API测试脚本: `test-auth.ps1`
|
||
- 数据库迁移: `Migrations/`
|
||
- Swagger文档: `http://localhost:5000/swagger`(开发环境)
|
||
|
||
---
|
||
|
||
## 附录
|
||
|
||
### Dapr事件
|
||
|
||
系统会通过Dapr发布以下事件:
|
||
|
||
- `user-created`: 用户注册成功
|
||
- `user-login`: 用户登录成功
|
||
- `user-updated`: 用户信息更新
|
||
- `user-deleted`: 用户被删除
|
||
- `user-password-changed`: 密码修改成功
|
||
|
||
前端可以订阅这些事件进行实时更新。
|