- 概述
- 基础信息
- 响应格式
- 状态码说明
- 通用查询参数
- 认证相关 API
- 验证码相关 API
- 用户管理 API
- 角色管理 API
- 菜单管理 API
- 个人中心 API
- 错误处理
- 使用示例
- 查询参数详细说明
- 数据库初始化
- 权限系统说明
- 开发指南
- 注意事项
基于 Webman 框架的后台管理系统 API,采用 RESTful 风格设计,使用 JWT 进行身份认证。
- 🔐 JWT身份认证
- 🛡️ RBAC权限控制
- 📄 完整的CRUD操作
- 🔍 灵活的查询筛选
- 📊 分页支持
- 🌳 树形结构支持
- 📝 详细的错误信息
- 🚀 高性能设计
curl -X POST http://localhost:8787/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"123456"}'# 获取用户列表
curl -X GET http://localhost:8787/system/user \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# 搜索角色
curl -X GET "http://localhost:8787/system/role?name=管理员" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"# 分页查询用户(第2页,每页20条)
GET /system/user?page=2&limit=20
# 按状态筛选启用的角色
GET /system/role?status=1
# 关键词搜索用户
GET /system/user?keyword=张三
# 获取菜单树
GET /system/menu/tree- Base URL:
http://localhost:8787 - 认证方式: Bearer Token (JWT)
- 数据格式: JSON
- 编码: UTF-8
所有 API 响应都采用统一的 JSON 格式:
{
"code": 200,
"message": "操作成功",
"data": {},
"timestamp": 1640995200
}{
"code": 200,
"message": "success",
"data": {
"data": [...],
"current_page": 1,
"last_page": 5,
"per_page": 15,
"total": 68,
"from": 1,
"to": 15
}
}{
"code": 400,
"message": "错误信息",
"data": null,
"timestamp": 1640995200
}200: 成功201: 创建成功400: 客户端错误(参数错误、验证失败等)401: 未授权(Token无效或过期)403: 禁止访问(权限不足)404: 资源不存在422: 数据验证失败500: 服务器内部错误
所有列表接口都支持以下查询参数:
| 参数 | 类型 | 说明 | 默认值 | 示例 |
|---|---|---|---|---|
page |
integer | 页码 | 1 | page=2 |
limit |
integer | 每页数量 | 15 | limit=20 |
order |
string | 排序规则 | id desc |
order=created_at desc |
POST /auth/login
请求参数:
{
"username": "admin",
"password": "123456",
"captcha_uuid": "f6ca6987-3478-42b2-8cdf-6162ab427ce6",
"captcha_code": "1234",
"require_captcha": true
}字段说明:
username: 用户名或邮箱(必填)password: 密码(必填)captcha_uuid: 验证码UUID(验证码启用时必填)captcha_code: 验证码(验证码启用时必填)require_captcha: 是否强制要求验证码(可选,默认根据系统配置和登录失败次数决定)
响应示例:
{
"code": 200,
"message": "登录成功",
"data": {
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"nickname": "超级管理员",
"status": 1,
"created_at": "2024-01-01 00:00:00"
},
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"expires_in": 7200
}
}POST /auth/logout
请求头:
Authorization: Bearer {token}
响应示例:
{
"code": 200,
"message": "退出成功",
"data": null
}POST /auth/refresh-token
请求头:
Authorization: Bearer {token}
响应示例:
{
"code": 200,
"message": "Token刷新成功",
"data": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"expires_in": 7200
}
}GET /auth/captcha/required
查询参数:
username: 用户名(可选)
响应示例:
{
"code": 200,
"message": "success",
"data": {
"required": true,
"message": "需要验证码"
}
}POST /auth/user/validate-token
请求头:
Authorization: Bearer {token}
GET /auth/user/current
请求头:
Authorization: Bearer {token}
响应示例:
{
"code": 200,
"message": "success",
"data": {
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"nickname": "超级管理员",
"status": 1
},
"roles": [
{
"id": 1,
"name": "超级管理员",
"code": "super_admin"
}
],
"permissions": ["*"],
"menus": [...]
}
}POST /auth/user/change-password
请求头:
Authorization: Bearer {token}
请求参数:
{
"old_password": "123456",
"new_password": "newpassword",
"confirm_password": "newpassword"
}POST /auth/user/forgot-password
请求参数:
{
"email": "user@example.com"
}POST /auth/user/reset-password
请求参数:
{
"token": "reset_token_here",
"password": "newpassword",
"confirm_password": "newpassword"
}GET /auth/user/menus
请求头:
Authorization: Bearer {token}
GET /auth/user/permissions
请求头:
Authorization: Bearer {token}
GET /auth/captcha/image
查询参数:
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
length |
integer | 验证码长度 | 4 |
width |
integer | 验证码宽度 | 120 |
height |
integer | 验证码高度 | 40 |
expire |
integer | 过期时间(秒) | 300 |
case_sensitive |
boolean | 是否区分大小写 | false |
响应示例:
{
"code": 200,
"message": "验证码生成成功",
"data": {
"uuid": "f6ca6987-3478-42b2-8cdf-6162ab427ce6",
"image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...",
"expire": 300
}
}POST /auth/captcha/sms
请求参数:
{
"phone": "13800138000",
"type": "login"
}字段说明:
phone: 手机号(必填)type: 验证码类型(必填,login=登录,register=注册,reset=重置密码)
响应示例:
{
"code": 200,
"message": "短信验证码发送成功",
"data": {
"uuid": "f6ca6987-3478-42b2-8cdf-6162ab427ce6",
"expire": 300,
"phone": "138****8000"
}
}GET /system/user
查询参数:
| 参数 | 类型 | 说明 | 示例 |
|---|---|---|---|
page |
integer | 页码 | page=1 |
limit |
integer | 每页数量 | limit=20 |
order |
string | 排序规则 | order=created_at desc |
username |
string | 用户名筛选(模糊搜索) | username=admin |
email |
string | 邮箱筛选(模糊搜索) | email=admin@example.com |
nickname |
string | 昵称筛选(模糊搜索) | nickname=管理员 |
status |
integer | 状态筛选 | status=1 |
phone |
string | 手机号筛选 | phone=138 |
keyword |
string | 关键词搜索(用户名、邮箱、昵称) | keyword=张三 |
响应示例:
{
"code": 200,
"message": "success",
"data": {
"data": [
{
"id": 1,
"username": "admin",
"email": "admin@example.com",
"nickname": "超级管理员",
"phone": "13800138000",
"status": 1,
"last_login_time": "2024-01-01 12:00:00",
"last_login_ip": "127.0.0.1",
"created_at": "2024-01-01 00:00:00",
"roles": [
{
"id": 1,
"name": "超级管理员",
"code": "super_admin"
}
]
}
],
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 1
}
}GET /system/user/{id}
响应示例:
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"nickname": "超级管理员",
"phone": "13800138000",
"status": 1,
"roles": [...]
}
}POST /system/user
请求参数:
{
"username": "testuser",
"email": "test@example.com",
"password": "123456",
"confirm_password": "123456",
"nickname": "测试用户",
"phone": "13800138000",
"status": 1,
"role_ids": [2, 3]
}字段说明:
username: 用户名(必填,唯一)email: 邮箱(必填,唯一)password: 密码(必填,最少6位)confirm_password: 确认密码(必填,需与password一致)nickname: 昵称(可选)phone: 手机号(可选)status: 状态(可选,0=禁用,1=启用,默认1)role_ids: 角色ID数组(可选)
PUT /system/user/{id}
请求参数:
{
"username": "testuser",
"email": "test@example.com",
"nickname": "测试用户",
"phone": "13800138000",
"status": 1,
"role_ids": [2, 3]
}注意: 更新时不能修改密码,密码需要单独接口修改。
DELETE /system/user/{id}
响应示例:
{
"code": 200,
"message": "用户删除成功",
"data": null
}POST /system/user/batch-delete
请求参数:
{
"ids": [1, 2, 3]
}POST /system/user/{id}/change-password
请求参数:
{
"password": "newpassword"
}POST /system/user/{id}/reset-password
请求参数:
{
"password": "123456"
}POST /system/user/{id}/change-status
请求参数:
{
"status": 1
}POST /system/user/batch-change-status
请求参数:
{
"ids": [1, 2, 3],
"status": 1
}POST /system/user/{id}/assign-roles
请求参数:
{
"role_ids": [1, 2, 3]
}GET /system/user/{id}/roles
GET /system/user/{id}/menus
GET /system/user/search
查询参数:
keyword: 搜索关键词page: 页码limit: 每页数量
GET /system/user/statistics
响应示例:
{
"code": 200,
"message": "success",
"data": {
"total": 100,
"enabled": 95,
"disabled": 5,
"recent": [...]
}
}GET /system/role
查询参数:
| 参数 | 类型 | 说明 | 示例 |
|---|---|---|---|
page |
integer | 页码 | page=1 |
limit |
integer | 每页数量 | limit=20 |
order |
string | 排序规则 | order=sort asc,id desc |
name |
string | 角色名称筛选(模糊搜索) | name=管理员 |
code |
string | 角色编码筛选(模糊搜索) | code=admin |
status |
integer | 状态筛选 | status=1 |
keyword |
string | 关键词搜索(名称或编码) | keyword=管理 |
响应示例:
{
"code": 200,
"message": "success",
"data": {
"data": [
{
"id": 1,
"name": "超级管理员",
"code": "super_admin",
"description": "系统超级管理员",
"sort": 0,
"status": 1,
"created_at": "2024-01-01 00:00:00",
"menus": [
{
"id": 1,
"name": "系统管理",
"code": "system"
}
]
}
],
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 1
}
}GET /system/role/{id}
GET /system/role/enabled
响应示例:
{
"code": 200,
"message": "success",
"data": [
{
"id": 1,
"name": "超级管理员",
"code": "super_admin",
"sort": 0
}
]
}POST /system/role
请求参数:
{
"name": "测试角色",
"code": "test_role",
"description": "测试角色描述",
"sort": 10,
"status": 1,
"menu_ids": [1, 2, 3]
}字段说明:
name: 角色名称(必填)code: 角色编码(必填,唯一)description: 角色描述(可选)sort: 排序值(可选,默认0)status: 状态(可选,0=禁用,1=启用,默认1)menu_ids: 菜单权限ID数组(可选)
PUT /system/role/{id}
请求参数:
{
"name": "测试角色",
"code": "test_role",
"description": "测试角色描述",
"sort": 10,
"status": 1,
"menu_ids": [1, 2, 3]
}DELETE /system/role/{id}
POST /system/role/batch-delete
请求参数:
{
"ids": [1, 2, 3]
}POST /system/role/{id}/change-status
请求参数:
{
"status": 1
}POST /system/role/batch-change-status
请求参数:
{
"ids": [1, 2, 3],
"status": 1
}POST /system/role/{id}/assign-menus
请求参数:
{
"menu_ids": [1, 2, 3, 4, 5]
}GET /system/role/{id}/menus
响应示例:
{
"code": 200,
"message": "success",
"data": [1, 2, 3, 4, 5]
}GET /system/role/search
查询参数:
keyword: 搜索关键词page: 页码limit: 每页数量
POST /system/role/update-sorts
请求参数:
{
"sorts": [
{"id": 1, "sort": 1},
{"id": 2, "sort": 2}
]
}POST /system/role/copy-permissions
请求参数:
{
"from_role_id": 1,
"to_role_id": 2
}GET /system/role/statistics
GET /system/menu
查询参数:
| 参数 | 类型 | 说明 | 示例 |
|---|---|---|---|
page |
integer | 页码 | page=1 |
limit |
integer | 每页数量 | limit=20 |
order |
string | 排序规则 | order=sort asc,id asc |
name |
string | 菜单名称筛选(模糊搜索) | name=用户管理 |
code |
string | 菜单编码筛选(模糊搜索) | code=user |
type |
integer | 菜单类型筛选 | type=2 |
parent_id |
integer | 父级ID筛选 | parent_id=1 |
status |
integer | 状态筛选 | status=1 |
keyword |
string | 关键词搜索(名称、编码、权限) | keyword=管理 |
菜单类型说明:
1: 目录2: 菜单3: 按钮
GET /system/menu/{id}
GET /system/menu/tree
查询参数:
parent_id: 父级ID(默认0)only_enabled: 是否只获取启用的菜单(默认true)
响应示例:
{
"code": 200,
"message": "success",
"data": [
{
"id": 1,
"parent_id": 0,
"name": "系统管理",
"code": "system",
"type": 1,
"path": "/system",
"component": "",
"permission": "system",
"icon": "system",
"sort": 1,
"status": 1,
"children": [
{
"id": 2,
"parent_id": 1,
"name": "用户管理",
"code": "user",
"type": 2,
"path": "/system/user",
"component": "system/user/index",
"permission": "system:user:list",
"icon": "user",
"sort": 1,
"status": 1,
"children": []
}
]
}
]
}GET /system/menu/parent-options
查询参数:
exclude_id: 排除的菜单ID
GET /system/menu/type-options
POST /system/menu
请求参数:
{
"parent_id": 0,
"name": "系统管理",
"code": "system",
"type": 1,
"path": "/system",
"component": "",
"permission": "system",
"icon": "system",
"sort": 1,
"status": 1,
"is_hidden": 0,
"is_cache": 1
}字段说明:
parent_id: 父级ID(必填,0表示顶级)name: 菜单名称(必填)code: 菜单编码(必填,唯一)type: 菜单类型(必填,1=目录,2=菜单,3=按钮)path: 路由路径(可选)component: 组件路径(可选)permission: 权限标识(可选)icon: 图标(可选)sort: 排序值(可选,默认0)status: 状态(可选,0=禁用,1=启用,默认1)is_hidden: 是否隐藏(可选,0=显示,1=隐藏,默认0)is_cache: 是否缓存(可选,0=不缓存,1=缓存,默认1)
PUT /system/menu/{id}
DELETE /system/menu/{id}
POST /system/menu/batch-delete
请求参数:
{
"ids": [1, 2, 3]
}POST /system/menu/{id}/change-status
请求参数:
{
"status": 1
}POST /system/menu/batch-change-status
请求参数:
{
"ids": [1, 2, 3],
"status": 1
}POST /system/menu/update-sorts
请求参数:
{
"sorts": [
{"id": 1, "sort": 1},
{"id": 2, "sort": 2}
]
}GET /system/menu/search
查询参数:
keyword: 搜索关键词page: 页码limit: 每页数量
GET /system/menu/statistics
GET /system/profile/info
请求头:
Authorization: Bearer {token}
响应示例:
{
"code": 200,
"message": "success",
"data": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"nickname": "超级管理员",
"phone": "13800138000",
"avatar": "/uploads/avatar/default.png",
"status": 1,
"last_login_time": "2024-01-01 12:00:00",
"last_login_ip": "127.0.0.1",
"created_at": "2024-01-01 00:00:00",
"roles": [
{
"id": 1,
"name": "超级管理员",
"code": "super_admin"
}
]
}
}PUT /system/profile/info
请求头:
Authorization: Bearer {token}
请求参数:
{
"nickname": "新昵称",
"phone": "13800138001",
"email": "newemail@example.com"
}字段说明:
nickname: 昵称(可选)phone: 手机号(可选)email: 邮箱(可选,需要唯一)
响应示例:
{
"code": 200,
"message": "个人信息更新成功",
"data": {
"id": 1,
"username": "admin",
"email": "newemail@example.com",
"nickname": "新昵称",
"phone": "13800138001"
}
}PUT /system/profile/avatar
请求头:
Authorization: Bearer {token}
请求参数:
{
"avatar": "/uploads/avatar/new_avatar.png"
}字段说明:
avatar: 头像路径(必填)
响应示例:
{
"code": 200,
"message": "头像更新成功",
"data": {
"avatar": "/uploads/avatar/new_avatar.png"
}
}PUT /system/profile/password
请求头:
Authorization: Bearer {token}
请求参数:
{
"old_password": "123456",
"new_password": "newpassword",
"confirm_password": "newpassword"
}字段说明:
old_password: 原密码(必填)new_password: 新密码(必填,最少6位)confirm_password: 确认密码(必填,需与new_password一致)
响应示例:
{
"code": 200,
"message": "密码修改成功",
"data": null
}GET /system/profile/online-devices
请求头:
Authorization: Bearer {token}
响应示例:
{
"code": 200,
"message": "success",
"data": [
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"device": "Chrome 120.0.0.0",
"os": "Windows 10",
"ip": "127.0.0.1",
"location": "本地",
"login_time": "2024-01-01 12:00:00",
"last_active": "2024-01-01 15:30:00",
"is_current": true
},
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"device": "Safari 17.0",
"os": "macOS 14.0",
"ip": "192.168.1.100",
"location": "上海",
"login_time": "2024-01-01 10:00:00",
"last_active": "2024-01-01 14:00:00",
"is_current": false
}
]
}DELETE /system/profile/kickout/{token}
请求头:
Authorization: Bearer {token}
路径参数:
token: 要强制下线的设备Token
响应示例:
{
"code": 200,
"message": "强制下线成功",
"data": null
}注意: 不能强制下线当前设备
当请求发生错误时,API 会返回相应的错误信息:
参数验证错误 (400)
{
"code": 400,
"message": "用户名已存在",
"data": null,
"timestamp": 1640995200
}认证失败 (401)
{
"code": 401,
"message": "Token无效或已过期",
"data": null,
"timestamp": 1640995200
}权限不足 (403)
{
"code": 403,
"message": "权限不足",
"data": null,
"timestamp": 1640995200
}资源不存在 (404)
{
"code": 404,
"message": "用户不存在",
"data": null,
"timestamp": 1640995200
}数据验证失败 (422)
{
"code": 422,
"message": "数据验证失败",
"data": {
"username": ["用户名不能为空"],
"email": ["邮箱格式不正确"]
},
"timestamp": 1640995200
}服务器错误 (500)
{
"code": 500,
"message": "服务器内部错误",
"data": null,
"timestamp": 1640995200
}// 设置基础URL和请求拦截器
const api = axios.create({
baseURL: 'http://localhost:8787',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
}
});
// 请求拦截器 - 添加Token
api.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 响应拦截器 - 统一错误处理
api.interceptors.response.use(
response => {
return response;
},
error => {
if (error.response?.status === 401) {
// Token过期,跳转到登录页
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// 登录
const login = async (username, password) => {
try {
const response = await api.post('/auth/login', {
username,
password
});
if (response.data.code === 200) {
localStorage.setItem('token', response.data.data.token);
return response.data.data;
}
throw new Error(response.data.message);
} catch (error) {
throw new Error(error.response?.data?.message || '登录失败');
}
};
// 获取用户列表
const getUsers = async (params = {}) => {
try {
const response = await api.get('/system/user', { params });
return response.data;
} catch (error) {
throw new Error(error.response?.data?.message || '获取用户列表失败');
}
};
// 创建用户
const createUser = async (userData) => {
try {
const response = await api.post('/system/user', userData);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.message || '创建用户失败');
}
};
// 获取角色列表(带查询参数)
const getRoles = async (params = {}) => {
try {
const response = await api.get('/system/role', { params });
return response.data;
} catch (error) {
throw new Error(error.response?.data?.message || '获取角色列表失败');
}
};
// 使用示例
async function example() {
try {
// 登录
const loginResult = await login('admin', '123456');
console.log('登录成功:', loginResult);
// 获取用户列表(第1页,每页20条,按创建时间倒序)
const users = await getUsers({
page: 1,
limit: 20,
order: 'created_at desc'
});
console.log('用户列表:', users);
// 搜索角色(名称包含"管理")
const roles = await getRoles({
name: '管理',
status: 1
});
console.log('角色列表:', roles);
} catch (error) {
console.error('操作失败:', error.message);
}
}# 1. 登录获取Token
curl -X POST http://localhost:8787/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"123456"}'
# 响应示例:
# {
# "code": 200,
# "message": "登录成功",
# "data": {
# "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
# "expires_in": 7200
# }
# }
# 2. 获取用户列表(需要替换YOUR_TOKEN_HERE为实际token)
curl -X GET "http://localhost:8787/system/user?page=1&limit=10" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# 3. 创建用户
curl -X POST http://localhost:8787/system/user \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "123456",
"confirm_password": "123456",
"nickname": "测试用户",
"status": 1
}'
# 4. 搜索角色(名称包含"管理")
curl -X GET "http://localhost:8787/system/role?name=管理&status=1" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# 5. 获取菜单树
curl -X GET http://localhost:8787/system/menu/tree \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# 6. 更新用户状态
curl -X POST http://localhost:8787/system/user/1/change-status \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{"status": 0}'import requests
import json
class WebmanAPI:
def __init__(self, base_url='http://localhost:8787'):
self.base_url = base_url
self.token = None
self.session = requests.Session()
self.session.headers.update({'Content-Type': 'application/json'})
def login(self, username, password):
"""用户登录"""
url = f"{self.base_url}/auth/login"
data = {"username": username, "password": password}
response = self.session.post(url, json=data)
result = response.json()
if result['code'] == 200:
self.token = result['data']['token']
self.session.headers.update({
'Authorization': f'Bearer {self.token}'
})
return result['data']
else:
raise Exception(result['message'])
def get_users(self, **params):
"""获取用户列表"""
url = f"{self.base_url}/system/user"
response = self.session.get(url, params=params)
return response.json()
def create_user(self, user_data):
"""创建用户"""
url = f"{self.base_url}/system/user"
response = self.session.post(url, json=user_data)
return response.json()
# 使用示例
if __name__ == "__main__":
api = WebmanAPI()
try:
# 登录
login_result = api.login('admin', '123456')
print(f"登录成功: {login_result}")
# 获取用户列表
users = api.get_users(page=1, limit=10, status=1)
print(f"用户列表: {users}")
# 创建用户
new_user = {
"username": "testuser",
"email": "test@example.com",
"password": "123456",
"confirm_password": "123456",
"nickname": "测试用户"
}
result = api.create_user(new_user)
print(f"创建用户: {result}")
except Exception as e:
print(f"操作失败: {e}")page: 页码,从1开始limit: 每页数量,最大100条order: 排序规则,格式:字段名 排序方向,多个字段用逗号分隔- 示例:
id desc、created_at desc,id asc
- 示例:
- 精确匹配:
status=1 - 模糊搜索:
name=管理员(会自动进行LIKE查询) - 关键词搜索:
keyword=张三(会在多个字段中搜索)
# 基础分页
GET /system/user?page=1&limit=20
# 状态筛选
GET /system/user?status=1
# 模糊搜索用户名
GET /system/user?username=admin
# 关键词搜索(搜索用户名、邮箱、昵称)
GET /system/user?keyword=张三
# 组合查询
GET /system/user?status=1&keyword=管理&page=2&limit=15&order=created_at desc
# 角色查询示例
GET /system/role?name=管理员&status=1&order=sort asc
# 菜单查询示例
GET /system/menu?type=2&parent_id=1&status=1在使用 API 之前,请先导入项目根目录下的 database.sql 文件来初始化数据库。
超级管理员账号:
- 用户名:
admin - 密码:
123456 - 邮箱:
admin@example.com
请在 config/think-orm.php 中配置数据库连接信息:
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'webman_starter',
'username' => 'root',
'password' => '',
'hostport' => '3306',
'charset' => 'utf8mb4',
],
],
];- 系统采用RBAC(基于角色的访问控制)模型
- 用户可以分配多个角色
- 角色可以分配多个菜单权限
- 所有需要认证的接口都会检查JWT Token
- 部分接口会检查用户是否有相应的权限
- 超级管理员拥有所有权限
- 菜单分为:目录、菜单、按钮三种类型
- 权限标识格式:
模块:控制器:操作 - 示例:
system:user:list、system:user:create
-
Token管理
- 将Token存储在localStorage或sessionStorage中
- 设置请求拦截器自动添加Authorization头
- 设置响应拦截器处理Token过期
-
错误处理
- 统一处理API错误响应
- 根据错误码显示相应的提示信息
- 401错误时自动跳转到登录页
-
分页组件
- 封装通用的分页组件
- 支持页码、每页数量、总数显示
- 支持跳转到指定页码
-
请求参数
- 使用对象传递查询参数
- 避免在URL中直接拼接参数
- 对特殊字符进行URL编码
-
错误处理
- 始终使用try-catch包装API调用
- 根据业务需求处理不同的错误码
- 提供用户友好的错误提示
-
性能优化
- 合理设置分页大小
- 使用防抖处理搜索请求
- 缓存不经常变化的数据
-
Token安全
- Token有效期为2小时,过期后需要重新登录或刷新
- 生产环境请务必修改JWT密钥
- 建议使用HTTPS保护数据传输
-
密码安全
- 默认密码请在生产环境中修改
- 密码采用bcrypt加密存储
- 建议设置密码复杂度要求
-
权限控制
- 不要在前端依赖权限控制
- 所有敏感操作都需要后端验证权限
- 定期审查用户权限分配
-
查询优化
- 避免一次性查询大量数据
- 合理使用分页和筛选条件
- 对经常查询的字段建立索引
-
缓存策略
- 菜单数据可以缓存
- 用户权限信息可以缓存
- 注意缓存更新时机
- PHP >= 8.0
- MySQL >= 5.7
- Composer
- Webman框架
- 修改所有默认密码和密钥
- 启用HTTPS
- 配置适当的CORS策略
- 设置合适的日志级别
- 配置数据库连接池
- 启用opcache提升性能