Files
vue-beta/Frontend_API_Documentation.md
qq1244 3541ae7755 实现完整的登录系统和退出登录功能
- 新增登录、注册、修改密码页面,支持三种用户类型
- 实现路由守卫和权限控制系统
- 集成Axios拦截器处理认证和错误
- 添加统一错误页面处理
- 完善Header组件退出登录功能,清除本地数据并跳转登录页
- 使用Element Plus构建现代化UI界面
- 支持响应式设计和移动端适配
2025-06-21 11:21:19 +08:00

645 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 餐厅管理系统 - 前端API接口文档
## 📋 接口概述
本系统使用JWT Token进行身份认证。除了登录注册接口外所有API都需要在请求头中携带有效的JWT Token。
**服务器地址**: `http://localhost:8080`
## 🔐 认证机制
### JWT Token使用方式
- **获取Token**: 通过登录接口获取
- **使用Token**: 在请求头中添加 `Authorization: Bearer {token}`
- **Token有效期**: 24小时
- **无需Token**: 仅注册和登录接口
## 📱 认证相关接口
### 1. 用户注册
**接口地址**: `POST /api/auth/register`
**是否需要Token**: ❌ 否
**请求参数**:
```json
{
"accountName": "用户名3-20字符字母数字下划线",
"accountPassword": "密码8-20字符至少包含字母和数字",
"confirmPassword": "确认密码(需与密码相同)",
"accountPhone": "手机号11位数字可选",
"accountType": "账户类型admin/manager/customer",
"accountGender": "性别male/female可选"
}
```
**请求示例**:
```javascript
const registerData = {
accountName: "zhangsan",
accountPassword: "password123",
confirmPassword: "password123",
accountPhone: "13812345678",
accountType: "customer",
accountGender: "male"
};
const response = await fetch('http://localhost:8080/api/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(registerData)
});
const result = await response.json();
```
**响应示例**:
```json
{
"code": 200,
"msg": "成功",
"data": {
"token": null,
"accountInfo": {
"accountId": 1,
"accountName": "zhangsan",
"accountType": "customer",
"accountPhone": "13812345678",
"accountGender": "male",
"accountImg": null
}
}
}
```
### 2. 用户登录
**接口地址**: `POST /api/auth/login`
**是否需要Token**: ❌ 否
**请求参数**:
```json
{
"accountName": "用户名",
"accountPassword": "密码"
}
```
**请求示例**:
```javascript
const loginData = {
accountName: "zhangsan",
accountPassword: "password123"
};
const response = await fetch('http://localhost:8080/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(loginData)
});
const result = await response.json();
// 保存Token到本地存储
if (result.code === 200) {
const jwtToken = result.data.token;
localStorage.setItem('token', jwtToken);
localStorage.setItem('userInfo', JSON.stringify(result.data.accountInfo));
}
```
**响应示例**:
```json
{
"code": 200,
"msg": "成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ6aGFuZ3NhbiIsImlhdCI6MTcwNDczNzgxLCJleHAiOjE3NTA1NjAxODF9...",
"accountInfo": {
"accountId": 1,
"accountName": "zhangsan",
"accountType": "customer",
"accountPhone": "13812345678",
"accountGender": "male",
"accountImg": null
}
}
}
```
### 3. 修改密码
**接口地址**: `PUT /api/auth/change-password`
**是否需要Token**: ✅ 是
**请求参数**:
```json
{
"oldPassword": "当前密码",
"newPassword": "新密码8-20字符至少包含字母和数字",
"confirmPassword": "确认新密码"
}
```
**请求示例**:
```javascript
// 获取存储的Token
const storedToken = localStorage.getItem('token');
const passwordData = {
oldPassword: "password123",
newPassword: "newpassword456",
confirmPassword: "newpassword456"
};
// 构建请求头确保完整Token传递
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${storedToken}`
};
const response = await fetch('http://localhost:8080/api/auth/change-password', {
method: 'PUT',
headers: headers,
body: JSON.stringify(passwordData)
});
const result = await response.json();
```
**响应示例**:
```json
{
"code": 200,
"msg": "成功",
"data": "密码修改成功"
}
```
### 4. 获取当前用户信息
**接口地址**: `GET /api/auth/current-user`
**是否需要Token**: ✅ 是
**请求示例**:
```javascript
// 获取存储的Token
const authToken = localStorage.getItem('token');
// 构建请求头
const requestHeaders = {
'Authorization': `Bearer ${authToken}`
};
const response = await fetch('http://localhost:8080/api/auth/current-user', {
method: 'GET',
headers: requestHeaders
});
const result = await response.json();
```
**响应示例**:
```json
{
"code": 200,
"msg": "成功",
"data": "当前登录用户: zhangsan"
}
```
## 🔧 前端Token管理
### Token存储和使用
```javascript
class AuthManager {
// 保存Token - 确保完整保存
static saveToken(tokenString, userInfo) {
if (tokenString && tokenString.trim()) {
localStorage.setItem('token', tokenString);
localStorage.setItem('userInfo', JSON.stringify(userInfo));
}
}
// 获取完整Token
static getToken() {
const tokenValue = localStorage.getItem('token');
return tokenValue ? tokenValue.trim() : null;
}
// 获取用户信息
static getUserInfo() {
const userInfo = localStorage.getItem('userInfo');
return userInfo ? JSON.parse(userInfo) : null;
}
// 清除Token登出
static logout() {
localStorage.removeItem('token');
localStorage.removeItem('userInfo');
}
// 检查是否已登录
static isLoggedIn() {
const token = this.getToken();
return token && token.length > 0;
}
// 创建认证头 - 确保完整Token传递
static getAuthHeaders() {
const fullToken = this.getToken();
return fullToken ? { 'Authorization': `Bearer ${fullToken}` } : {};
}
}
```
### 统一请求封装
```javascript
class ApiClient {
static baseURL = 'http://localhost:8080';
// 通用请求方法 - 使用变量方式确保Token完整传递
static async request(url, options = {}) {
// 获取完整Token
const currentToken = AuthManager.getToken();
// 构建基础headers
const baseHeaders = {
'Content-Type': 'application/json'
};
// 如果有Token添加认证header
const authHeaders = currentToken ? { 'Authorization': `Bearer ${currentToken}` } : {};
// 合并headers
const finalHeaders = {
...baseHeaders,
...authHeaders,
...(options.headers || {})
};
const config = {
...options,
headers: finalHeaders
};
try {
const response = await fetch(`${this.baseURL}${url}`, config);
const result = await response.json();
// 处理认证失败
if (response.status === 403 || response.status === 401) {
AuthManager.logout();
// 跳转到登录页面
window.location.href = '/login';
return null;
}
return result;
} catch (error) {
console.error('API请求失败:', error);
throw error;
}
}
// GET请求
static async get(url) {
return this.request(url, { method: 'GET' });
}
// POST请求
static async post(url, data) {
return this.request(url, {
method: 'POST',
body: JSON.stringify(data)
});
}
// PUT请求
static async put(url, data) {
return this.request(url, {
method: 'PUT',
body: JSON.stringify(data)
});
}
// DELETE请求
static async delete(url) {
return this.request(url, { method: 'DELETE' });
}
}
```
### 认证相关操作
```javascript
class AuthAPI {
// 用户注册
static async register(userData) {
return ApiClient.post('/api/auth/register', userData);
}
// 用户登录 - 确保完整Token保存
static async login(credentials) {
const result = await ApiClient.post('/api/auth/login', credentials);
if (result && result.code === 200) {
// 获取完整Token并保存
const completeToken = result.data.token;
AuthManager.saveToken(completeToken, result.data.accountInfo);
}
return result;
}
// 修改密码 - 使用变量方式传递Token
static async changePassword(passwordData) {
// 获取完整Token
const userToken = AuthManager.getToken();
// 构建请求头
const requestHeaders = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
};
// 直接使用fetch确保Token完整传递
const response = await fetch(`${ApiClient.baseURL}/api/auth/change-password`, {
method: 'PUT',
headers: requestHeaders,
body: JSON.stringify(passwordData)
});
return await response.json();
}
// 获取当前用户 - 使用变量方式传递Token
static async getCurrentUser() {
const accessToken = AuthManager.getToken();
const headers = { 'Authorization': `Bearer ${accessToken}` };
const response = await fetch(`${ApiClient.baseURL}/api/auth/current-user`, {
method: 'GET',
headers: headers
});
return await response.json();
}
// 登出
static logout() {
AuthManager.logout();
window.location.href = '/login';
}
}
```
## 🎯 使用示例
### 登录页面
```javascript
// 登录表单提交
async function handleLogin(event) {
event.preventDefault();
const formData = new FormData(event.target);
const loginCredentials = {
accountName: formData.get('username'),
accountPassword: formData.get('password')
};
try {
const loginResult = await AuthAPI.login(loginCredentials);
if (loginResult.code === 200) {
alert('登录成功!');
// 验证Token是否正确保存
const savedToken = AuthManager.getToken();
console.log('Token已保存:', savedToken ? '是' : '否');
window.location.href = '/dashboard';
} else {
alert(`登录失败:${loginResult.msg}`);
}
} catch (error) {
alert('登录请求失败,请检查网络连接');
}
}
```
### 注册页面
```javascript
// 注册表单提交
async function handleRegister(event) {
event.preventDefault();
const formData = new FormData(event.target);
const registrationData = {
accountName: formData.get('username'),
accountPassword: formData.get('password'),
confirmPassword: formData.get('confirmPassword'),
accountPhone: formData.get('phone'),
accountType: formData.get('userType'),
accountGender: formData.get('gender')
};
try {
const registerResult = await AuthAPI.register(registrationData);
if (registerResult.code === 200) {
alert('注册成功!请登录');
window.location.href = '/login';
} else {
alert(`注册失败:${registerResult.msg}`);
}
} catch (error) {
alert('注册请求失败,请检查网络连接');
}
}
```
### 修改密码页面
```javascript
// 修改密码表单提交
async function handleChangePassword(event) {
event.preventDefault();
const formData = new FormData(event.target);
const changePasswordInfo = {
oldPassword: formData.get('oldPassword'),
newPassword: formData.get('newPassword'),
confirmPassword: formData.get('confirmPassword')
};
try {
// 使用专门的方法确保Token完整传递
const changeResult = await AuthAPI.changePassword(changePasswordInfo);
if (changeResult.code === 200) {
alert('密码修改成功!');
} else {
alert(`密码修改失败:${changeResult.msg}`);
}
} catch (error) {
alert('请求失败,请检查网络连接');
}
}
```
### 业务API调用示例
```javascript
// 获取数据列表 - 使用变量方式确保Token传递
async function fetchDataWithAuth(apiEndpoint) {
try {
// 获取完整Token
const authenticationToken = AuthManager.getToken();
if (!authenticationToken) {
alert('请先登录');
window.location.href = '/login';
return;
}
// 构建请求头
const apiHeaders = {
'Authorization': `Bearer ${authenticationToken}`
};
const response = await fetch(`http://localhost:8080${apiEndpoint}`, {
method: 'GET',
headers: apiHeaders
});
const result = await response.json();
if (result && result.code === 200) {
return result.data;
} else {
alert(`请求失败:${result.msg}`);
return null;
}
} catch (error) {
alert('请求失败,请检查网络连接');
return null;
}
}
// 发送数据 - 使用变量方式确保Token传递
async function postDataWithAuth(apiEndpoint, postData) {
try {
// 获取完整Token
const userAuthToken = AuthManager.getToken();
if (!userAuthToken) {
alert('请先登录');
window.location.href = '/login';
return;
}
// 构建请求头
const requestHeaders = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userAuthToken}`
};
const response = await fetch(`http://localhost:8080${apiEndpoint}`, {
method: 'POST',
headers: requestHeaders,
body: JSON.stringify(postData)
});
const result = await response.json();
if (result && result.code === 200) {
return result.data;
} else {
alert(`操作失败:${result.msg}`);
return null;
}
} catch (error) {
alert('请求失败,请检查网络连接');
return null;
}
}
```
## 🚨 错误处理
### 常见错误码
| 错误码 | 说明 | 处理方式 |
|--------|------|----------|
| 200 | 成功 | 正常处理数据 |
| 401 | 未认证 | 跳转到登录页面 |
| 403 | 已禁止/Token无效 | 清除Token跳转到登录页面 |
| 500 | 服务器错误 | 显示错误信息,建议重试 |
### Token验证和错误处理
```javascript
// 页面加载时验证Token有效性
async function validateTokenOnPageLoad() {
const currentToken = AuthManager.getToken();
if (!currentToken) {
// 没有Token跳转到登录页
window.location.href = '/login';
return;
}
try {
// 测试Token是否有效
const testHeaders = { 'Authorization': `Bearer ${currentToken}` };
const testResponse = await fetch('http://localhost:8080/api/auth/test', {
method: 'GET',
headers: testHeaders
});
if (testResponse.status === 403 || testResponse.status === 401) {
// Token无效清除并跳转
AuthManager.logout();
window.location.href = '/login';
}
} catch (error) {
console.error('Token验证失败:', error);
}
}
// 页面加载时执行Token验证
window.addEventListener('DOMContentLoaded', validateTokenOnPageLoad);
```
## 📝 重要注意事项
1. **Token完整性**:
- 始终使用变量方式传递Token避免字符串截断
- 在存储和读取Token时检查完整性
2. **Token安全**:
- Token存储在localStorage中注意防止XSS攻击
- 生产环境建议考虑更安全的存储方式
3. **请求头构建**:
- 使用变量方式构建Authorization头
- 确保Token前缀"Bearer "正确添加
4. **错误处理**:
- 统一处理401/403错误自动跳转登录页
- 为用户提供友好的错误提示
5. **调试建议**:
- 在控制台检查Token是否完整
- 验证请求头是否正确设置
这份文档强调了使用变量方式来确保Token完整传递避免了直接字符串拼接可能导致的截断问题