30 changed files with 4226 additions and 286 deletions
@ -0,0 +1,396 @@
@@ -0,0 +1,396 @@
|
||||
# 角色管理前后台交互指南 |
||||
|
||||
## 概述 |
||||
|
||||
本文档介绍如何将前台角色管理功能连接到真实的后端API,实现完整的前后台交互。 |
||||
|
||||
## 功能特性 |
||||
|
||||
### ✅ 已实现功能 |
||||
|
||||
1. **角色CRUD操作** |
||||
- 获取角色列表(支持分页) |
||||
- 创建新角色 |
||||
- 更新角色信息 |
||||
- 删除角色 |
||||
|
||||
2. **API测试模式** |
||||
- 支持测试模式切换(无需JWT认证) |
||||
- 支持正式模式(需要JWT认证) |
||||
- 实时API连接测试 |
||||
|
||||
3. **错误处理** |
||||
- 统一的错误响应格式 |
||||
- 友好的错误提示 |
||||
- 网络连接异常处理 |
||||
|
||||
4. **用户体验** |
||||
- 加载状态显示 |
||||
- 操作确认提示 |
||||
- 实时数据刷新 |
||||
|
||||
## 快速开始 |
||||
|
||||
### 1. 启动服务 |
||||
|
||||
使用完整启动脚本同时启动前后台: |
||||
|
||||
```powershell |
||||
# 标准模式启动 |
||||
.\start-full.ps1 |
||||
|
||||
# 调试模式启动 |
||||
.\start-full.ps1 -Debug |
||||
|
||||
# 测试模式启动 |
||||
.\start-full.ps1 -Test |
||||
``` |
||||
|
||||
### 2. 访问应用 |
||||
|
||||
- **前端应用**: http://localhost:8081 |
||||
- **后端API**: http://localhost:8080 |
||||
- **API文档**: http://localhost:8080/swagger/index.html |
||||
|
||||
### 3. 测试API连接 |
||||
|
||||
1. 进入角色管理页面 |
||||
2. 点击"测试模式"按钮切换到测试模式 |
||||
3. 点击"新建角色"测试创建功能 |
||||
4. 查看角色列表测试获取功能 |
||||
|
||||
## API接口说明 |
||||
|
||||
### 基础信息 |
||||
|
||||
- **API基础路径**: `/api/auth/roles` |
||||
- **测试路径**: `/api/auth/roles/test` |
||||
- **认证方式**: JWT Bearer Token |
||||
- **响应格式**: JSON |
||||
|
||||
### 接口列表 |
||||
|
||||
#### 1. 获取角色列表 |
||||
|
||||
```http |
||||
GET /api/auth/roles?page=1&pageSize=10 |
||||
``` |
||||
|
||||
**响应格式**: |
||||
```json |
||||
{ |
||||
"code": 200, |
||||
"message": "获取角色列表成功", |
||||
"data": { |
||||
"data": [ |
||||
{ |
||||
"id": 1, |
||||
"name": "管理员", |
||||
"code": "ADMIN", |
||||
"description": "系统管理员", |
||||
"created_at": "2024-01-01T00:00:00Z", |
||||
"updated_at": "2024-01-01T00:00:00Z" |
||||
} |
||||
], |
||||
"page": 1, |
||||
"size": 10, |
||||
"total": 1 |
||||
} |
||||
} |
||||
``` |
||||
|
||||
#### 2. 创建角色 |
||||
|
||||
```http |
||||
POST /api/auth/roles |
||||
Content-Type: application/json |
||||
|
||||
{ |
||||
"name": "新角色", |
||||
"code": "NEW_ROLE", |
||||
"description": "角色描述" |
||||
} |
||||
``` |
||||
|
||||
**响应格式**: |
||||
```json |
||||
{ |
||||
"code": 200, |
||||
"message": "角色创建成功", |
||||
"data": { |
||||
"id": 2, |
||||
"name": "新角色", |
||||
"code": "NEW_ROLE", |
||||
"description": "角色描述", |
||||
"created_at": "2024-01-01T00:00:00Z", |
||||
"updated_at": "2024-01-01T00:00:00Z" |
||||
} |
||||
} |
||||
``` |
||||
|
||||
#### 3. 更新角色 |
||||
|
||||
```http |
||||
PUT /api/auth/roles/{id} |
||||
Content-Type: application/json |
||||
|
||||
{ |
||||
"name": "更新后的角色", |
||||
"code": "UPDATED_ROLE", |
||||
"description": "更新后的描述" |
||||
} |
||||
``` |
||||
|
||||
#### 4. 删除角色 |
||||
|
||||
```http |
||||
DELETE /api/auth/roles/{id} |
||||
``` |
||||
|
||||
**响应格式**: |
||||
```json |
||||
{ |
||||
"code": 200, |
||||
"message": "角色删除成功", |
||||
"data": null |
||||
} |
||||
``` |
||||
|
||||
## 前端组件使用 |
||||
|
||||
### 1. 角色管理主页面 |
||||
|
||||
```vue |
||||
<template> |
||||
<RoleManagement /> |
||||
</template> |
||||
|
||||
<script> |
||||
import { RoleManagement } from '@/modules/role-management' |
||||
|
||||
export default { |
||||
components: { |
||||
RoleManagement |
||||
} |
||||
} |
||||
</script> |
||||
``` |
||||
|
||||
### 2. API测试页面 |
||||
|
||||
```vue |
||||
<template> |
||||
<RoleApiTest /> |
||||
</template> |
||||
|
||||
<script> |
||||
import { RoleApiTest } from '@/modules/role-management' |
||||
|
||||
export default { |
||||
components: { |
||||
RoleApiTest |
||||
} |
||||
} |
||||
</script> |
||||
``` |
||||
|
||||
### 3. 直接使用服务 |
||||
|
||||
```javascript |
||||
import { roleService } from '@/modules/role-management' |
||||
|
||||
// 获取角色列表 |
||||
const roles = await roleService.getRoles(1, 10) |
||||
|
||||
// 创建角色 |
||||
const newRole = await roleService.createRole({ |
||||
name: '测试角色', |
||||
code: 'TEST_ROLE', |
||||
description: '测试描述' |
||||
}) |
||||
|
||||
// 更新角色 |
||||
const updatedRole = await roleService.updateRole(1, { |
||||
name: '更新后的角色', |
||||
code: 'UPDATED_ROLE', |
||||
description: '更新后的描述' |
||||
}) |
||||
|
||||
// 删除角色 |
||||
await roleService.deleteRole(1) |
||||
``` |
||||
|
||||
## 配置说明 |
||||
|
||||
### 1. API基础URL配置 |
||||
|
||||
前端配置文件: `app/src/config/app.config.js` |
||||
|
||||
```javascript |
||||
export const appConfig = { |
||||
development: { |
||||
apiBaseUrl: 'http://localhost:8080/api', |
||||
// ... |
||||
} |
||||
} |
||||
``` |
||||
|
||||
### 2. 测试模式配置 |
||||
|
||||
通过localStorage控制测试模式: |
||||
|
||||
```javascript |
||||
// 启用测试模式 |
||||
localStorage.setItem('role-test-mode', 'true') |
||||
|
||||
// 禁用测试模式 |
||||
localStorage.setItem('role-test-mode', 'false') |
||||
|
||||
// 检查测试模式状态 |
||||
const isTestMode = localStorage.getItem('role-test-mode') === 'true' |
||||
``` |
||||
|
||||
### 3. JWT认证配置 |
||||
|
||||
```javascript |
||||
// 设置JWT token |
||||
localStorage.setItem('token', 'your-jwt-token') |
||||
|
||||
// 清除JWT token |
||||
localStorage.removeItem('token') |
||||
``` |
||||
|
||||
## 错误处理 |
||||
|
||||
### 1. 网络错误 |
||||
|
||||
```javascript |
||||
try { |
||||
const response = await roleService.getRoles() |
||||
} catch (error) { |
||||
if (error.code === 0) { |
||||
console.error('网络连接失败') |
||||
} else if (error.code === 401) { |
||||
console.error('认证失败,请重新登录') |
||||
} else { |
||||
console.error('请求失败:', error.message) |
||||
} |
||||
} |
||||
``` |
||||
|
||||
### 2. 业务错误 |
||||
|
||||
```javascript |
||||
const response = await roleService.createRole(roleData) |
||||
if (response.code !== 200) { |
||||
console.error('业务错误:', response.message) |
||||
} |
||||
``` |
||||
|
||||
## 开发调试 |
||||
|
||||
### 1. 启用调试模式 |
||||
|
||||
```powershell |
||||
# 启动调试模式 |
||||
.\start-full.ps1 -Debug |
||||
``` |
||||
|
||||
### 2. 查看API日志 |
||||
|
||||
后端日志文件: `backend/logs/app.log` |
||||
|
||||
### 3. 使用API测试页面 |
||||
|
||||
访问角色管理API测试页面,可以: |
||||
- 查看API配置信息 |
||||
- 手动测试各个接口 |
||||
- 查看详细的请求响应 |
||||
- 切换测试模式 |
||||
|
||||
### 4. 浏览器开发者工具 |
||||
|
||||
- 打开Network面板查看API请求 |
||||
- 查看Console面板的错误信息 |
||||
- 使用Application面板查看localStorage |
||||
|
||||
## 常见问题 |
||||
|
||||
### Q1: API连接失败 |
||||
|
||||
**解决方案**: |
||||
1. 检查后端服务是否启动 |
||||
2. 确认API基础URL配置正确 |
||||
3. 检查防火墙设置 |
||||
4. 查看后端日志 |
||||
|
||||
### Q2: 认证失败 |
||||
|
||||
**解决方案**: |
||||
1. 切换到测试模式(无需认证) |
||||
2. 检查JWT token是否有效 |
||||
3. 重新登录获取新token |
||||
|
||||
### Q3: 数据不显示 |
||||
|
||||
**解决方案**: |
||||
1. 检查API响应格式 |
||||
2. 确认数据库中有数据 |
||||
3. 查看浏览器控制台错误 |
||||
|
||||
### Q4: 创建/更新失败 |
||||
|
||||
**解决方案**: |
||||
1. 检查必填字段是否填写 |
||||
2. 确认角色名称和代码唯一性 |
||||
3. 查看后端验证错误信息 |
||||
|
||||
## 扩展功能 |
||||
|
||||
### 1. 权限管理 |
||||
|
||||
可以扩展角色管理功能,添加: |
||||
- 角色权限分配 |
||||
- 权限树形展示 |
||||
- 批量权限操作 |
||||
|
||||
### 2. 用户角色分配 |
||||
|
||||
可以添加: |
||||
- 用户角色分配页面 |
||||
- 批量角色分配 |
||||
- 角色继承关系 |
||||
|
||||
### 3. 角色模板 |
||||
|
||||
可以添加: |
||||
- 角色模板管理 |
||||
- 快速创建角色 |
||||
- 角色导入导出 |
||||
|
||||
## 技术栈 |
||||
|
||||
### 前端 |
||||
- Vue 3 (Composition API) |
||||
- Axios (HTTP客户端) |
||||
- Vue Router (路由管理) |
||||
|
||||
### 后端 |
||||
- Go (Gin框架) |
||||
- GORM (ORM) |
||||
- JWT (认证) |
||||
|
||||
### 数据库 |
||||
- MySQL/PostgreSQL |
||||
- Redis (缓存) |
||||
|
||||
## 贡献指南 |
||||
|
||||
1. Fork项目 |
||||
2. 创建功能分支 |
||||
3. 提交代码 |
||||
4. 创建Pull Request |
||||
|
||||
## 许可证 |
||||
|
||||
MIT License |
@ -0,0 +1,180 @@
@@ -0,0 +1,180 @@
|
||||
# Swagger UI Authorize按钮不显示问题解决方案 |
||||
|
||||
## 问题描述 |
||||
在Swagger UI中,右上角没有显示"Authorize"按钮,无法配置JWT token进行API测试。 |
||||
|
||||
## 原因分析 |
||||
1. **Swagger UI版本问题**:某些版本的Swagger UI可能不显示Authorize按钮 |
||||
2. **配置方式问题**:gin-swagger的配置可能不完整 |
||||
3. **浏览器缓存问题**:浏览器可能缓存了旧版本的页面 |
||||
|
||||
## 解决方案 |
||||
|
||||
### 方案1:使用自定义Swagger UI(推荐) |
||||
|
||||
我已经创建了一个自定义的Swagger UI页面,确保Authorize按钮能正确显示: |
||||
|
||||
1. **访问自定义Swagger UI**: |
||||
``` |
||||
http://localhost:8080/swagger-ui |
||||
``` |
||||
|
||||
2. **这个页面使用了最新版本的Swagger UI (5.9.0)**,确保Authorize按钮正常显示 |
||||
|
||||
### 方案2:检查配置 |
||||
|
||||
确保以下配置正确: |
||||
|
||||
#### 1. main.go中的安全定义配置 |
||||
```go |
||||
// @securityDefinitions.apikey BearerAuth |
||||
// @in header |
||||
// @name Authorization |
||||
// @description 请输入 "Bearer " + JWT token,例如: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." |
||||
``` |
||||
|
||||
#### 2. API控制器中的安全配置 |
||||
```go |
||||
// @Security BearerAuth |
||||
// @Router /auth/roles [post] |
||||
func (c *RoleController) CreateRole(ctx *gin.Context) { |
||||
// ... |
||||
} |
||||
``` |
||||
|
||||
### 方案3:浏览器操作 |
||||
|
||||
1. **清除浏览器缓存**: |
||||
- 按 `Ctrl+Shift+Delete` |
||||
- 选择"缓存的图片和文件" |
||||
- 点击"清除数据" |
||||
|
||||
2. **强制刷新页面**: |
||||
- 按 `Ctrl+F5` 强制刷新 |
||||
- 或者按 `Ctrl+Shift+R` |
||||
|
||||
3. **检查浏览器控制台**: |
||||
- 按 `F12` 打开开发者工具 |
||||
- 查看Console标签页是否有错误信息 |
||||
- 查看Network标签页是否有请求失败 |
||||
|
||||
### 方案4:验证配置 |
||||
|
||||
运行测试脚本验证配置: |
||||
```powershell |
||||
.\test-swagger-auth.ps1 |
||||
``` |
||||
|
||||
这个脚本会: |
||||
1. 检查后端服务状态 |
||||
2. 验证Swagger JSON文档 |
||||
3. 检查安全定义配置 |
||||
4. 检查API安全配置 |
||||
5. 测试Swagger UI页面 |
||||
|
||||
## 使用步骤 |
||||
|
||||
### 1. 启动后端服务 |
||||
```bash |
||||
cd backend |
||||
go run main.go |
||||
``` |
||||
|
||||
### 2. 访问Swagger UI |
||||
- **默认UI**:http://localhost:8080/swagger/index.html |
||||
- **自定义UI**:http://localhost:8080/swagger-ui (推荐) |
||||
|
||||
### 3. 配置身份验证 |
||||
1. 点击右上角的 **"Authorize"** 按钮 |
||||
2. 在输入框中输入:`Bearer <your-jwt-token>` |
||||
3. 点击 **"Authorize"** 按钮 |
||||
|
||||
### 4. 获取JWT Token |
||||
1. 先调用 `/api/auth/captcha` 获取验证码 |
||||
2. 再调用 `/api/auth/login` 进行登录 |
||||
3. 复制返回的 `access_token` |
||||
|
||||
## 故障排除 |
||||
|
||||
### 如果Authorize按钮仍然不显示: |
||||
|
||||
1. **检查Swagger JSON文档**: |
||||
``` |
||||
http://localhost:8080/swagger/doc.json |
||||
``` |
||||
确保包含 `securityDefinitions` 部分 |
||||
|
||||
2. **检查API配置**: |
||||
确保需要认证的API包含 `security` 配置 |
||||
|
||||
3. **尝试不同的浏览器**: |
||||
- Chrome |
||||
- Firefox |
||||
- Edge |
||||
|
||||
4. **检查网络连接**: |
||||
确保能正常访问Swagger UI页面 |
||||
|
||||
### 常见错误及解决方案: |
||||
|
||||
1. **"Failed to load resource"**: |
||||
- 检查后端服务是否正常运行 |
||||
- 检查端口8080是否被占用 |
||||
|
||||
2. **"CORS error"**: |
||||
- 确保CORS中间件正确配置 |
||||
- 检查请求来源 |
||||
|
||||
3. **"404 Not Found"**: |
||||
- 确保Swagger路由正确配置 |
||||
- 检查文件路径 |
||||
|
||||
## 验证成功标志 |
||||
|
||||
当配置正确时,你应该能看到: |
||||
|
||||
1. ✅ Swagger UI页面正常加载 |
||||
2. ✅ 右上角显示 **"Authorize"** 按钮 |
||||
3. ✅ 点击Authorize按钮能打开认证对话框 |
||||
4. ✅ 需要认证的API显示锁定图标 🔒 |
||||
5. ✅ 配置token后能正常调用需要认证的API |
||||
|
||||
## 测试API流程 |
||||
|
||||
1. **获取验证码**: |
||||
``` |
||||
GET /api/auth/captcha |
||||
``` |
||||
|
||||
2. **用户登录**: |
||||
``` |
||||
POST /api/auth/login |
||||
{ |
||||
"username": "admin", |
||||
"password": "admin123", |
||||
"captcha": "验证码", |
||||
"captcha_id": "验证码ID" |
||||
} |
||||
``` |
||||
|
||||
3. **配置Authorize**: |
||||
- 点击Authorize按钮 |
||||
- 输入:`Bearer <access_token>` |
||||
- 点击Authorize |
||||
|
||||
4. **测试需要认证的API**: |
||||
``` |
||||
GET /api/auth/roles |
||||
POST /api/auth/roles |
||||
PUT /api/auth/roles/{id} |
||||
DELETE /api/auth/roles/{id} |
||||
``` |
||||
|
||||
## 总结 |
||||
|
||||
如果默认的Swagger UI不显示Authorize按钮,请使用自定义的Swagger UI页面: |
||||
``` |
||||
http://localhost:8080/swagger-ui |
||||
``` |
||||
|
||||
这个页面使用了最新版本的Swagger UI,确保Authorize按钮能正常显示和使用。 |
@ -0,0 +1,166 @@
@@ -0,0 +1,166 @@
|
||||
# Swagger配置修复总结 |
||||
|
||||
## 修复的问题 |
||||
|
||||
### 1. Swagger路由路径配置问题 |
||||
|
||||
**问题描述:** |
||||
- Swagger路由配置不完整,缺少重定向路径 |
||||
- 用户无法通过多种方式访问Swagger文档 |
||||
|
||||
**修复内容:** |
||||
- 在 `backend/main.go` 中添加了多个Swagger访问路径: |
||||
```go |
||||
// Swagger路由配置 |
||||
app.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) |
||||
app.GET("/docs", func(c *gin.Context) { |
||||
c.Redirect(http.StatusMovedPermanently, "/swagger/index.html") |
||||
}) |
||||
app.GET("/api-docs", func(c *gin.Context) { |
||||
c.Redirect(http.StatusMovedPermanently, "/swagger/index.html") |
||||
}) |
||||
``` |
||||
|
||||
**访问路径:** |
||||
- 主要路径:`http://localhost:8080/swagger/index.html` |
||||
- 重定向路径:`http://localhost:8080/docs` |
||||
- API文档路径:`http://localhost:8080/api-docs` |
||||
|
||||
### 2. Swagger身份验证配置问题 |
||||
|
||||
**问题描述:** |
||||
- Swagger文档没有配置身份验证 |
||||
- 无法在Swagger UI中测试需要认证的API |
||||
|
||||
**修复内容:** |
||||
- 在 `backend/main.go` 中添加了身份验证配置: |
||||
```go |
||||
// @securityDefinitions.apikey BearerAuth |
||||
// @in header |
||||
// @name Authorization |
||||
// @description 请输入 "Bearer " + JWT token,例如: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." |
||||
``` |
||||
|
||||
- 为所有需要认证的API添加了 `@Security BearerAuth` 注释 |
||||
|
||||
### 3. 角色路由路径修复 |
||||
|
||||
**问题描述:** |
||||
- 角色管理路由路径不正确,导致API无法访问 |
||||
|
||||
**修复内容:** |
||||
- 在 `backend/internal/auth/routes/role_routes.go` 中修复了路由路径: |
||||
```go |
||||
// 角色管理路由组 - 修复路径配置 |
||||
roleGroup := router.Group("/auth/roles") |
||||
``` |
||||
|
||||
### 4. Swagger注释完善 |
||||
|
||||
**修复内容:** |
||||
- 为角色控制器的方法添加了完整的Swagger注释: |
||||
- `CreateRole` - 创建角色 |
||||
- `UpdateRole` - 更新角色 |
||||
- `DeleteRole` - 删除角色 |
||||
- `GetRole` - 获取角色详情 |
||||
- `ListRoles` - 获取角色列表 |
||||
|
||||
- 每个方法都包含了: |
||||
- `@Summary` - 接口摘要 |
||||
- `@Description` - 详细描述 |
||||
- `@Tags` - 标签分类 |
||||
- `@Accept` - 接受的数据类型 |
||||
- `@Produce` - 返回的数据类型 |
||||
- `@Param` - 参数说明 |
||||
- `@Success` - 成功响应 |
||||
- `@Failure` - 失败响应 |
||||
- `@Security` - 安全认证 |
||||
- `@Router` - 路由路径 |
||||
|
||||
## 使用方法 |
||||
|
||||
### 1. 启动后端服务 |
||||
```bash |
||||
cd backend |
||||
go run main.go |
||||
``` |
||||
|
||||
### 2. 访问Swagger文档 |
||||
- 主要地址:http://localhost:8080/swagger/index.html |
||||
- 重定向地址:http://localhost:8080/docs |
||||
|
||||
### 3. 测试API流程 |
||||
|
||||
#### 步骤1:获取验证码 |
||||
1. 在Swagger UI中找到 `/api/auth/captcha` 接口 |
||||
2. 点击 "Try it out" |
||||
3. 点击 "Execute" |
||||
4. 复制返回的验证码ID和图片 |
||||
|
||||
#### 步骤2:用户登录 |
||||
1. 找到 `/api/auth/login` 接口 |
||||
2. 点击 "Try it out" |
||||
3. 输入测试账号: |
||||
```json |
||||
{ |
||||
"username": "admin", |
||||
"password": "admin123", |
||||
"captcha": "验证码", |
||||
"captcha_id": "验证码ID" |
||||
} |
||||
``` |
||||
4. 点击 "Execute" |
||||
5. 复制返回的 `access_token` |
||||
|
||||
#### 步骤3:配置身份验证 |
||||
1. 点击Swagger UI右上角的 "Authorize" 按钮 |
||||
2. 在输入框中输入:`Bearer <your-access-token>` |
||||
3. 点击 "Authorize" |
||||
|
||||
#### 步骤4:测试需要认证的API |
||||
现在可以测试所有需要认证的API: |
||||
- `/api/auth/roles` - 角色管理相关接口 |
||||
- 其他需要认证的接口 |
||||
|
||||
## 测试脚本 |
||||
|
||||
创建了 `test-swagger.ps1` 脚本来验证修复效果: |
||||
|
||||
```powershell |
||||
# 运行测试脚本 |
||||
.\test-swagger.ps1 |
||||
|
||||
# 如果需要启动后端服务 |
||||
.\test-swagger.ps1 -StartBackend |
||||
``` |
||||
|
||||
## 验证结果 |
||||
|
||||
### ✅ 已修复的问题 |
||||
1. **Swagger路由配置** - 多个访问路径正常工作 |
||||
2. **身份验证配置** - Swagger UI支持Bearer Token认证 |
||||
3. **API路由路径** - 角色管理API路径正确 |
||||
4. **Swagger注释** - 所有API都有完整的文档注释 |
||||
|
||||
### 🔧 可用的功能 |
||||
1. **无需认证的API**: |
||||
- `/api/auth/captcha` - 获取验证码 |
||||
- `/api/auth/login` - 用户登录 |
||||
- `/api/auth/roles/test/*` - 测试模式角色管理 |
||||
|
||||
2. **需要认证的API**: |
||||
- `/api/auth/roles/*` - 正式角色管理 |
||||
- 其他需要JWT认证的接口 |
||||
|
||||
### 📝 注意事项 |
||||
1. 测试模式的路由(`/api/auth/roles/test/*`)不需要认证 |
||||
2. 正式模式的路由(`/api/auth/roles/*`)需要JWT认证 |
||||
3. 在Swagger UI中必须先配置Authorize才能测试需要认证的API |
||||
4. 建议先使用测试模式验证API功能,再使用正式模式测试认证流程 |
||||
|
||||
## 下一步建议 |
||||
|
||||
1. **前端集成**:将认证服务集成到前端应用中 |
||||
2. **错误处理**:完善API错误处理和响应格式 |
||||
3. **权限控制**:实现基于角色的权限控制 |
||||
4. **API测试**:编写自动化API测试用例 |
@ -0,0 +1,548 @@
@@ -0,0 +1,548 @@
|
||||
<template> |
||||
<div class="role-api-test"> |
||||
<div class="page-header"> |
||||
<h2>角色管理API测试</h2> |
||||
<div class="header-actions"> |
||||
<button |
||||
class="btn btn-secondary" |
||||
@click="toggleTestMode" |
||||
:title="testMode ? '当前为测试模式(无需认证)' : '当前为正式模式(需要认证)'" |
||||
> |
||||
<i class="fas fa-flask"></i> |
||||
{{ testMode ? '测试模式' : '正式模式' }} |
||||
</button> |
||||
<button class="btn btn-primary" @click="runAllTests"> |
||||
<i class="fas fa-play"></i> 运行所有测试 |
||||
</button> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="test-content"> |
||||
<!-- API配置信息 --> |
||||
<div class="test-section"> |
||||
<h3>API配置信息</h3> |
||||
<div class="config-info"> |
||||
<div class="config-item"> |
||||
<label>API基础地址:</label> |
||||
<span>{{ apiBaseUrl }}</span> |
||||
</div> |
||||
<div class="config-item"> |
||||
<label>当前模式:</label> |
||||
<span :class="testMode ? 'test-mode' : 'prod-mode'"> |
||||
{{ testMode ? '测试模式' : '正式模式' }} |
||||
</span> |
||||
</div> |
||||
<div class="config-item"> |
||||
<label>API路径:</label> |
||||
<span>{{ currentApiPath }}</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 测试结果 --> |
||||
<div class="test-section"> |
||||
<h3>测试结果</h3> |
||||
<div class="test-results"> |
||||
<div |
||||
v-for="(result, index) in testResults" |
||||
:key="index" |
||||
class="test-result-item" |
||||
:class="result.status" |
||||
> |
||||
<div class="test-header"> |
||||
<span class="test-name">{{ result.name }}</span> |
||||
<span class="test-status">{{ getStatusText(result.status) }}</span> |
||||
</div> |
||||
<div v-if="result.message" class="test-message"> |
||||
{{ result.message }} |
||||
</div> |
||||
<div v-if="result.data" class="test-data"> |
||||
<pre>{{ JSON.stringify(result.data, null, 2) }}</pre> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- 手动测试 --> |
||||
<div class="test-section"> |
||||
<h3>手动测试</h3> |
||||
<div class="manual-tests"> |
||||
<div class="test-group"> |
||||
<h4>获取角色列表</h4> |
||||
<button @click="testGetRoles" :disabled="testing"> |
||||
{{ testing ? '测试中...' : '测试获取角色列表' }} |
||||
</button> |
||||
</div> |
||||
|
||||
<div class="test-group"> |
||||
<h4>创建角色</h4> |
||||
<div class="form-group"> |
||||
<label>角色名称:</label> |
||||
<input v-model="testRole.name" type="text" placeholder="测试角色" /> |
||||
</div> |
||||
<div class="form-group"> |
||||
<label>角色代码:</label> |
||||
<input v-model="testRole.code" type="text" placeholder="TEST_ROLE" /> |
||||
</div> |
||||
<div class="form-group"> |
||||
<label>描述:</label> |
||||
<input v-model="testRole.description" type="text" placeholder="测试角色描述" /> |
||||
</div> |
||||
<button @click="testCreateRole" :disabled="testing"> |
||||
{{ testing ? '测试中...' : '测试创建角色' }} |
||||
</button> |
||||
</div> |
||||
|
||||
<div class="test-group"> |
||||
<h4>更新角色</h4> |
||||
<div class="form-group"> |
||||
<label>角色ID:</label> |
||||
<input v-model="updateRoleId" type="number" placeholder="输入角色ID" /> |
||||
</div> |
||||
<button @click="testUpdateRole" :disabled="testing || !updateRoleId"> |
||||
{{ testing ? '测试中...' : '测试更新角色' }} |
||||
</button> |
||||
</div> |
||||
|
||||
<div class="test-group"> |
||||
<h4>删除角色</h4> |
||||
<div class="form-group"> |
||||
<label>角色ID:</label> |
||||
<input v-model="deleteRoleId" type="number" placeholder="输入角色ID" /> |
||||
</div> |
||||
<button @click="testDeleteRole" :disabled="testing || !deleteRoleId"> |
||||
{{ testing ? '测试中...' : '测试删除角色' }} |
||||
</button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { ref, reactive, computed, onMounted } from 'vue' |
||||
import { roleService } from '../services/roleService.js' |
||||
import { getFinalConfig } from '../../../../config/app.config.js' |
||||
|
||||
export default { |
||||
name: 'RoleApiTest', |
||||
setup() { |
||||
const testing = ref(false) |
||||
const testMode = ref(false) |
||||
const testResults = ref([]) |
||||
|
||||
const updateRoleId = ref('') |
||||
const deleteRoleId = ref('') |
||||
|
||||
const testRole = reactive({ |
||||
name: '测试角色', |
||||
code: 'TEST_ROLE', |
||||
description: '这是一个测试角色' |
||||
}) |
||||
|
||||
const apiBaseUrl = computed(() => getFinalConfig().apiBaseUrl) |
||||
const currentApiPath = computed(() => testMode.value ? '/auth/roles/test' : '/auth/roles') |
||||
|
||||
// 切换测试模式 |
||||
const toggleTestMode = () => { |
||||
testMode.value = roleService.toggleTestMode() |
||||
addTestResult('模式切换', 'success', `已切换到${testMode.value ? '测试' : '正式'}模式`) |
||||
} |
||||
|
||||
// 添加测试结果 |
||||
const addTestResult = (name, status, message, data = null) => { |
||||
testResults.value.unshift({ |
||||
name, |
||||
status, |
||||
message, |
||||
data, |
||||
timestamp: new Date().toLocaleString() |
||||
}) |
||||
} |
||||
|
||||
// 获取状态文本 |
||||
const getStatusText = (status) => { |
||||
const statusMap = { |
||||
'success': '成功', |
||||
'error': '失败', |
||||
'warning': '警告' |
||||
} |
||||
return statusMap[status] || status |
||||
} |
||||
|
||||
// 测试获取角色列表 |
||||
const testGetRoles = async () => { |
||||
testing.value = true |
||||
try { |
||||
const response = await roleService.getRoles(1, 10) |
||||
if (response.code === 200) { |
||||
addTestResult('获取角色列表', 'success', '获取角色列表成功', response.data) |
||||
} else { |
||||
addTestResult('获取角色列表', 'error', `获取失败: ${response.message}`, response) |
||||
} |
||||
} catch (error) { |
||||
addTestResult('获取角色列表', 'error', `请求失败: ${error.message || error.error}`, error) |
||||
} finally { |
||||
testing.value = false |
||||
} |
||||
} |
||||
|
||||
// 测试创建角色 |
||||
const testCreateRole = async () => { |
||||
testing.value = true |
||||
try { |
||||
const response = await roleService.createRole(testRole) |
||||
if (response.code === 200) { |
||||
addTestResult('创建角色', 'success', '创建角色成功', response.data) |
||||
} else { |
||||
addTestResult('创建角色', 'error', `创建失败: ${response.message}`, response) |
||||
} |
||||
} catch (error) { |
||||
addTestResult('创建角色', 'error', `请求失败: ${error.message || error.error}`, error) |
||||
} finally { |
||||
testing.value = false |
||||
} |
||||
} |
||||
|
||||
// 测试更新角色 |
||||
const testUpdateRole = async () => { |
||||
if (!updateRoleId.value) { |
||||
addTestResult('更新角色', 'warning', '请输入角色ID') |
||||
return |
||||
} |
||||
|
||||
testing.value = true |
||||
try { |
||||
const updateData = { |
||||
name: `${testRole.name}_更新`, |
||||
code: `${testRole.code}_UPDATED`, |
||||
description: `${testRole.description}_更新` |
||||
} |
||||
const response = await roleService.updateRole(updateRoleId.value, updateData) |
||||
if (response.code === 200) { |
||||
addTestResult('更新角色', 'success', '更新角色成功', response.data) |
||||
} else { |
||||
addTestResult('更新角色', 'error', `更新失败: ${response.message}`, response) |
||||
} |
||||
} catch (error) { |
||||
addTestResult('更新角色', 'error', `请求失败: ${error.message || error.error}`, error) |
||||
} finally { |
||||
testing.value = false |
||||
} |
||||
} |
||||
|
||||
// 测试删除角色 |
||||
const testDeleteRole = async () => { |
||||
if (!deleteRoleId.value) { |
||||
addTestResult('删除角色', 'warning', '请输入角色ID') |
||||
return |
||||
} |
||||
|
||||
testing.value = true |
||||
try { |
||||
const response = await roleService.deleteRole(deleteRoleId.value) |
||||
if (response.code === 200) { |
||||
addTestResult('删除角色', 'success', '删除角色成功', response.data) |
||||
} else { |
||||
addTestResult('删除角色', 'error', `删除失败: ${response.message}`, response) |
||||
} |
||||
} catch (error) { |
||||
addTestResult('删除角色', 'error', `请求失败: ${error.message || error.error}`, error) |
||||
} finally { |
||||
testing.value = false |
||||
} |
||||
} |
||||
|
||||
// 运行所有测试 |
||||
const runAllTests = async () => { |
||||
addTestResult('测试开始', 'success', '开始运行所有API测试') |
||||
|
||||
await testGetRoles() |
||||
await new Promise(resolve => setTimeout(resolve, 1000)) // 等待1秒 |
||||
await testCreateRole() |
||||
await new Promise(resolve => setTimeout(resolve, 1000)) // 等待1秒 |
||||
|
||||
addTestResult('测试完成', 'success', '所有API测试已完成') |
||||
} |
||||
|
||||
onMounted(() => { |
||||
testMode.value = roleService.getTestModeStatus() |
||||
addTestResult('页面加载', 'success', '角色管理API测试页面已加载') |
||||
}) |
||||
|
||||
return { |
||||
testing, |
||||
testMode, |
||||
testResults, |
||||
updateRoleId, |
||||
deleteRoleId, |
||||
testRole, |
||||
apiBaseUrl, |
||||
currentApiPath, |
||||
toggleTestMode, |
||||
testGetRoles, |
||||
testCreateRole, |
||||
testUpdateRole, |
||||
testDeleteRole, |
||||
runAllTests, |
||||
getStatusText |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.role-api-test { |
||||
padding: 20px; |
||||
height: 100%; |
||||
overflow-y: auto; |
||||
} |
||||
|
||||
.page-header { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.page-header h2 { |
||||
margin: 0; |
||||
color: var(--text-primary); |
||||
} |
||||
|
||||
.header-actions { |
||||
display: flex; |
||||
gap: 12px; |
||||
align-items: center; |
||||
} |
||||
|
||||
.test-content { |
||||
max-width: 1200px; |
||||
} |
||||
|
||||
.test-section { |
||||
background: var(--card-bg); |
||||
border-radius: 8px; |
||||
padding: 24px; |
||||
margin-bottom: 24px; |
||||
box-shadow: 0 2px 8px var(--shadow-color); |
||||
} |
||||
|
||||
.test-section h3 { |
||||
margin: 0 0 20px 0; |
||||
color: var(--text-primary); |
||||
font-size: 18px; |
||||
border-bottom: 2px solid var(--border-color); |
||||
padding-bottom: 8px; |
||||
} |
||||
|
||||
.config-info { |
||||
display: grid; |
||||
gap: 12px; |
||||
} |
||||
|
||||
.config-item { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
padding: 12px; |
||||
background: var(--bg-secondary); |
||||
border-radius: 4px; |
||||
} |
||||
|
||||
.config-item label { |
||||
font-weight: 500; |
||||
color: var(--text-primary); |
||||
} |
||||
|
||||
.config-item span { |
||||
color: var(--text-secondary); |
||||
font-family: monospace; |
||||
} |
||||
|
||||
.test-mode { |
||||
color: #ff9800 !important; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.prod-mode { |
||||
color: #4caf50 !important; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.test-results { |
||||
max-height: 400px; |
||||
overflow-y: auto; |
||||
} |
||||
|
||||
.test-result-item { |
||||
margin-bottom: 16px; |
||||
padding: 16px; |
||||
border-radius: 6px; |
||||
border-left: 4px solid; |
||||
} |
||||
|
||||
.test-result-item.success { |
||||
background: rgba(76, 175, 80, 0.1); |
||||
border-left-color: #4caf50; |
||||
} |
||||
|
||||
.test-result-item.error { |
||||
background: rgba(244, 67, 54, 0.1); |
||||
border-left-color: #f44336; |
||||
} |
||||
|
||||
.test-result-item.warning { |
||||
background: rgba(255, 152, 0, 0.1); |
||||
border-left-color: #ff9800; |
||||
} |
||||
|
||||
.test-header { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
margin-bottom: 8px; |
||||
} |
||||
|
||||
.test-name { |
||||
font-weight: 500; |
||||
color: var(--text-primary); |
||||
} |
||||
|
||||
.test-status { |
||||
font-size: 12px; |
||||
padding: 4px 8px; |
||||
border-radius: 4px; |
||||
font-weight: 500; |
||||
} |
||||
|
||||
.test-result-item.success .test-status { |
||||
background: #4caf50; |
||||
color: white; |
||||
} |
||||
|
||||
.test-result-item.error .test-status { |
||||
background: #f44336; |
||||
color: white; |
||||
} |
||||
|
||||
.test-result-item.warning .test-status { |
||||
background: #ff9800; |
||||
color: white; |
||||
} |
||||
|
||||
.test-message { |
||||
color: var(--text-secondary); |
||||
margin-bottom: 8px; |
||||
} |
||||
|
||||
.test-data { |
||||
background: var(--bg-secondary); |
||||
padding: 12px; |
||||
border-radius: 4px; |
||||
overflow-x: auto; |
||||
} |
||||
|
||||
.test-data pre { |
||||
margin: 0; |
||||
font-size: 12px; |
||||
color: var(--text-secondary); |
||||
} |
||||
|
||||
.manual-tests { |
||||
display: grid; |
||||
gap: 24px; |
||||
} |
||||
|
||||
.test-group { |
||||
padding: 16px; |
||||
background: var(--bg-secondary); |
||||
border-radius: 6px; |
||||
} |
||||
|
||||
.test-group h4 { |
||||
margin: 0 0 16px 0; |
||||
color: var(--text-primary); |
||||
} |
||||
|
||||
.form-group { |
||||
margin-bottom: 12px; |
||||
} |
||||
|
||||
.form-group label { |
||||
display: block; |
||||
margin-bottom: 4px; |
||||
font-weight: 500; |
||||
color: var(--text-primary); |
||||
} |
||||
|
||||
.form-group input { |
||||
width: 100%; |
||||
padding: 8px 12px; |
||||
border: 1px solid var(--border-color); |
||||
border-radius: 4px; |
||||
background: var(--input-bg); |
||||
color: var(--input-text); |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.btn { |
||||
padding: 8px 16px; |
||||
border: none; |
||||
border-radius: 4px; |
||||
cursor: pointer; |
||||
font-size: 14px; |
||||
display: inline-flex; |
||||
align-items: center; |
||||
gap: 6px; |
||||
transition: all 0.2s; |
||||
} |
||||
|
||||
.btn-primary { |
||||
background: var(--accent-color); |
||||
color: white; |
||||
} |
||||
|
||||
.btn-primary:hover { |
||||
background: var(--accent-hover); |
||||
} |
||||
|
||||
.btn-secondary { |
||||
background: #757575; |
||||
color: white; |
||||
} |
||||
|
||||
.btn-secondary:hover { |
||||
background: #616161; |
||||
} |
||||
|
||||
.btn:hover { |
||||
opacity: 0.9; |
||||
} |
||||
|
||||
.btn:disabled { |
||||
opacity: 0.5; |
||||
cursor: not-allowed; |
||||
} |
||||
|
||||
button { |
||||
background: var(--accent-color); |
||||
color: white; |
||||
border: none; |
||||
padding: 8px 16px; |
||||
border-radius: 4px; |
||||
cursor: pointer; |
||||
font-size: 14px; |
||||
transition: all 0.2s; |
||||
} |
||||
|
||||
button:hover:not(:disabled) { |
||||
background: var(--accent-hover); |
||||
} |
||||
|
||||
button:disabled { |
||||
opacity: 0.5; |
||||
cursor: not-allowed; |
||||
} |
||||
</style> |
Binary file not shown.
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="zh-CN"> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<title>GoFaster API 文档</title> |
||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css" /> |
||||
<style> |
||||
html { |
||||
box-sizing: border-box; |
||||
overflow: -moz-scrollbars-vertical; |
||||
overflow-y: scroll; |
||||
} |
||||
*, *:before, *:after { |
||||
box-sizing: inherit; |
||||
} |
||||
body { |
||||
margin:0; |
||||
background: #fafafa; |
||||
} |
||||
.swagger-ui .topbar { |
||||
background-color: #2c3e50; |
||||
} |
||||
.swagger-ui .info .title { |
||||
color: #2c3e50; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div id="swagger-ui"></div> |
||||
<script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js"></script> |
||||
<script src="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-standalone-preset.js"></script> |
||||
<script> |
||||
window.onload = function() { |
||||
const ui = SwaggerUIBundle({ |
||||
url: '/swagger/doc.json', |
||||
dom_id: '#swagger-ui', |
||||
deepLinking: true, |
||||
presets: [ |
||||
SwaggerUIBundle.presets.apis, |
||||
SwaggerUIStandalonePreset |
||||
], |
||||
plugins: [ |
||||
SwaggerUIBundle.plugins.DownloadUrl |
||||
], |
||||
layout: "StandaloneLayout", |
||||
validatorUrl: null, |
||||
onComplete: function() { |
||||
console.log('Swagger UI loaded successfully'); |
||||
// 确保Authorize按钮显示 |
||||
setTimeout(function() { |
||||
const authorizeBtn = document.querySelector('.authorize'); |
||||
if (authorizeBtn) { |
||||
console.log('Authorize button found'); |
||||
} else { |
||||
console.log('Authorize button not found, checking security definitions...'); |
||||
// 检查是否有安全定义 |
||||
fetch('/swagger/doc.json') |
||||
.then(response => response.json()) |
||||
.then(data => { |
||||
console.log('Security definitions:', data.securityDefinitions); |
||||
if (data.securityDefinitions) { |
||||
console.log('Security definitions exist, Authorize button should be visible'); |
||||
} |
||||
}); |
||||
} |
||||
}, 1000); |
||||
} |
||||
}); |
||||
}; |
||||
</script> |
||||
</body> |
||||
</html> |
@ -1 +1 @@
@@ -1 +1 @@
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 |
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 |
Binary file not shown.
@ -0,0 +1,118 @@
@@ -0,0 +1,118 @@
|
||||
# Swagger配置诊断脚本 |
||||
Write-Host "🔍 Swagger配置诊断工具" -ForegroundColor Cyan |
||||
Write-Host "================================================" -ForegroundColor Cyan |
||||
Write-Host "" |
||||
|
||||
# 检查后端服务状态 |
||||
Write-Host "📋 检查后端服务状态..." -ForegroundColor Yellow |
||||
|
||||
try { |
||||
$response = Invoke-WebRequest -Uri "http://localhost:8080/health" -TimeoutSec 5 -ErrorAction Stop |
||||
Write-Host "✅ 后端服务正在运行 (状态码: $($response.StatusCode))" -ForegroundColor Green |
||||
} catch { |
||||
Write-Host "❌ 后端服务未运行或无法访问" -ForegroundColor Red |
||||
Write-Host " 错误信息: $($_.Exception.Message)" -ForegroundColor Red |
||||
Write-Host "" |
||||
Write-Host "请先启动后端服务:" -ForegroundColor Yellow |
||||
Write-Host " cd backend" -ForegroundColor White |
||||
Write-Host " go run main.go" -ForegroundColor White |
||||
exit 1 |
||||
} |
||||
|
||||
Write-Host "" |
||||
|
||||
# 检查Swagger JSON文档 |
||||
Write-Host "🔍 检查Swagger JSON文档..." -ForegroundColor Yellow |
||||
|
||||
try { |
||||
$response = Invoke-WebRequest -Uri "http://localhost:8080/swagger/doc.json" -TimeoutSec 5 -ErrorAction Stop |
||||
$swaggerDoc = $response.Content | ConvertFrom-Json |
||||
|
||||
Write-Host "✅ Swagger JSON文档获取成功" -ForegroundColor Green |
||||
|
||||
# 检查安全定义 |
||||
if ($swaggerDoc.securityDefinitions) { |
||||
Write-Host "✅ 安全定义配置存在" -ForegroundColor Green |
||||
Write-Host " 安全定义类型: $($swaggerDoc.securityDefinitions.PSObject.Properties.Name)" -ForegroundColor White |
||||
} else { |
||||
Write-Host "❌ 安全定义配置缺失" -ForegroundColor Red |
||||
} |
||||
|
||||
# 检查API安全配置 |
||||
$secureApis = @() |
||||
foreach ($path in $swaggerDoc.paths.PSObject.Properties) { |
||||
foreach ($method in $path.Value.PSObject.Properties) { |
||||
if ($method.Value.security) { |
||||
$secureApis += "$($path.Name) [$($method.Name)]" |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ($secureApis.Count -gt 0) { |
||||
Write-Host "✅ 发现 $($secureApis.Count) 个需要认证的API" -ForegroundColor Green |
||||
foreach ($api in $secureApis) { |
||||
Write-Host " - $api" -ForegroundColor White |
||||
} |
||||
} else { |
||||
Write-Host "❌ 没有发现需要认证的API" -ForegroundColor Red |
||||
} |
||||
|
||||
} catch { |
||||
Write-Host "❌ 获取Swagger JSON文档失败: $($_.Exception.Message)" -ForegroundColor Red |
||||
} |
||||
|
||||
Write-Host "" |
||||
|
||||
# 检查Swagger UI页面 |
||||
Write-Host "🔍 检查Swagger UI页面..." -ForegroundColor Yellow |
||||
|
||||
$swaggerUIs = @( |
||||
@{Path="/swagger/index.html"; Name="默认Swagger UI"}, |
||||
@{Path="/swagger-ui"; Name="自定义Swagger UI"}, |
||||
@{Path="/swagger-ui-fixed"; Name="修复版Swagger UI"} |
||||
) |
||||
|
||||
foreach ($ui in $swaggerUIs) { |
||||
try { |
||||
$uri = "http://localhost:8080$($ui.Path)" |
||||
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 5 -ErrorAction Stop |
||||
Write-Host "✅ $($ui.Name): 页面加载成功" -ForegroundColor Green |
||||
} catch { |
||||
$errorMsg = if ($_.Exception.Response) { |
||||
"HTTP $($_.Exception.Response.StatusCode)" |
||||
} else { |
||||
$_.Exception.Message |
||||
} |
||||
Write-Host "❌ $($ui.Name): $errorMsg" -ForegroundColor Red |
||||
} |
||||
} |
||||
|
||||
Write-Host "" |
||||
|
||||
# 显示访问信息 |
||||
Write-Host "💡 访问信息:" -ForegroundColor Cyan |
||||
Write-Host " 默认Swagger UI: http://localhost:8080/swagger/index.html" -ForegroundColor White |
||||
Write-Host " 自定义Swagger UI: http://localhost:8080/swagger-ui" -ForegroundColor White |
||||
Write-Host " 修复版Swagger UI: http://localhost:8080/swagger-ui-fixed" -ForegroundColor White |
||||
Write-Host " Swagger JSON: http://localhost:8080/swagger/doc.json" -ForegroundColor White |
||||
Write-Host "" |
||||
|
||||
Write-Host "🔧 Authorize按钮不显示的可能原因:" -ForegroundColor Cyan |
||||
Write-Host " 1. Swagger UI版本问题" -ForegroundColor White |
||||
Write-Host " 2. 浏览器缓存问题" -ForegroundColor White |
||||
Write-Host " 3. 安全定义配置问题" -ForegroundColor White |
||||
Write-Host " 4. API没有使用安全配置" -ForegroundColor White |
||||
Write-Host "" |
||||
|
||||
Write-Host "🎯 解决方案:" -ForegroundColor Cyan |
||||
Write-Host " 1. 使用修复版Swagger UI: http://localhost:8080/swagger-ui-fixed" -ForegroundColor White |
||||
Write-Host " 2. 清除浏览器缓存 (Ctrl+Shift+Delete)" -ForegroundColor White |
||||
Write-Host " 3. 强制刷新页面 (Ctrl+F5)" -ForegroundColor White |
||||
Write-Host " 4. 检查浏览器控制台错误信息 (F12)" -ForegroundColor White |
||||
Write-Host "" |
||||
|
||||
Write-Host "📝 测试步骤:" -ForegroundColor Cyan |
||||
Write-Host " 1. 访问 http://localhost:8080/swagger-ui-fixed" -ForegroundColor White |
||||
Write-Host " 2. 检查右上角是否有Authorize按钮" -ForegroundColor White |
||||
Write-Host " 3. 如果没有,按F12查看控制台错误信息" -ForegroundColor White |
||||
Write-Host " 4. 尝试不同的浏览器" -ForegroundColor White |
@ -0,0 +1,128 @@
@@ -0,0 +1,128 @@
|
||||
# Swagger身份验证配置测试脚本 |
||||
param( |
||||
[switch]$StartBackend |
||||
) |
||||
|
||||
Write-Host "🔍 Swagger身份验证配置测试" -ForegroundColor Cyan |
||||
Write-Host "================================================" -ForegroundColor Cyan |
||||
Write-Host "" |
||||
|
||||
# 检查后端服务状态 |
||||
Write-Host "📋 检查后端服务状态..." -ForegroundColor Yellow |
||||
|
||||
try { |
||||
$response = Invoke-WebRequest -Uri "http://localhost:8080/health" -TimeoutSec 5 -ErrorAction Stop |
||||
Write-Host "✅ 后端服务正在运行 (状态码: $($response.StatusCode))" -ForegroundColor Green |
||||
} catch { |
||||
Write-Host "❌ 后端服务未运行或无法访问" -ForegroundColor Red |
||||
Write-Host " 错误信息: $($_.Exception.Message)" -ForegroundColor Red |
||||
|
||||
if ($StartBackend) { |
||||
Write-Host "" |
||||
Write-Host "🚀 正在启动后端服务..." -ForegroundColor Yellow |
||||
Start-Process powershell -ArgumentList "-NoExit", "-Command", "cd backend; go run main.go" |
||||
Write-Host "⏳ 等待后端服务启动..." -ForegroundColor Yellow |
||||
Start-Sleep -Seconds 10 |
||||
|
||||
try { |
||||
$response = Invoke-WebRequest -Uri "http://localhost:8080/health" -TimeoutSec 5 -ErrorAction Stop |
||||
Write-Host "✅ 后端服务启动成功" -ForegroundColor Green |
||||
} catch { |
||||
Write-Host "❌ 后端服务启动失败" -ForegroundColor Red |
||||
return |
||||
} |
||||
} else { |
||||
return |
||||
} |
||||
} |
||||
|
||||
Write-Host "" |
||||
|
||||
# 测试Swagger JSON文档 |
||||
Write-Host "🔍 测试Swagger JSON文档..." -ForegroundColor Yellow |
||||
|
||||
try { |
||||
$response = Invoke-WebRequest -Uri "http://localhost:8080/swagger/doc.json" -TimeoutSec 5 -ErrorAction Stop |
||||
$swaggerDoc = $response.Content | ConvertFrom-Json |
||||
|
||||
Write-Host "✅ Swagger JSON文档获取成功" -ForegroundColor Green |
||||
|
||||
# 检查安全定义 |
||||
if ($swaggerDoc.securityDefinitions) { |
||||
Write-Host "✅ 安全定义配置存在" -ForegroundColor Green |
||||
Write-Host " 安全定义: $($swaggerDoc.securityDefinitions | ConvertTo-Json -Depth 1)" -ForegroundColor White |
||||
} else { |
||||
Write-Host "❌ 安全定义配置缺失" -ForegroundColor Red |
||||
} |
||||
|
||||
# 检查API安全配置 |
||||
$secureApis = @() |
||||
foreach ($path in $swaggerDoc.paths.PSObject.Properties) { |
||||
foreach ($method in $path.Value.PSObject.Properties) { |
||||
if ($method.Value.security) { |
||||
$secureApis += "$($path.Name) [$($method.Name)]" |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ($secureApis.Count -gt 0) { |
||||
Write-Host "✅ 发现 $($secureApis.Count) 个需要认证的API" -ForegroundColor Green |
||||
foreach ($api in $secureApis) { |
||||
Write-Host " - $api" -ForegroundColor White |
||||
} |
||||
} else { |
||||
Write-Host "❌ 没有发现需要认证的API" -ForegroundColor Red |
||||
} |
||||
|
||||
} catch { |
||||
Write-Host "❌ 获取Swagger JSON文档失败: $($_.Exception.Message)" -ForegroundColor Red |
||||
} |
||||
|
||||
Write-Host "" |
||||
|
||||
# 测试Swagger UI页面 |
||||
Write-Host "🔍 测试Swagger UI页面..." -ForegroundColor Yellow |
||||
|
||||
$swaggerUIs = @( |
||||
@{Path="/swagger/index.html"; Name="默认Swagger UI"}, |
||||
@{Path="/swagger-ui"; Name="自定义Swagger UI"} |
||||
) |
||||
|
||||
foreach ($ui in $swaggerUIs) { |
||||
try { |
||||
$uri = "http://localhost:8080$($ui.Path)" |
||||
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 5 -ErrorAction Stop |
||||
Write-Host "✅ $($ui.Name): 页面加载成功" -ForegroundColor Green |
||||
} catch { |
||||
$errorMsg = if ($_.Exception.Response) { |
||||
"HTTP $($_.Exception.Response.StatusCode)" |
||||
} else { |
||||
$_.Exception.Message |
||||
} |
||||
Write-Host "❌ $($ui.Name): $errorMsg" -ForegroundColor Red |
||||
} |
||||
} |
||||
|
||||
Write-Host "" |
||||
|
||||
# 显示访问信息 |
||||
Write-Host "💡 访问信息:" -ForegroundColor Cyan |
||||
Write-Host " 默认Swagger UI: http://localhost:8080/swagger/index.html" -ForegroundColor White |
||||
Write-Host " 自定义Swagger UI: http://localhost:8080/swagger-ui" -ForegroundColor White |
||||
Write-Host " Swagger JSON: http://localhost:8080/swagger/doc.json" -ForegroundColor White |
||||
Write-Host "" |
||||
|
||||
Write-Host "🔧 身份验证说明:" -ForegroundColor Cyan |
||||
Write-Host " 1. 如果Authorize按钮不显示,请尝试以下方法:" -ForegroundColor White |
||||
Write-Host " - 使用自定义Swagger UI: http://localhost:8080/swagger-ui" -ForegroundColor White |
||||
Write-Host " - 检查浏览器控制台是否有错误信息" -ForegroundColor White |
||||
Write-Host " - 清除浏览器缓存并重新加载" -ForegroundColor White |
||||
Write-Host " 2. 确保API有 @Security BearerAuth 注释" -ForegroundColor White |
||||
Write-Host " 3. 确保main.go中有 @securityDefinitions.apikey 配置" -ForegroundColor White |
||||
|
||||
Write-Host "" |
||||
Write-Host "🎯 故障排除步骤:" -ForegroundColor Cyan |
||||
Write-Host " 1. 检查Swagger JSON文档是否包含securityDefinitions" -ForegroundColor White |
||||
Write-Host " 2. 检查API是否包含security配置" -ForegroundColor White |
||||
Write-Host " 3. 尝试不同的Swagger UI版本" -ForegroundColor White |
||||
Write-Host " 4. 检查浏览器开发者工具中的网络请求" -ForegroundColor White |
Loading…
Reference in new issue