Browse Source

修复前后台和swagger

master
hejl 4 days ago
parent
commit
cceb30aaba
  1. 1
      .gitignore
  2. 396
      gofaster/ROLE_MANAGEMENT_API_GUIDE.md
  3. 180
      gofaster/SWAGGER_AUTH_FIX.md
  4. 166
      gofaster/SWAGGER_FIX_SUMMARY.md
  5. 2
      gofaster/app/dist/renderer/js/index.js
  6. 402
      gofaster/app/src/main/index.js
  7. 548
      gofaster/app/src/renderer/modules/role-management/views/RoleApiTest.vue
  8. 773
      gofaster/backend/docs/docs.go
  9. 773
      gofaster/backend/docs/swagger.json
  10. 485
      gofaster/backend/docs/swagger.yaml
  11. 56
      gofaster/backend/internal/auth/controller/role_controller.go
  12. 55
      gofaster/backend/internal/auth/controller/user_controller.go
  13. 4
      gofaster/backend/internal/auth/routes/auth_routes.go
  14. 16
      gofaster/backend/internal/auth/routes/role_routes.go
  15. 23
      gofaster/backend/internal/auth/service/init_service.go
  16. 2
      gofaster/backend/internal/auth/service/permission_service.go
  17. 2
      gofaster/backend/internal/auth/service/role_service.go
  18. 17
      gofaster/backend/internal/auth/service/user_service.go
  19. 2
      gofaster/backend/internal/shared/middleware/jwt_middleware.go
  20. BIN
      gofaster/backend/main.exe
  21. 29
      gofaster/backend/main.go
  22. 73
      gofaster/backend/swagger-ui-fixed.html
  23. 2
      gofaster/backend/tmp/build-errors.log
  24. BIN
      gofaster/backend/tmp/main.exe
  25. 2
      gofaster/dev-full.ps1
  26. 118
      gofaster/diagnose-swagger.ps1
  27. 1
      gofaster/start-backend-only.ps1
  28. 99
      gofaster/test-backend.ps1
  29. 128
      gofaster/test-swagger-auth.ps1
  30. 157
      gofaster/test-swagger.ps1

1
.gitignore vendored

@ -15,3 +15,4 @@ @@ -15,3 +15,4 @@
/gofaster/tmp/
/gofaster/app/dist/*/*/
/gofaster/backend/tmp
/gofaster/backend/tmp/main.exe

396
gofaster/ROLE_MANAGEMENT_API_GUIDE.md

@ -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

180
gofaster/SWAGGER_AUTH_FIX.md

@ -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按钮能正常显示和使用。

166
gofaster/SWAGGER_FIX_SUMMARY.md

@ -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测试用例

2
gofaster/app/dist/renderer/js/index.js vendored

@ -14510,7 +14510,7 @@ __webpack_require__.r(__webpack_exports__); @@ -14510,7 +14510,7 @@ __webpack_require__.r(__webpack_exports__);
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ (() => {
/******/ __webpack_require__.h = () => ("fd7db7612102d9d9")
/******/ __webpack_require__.h = () => ("a30697658a725fba")
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */

402
gofaster/app/src/main/index.js

@ -65,7 +65,13 @@ let isDev = null @@ -65,7 +65,13 @@ let isDev = null
function getIsDev() {
if (isDev === null) {
try {
isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
// 确保app对象可用
if (app && typeof app.isPackaged === 'boolean') {
isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
} else {
// 如果app对象还没有准备好,默认使用开发环境
isDev = process.env.NODE_ENV === 'development' || true
}
} catch (error) {
// 如果app对象还没有准备好,默认使用开发环境
isDev = process.env.NODE_ENV === 'development' || true
@ -77,6 +83,12 @@ function getIsDev() { @@ -77,6 +83,12 @@ function getIsDev() {
// 初始化日志系统
function initLogging() {
try {
// 确保app对象可用
if (!app || typeof app.getPath !== 'function') {
console.warn('app对象不可用,跳过日志系统初始化');
return;
}
// 创建日志目录
const logDir = path.join(app.getPath('userData'), 'logs')
if (!fs.existsSync(logDir)) {
@ -155,6 +167,7 @@ if (getIsDev() && !process.argv.includes('--watch')) { @@ -155,6 +167,7 @@ if (getIsDev() && !process.argv.includes('--watch')) {
/\.git|[\/\\]\./
]
});
console.log('热重载已启用');
} catch (error) {
console.log('Hot reload failed:', error.message);
}
@ -502,212 +515,225 @@ function createWindow() { @@ -502,212 +515,225 @@ function createWindow() {
}
}
app.whenReady().then(() => {
// 初始化窗口状态管理器
initWindowStateManager()
// 初始化日志系统
initLogging()
createWindow()
// 确保app对象可用后再调用whenReady
if (app && typeof app.whenReady === 'function') {
app.whenReady().then(() => {
// 初始化窗口状态管理器
initWindowStateManager()
// 初始化日志系统
initLogging()
createWindow()
// 修复IPC通信问题
ipcMain.on('request-status', (event) => {
try {
const statusData = {
status: 'running',
timestamp: Date.now()
// 修复IPC通信问题
ipcMain.on('request-status', (event) => {
try {
const statusData = {
status: 'running',
timestamp: Date.now()
}
event.sender.send('status-update', statusData)
} catch (error) {
console.error('IPC communication error:', error);
}
event.sender.send('status-update', statusData)
} catch (error) {
console.error('IPC communication error:', error);
}
})
})
// 添加获取进程内存信息的API
ipcMain.handle('get-process-memory-info', async (event) => {
try {
// 使用 process.memoryUsage 获取内存信息
const memoryUsage = process.memoryUsage();
// 获取更详细的系统内存信息
let systemMemoryInfo = {};
// 添加获取进程内存信息的API
ipcMain.handle('get-process-memory-info', async (event) => {
try {
// 尝试使用 require('os') 获取系统内存信息
const os = require('os');
systemMemoryInfo = {
totalMemory: os.totalmem(),
freeMemory: os.freemem(),
usedMemory: os.totalmem() - os.freemem()
// 使用 process.memoryUsage 获取内存信息
const memoryUsage = process.memoryUsage();
// 获取更详细的系统内存信息
let systemMemoryInfo = {};
try {
// 尝试使用 require('os') 获取系统内存信息
const os = require('os');
systemMemoryInfo = {
totalMemory: os.totalmem(),
freeMemory: os.freemem(),
usedMemory: os.totalmem() - os.freemem()
};
} catch (osError) {
console.warn('Cannot get system memory info:', osError.message);
}
return {
// 进程内存使用情况
privateBytes: memoryUsage.rss, // Resident Set Size - 进程占用的物理内存
sharedBytes: memoryUsage.external, // 外部内存使用
heapUsed: memoryUsage.heapUsed, // JavaScript堆内存使用
heapTotal: memoryUsage.heapTotal, // JavaScript堆内存总量
// 系统内存信息
systemTotal: systemMemoryInfo.totalMemory || 0,
systemFree: systemMemoryInfo.freeMemory || 0,
systemUsed: systemMemoryInfo.usedMemory || 0
};
} catch (error) {
console.error('Failed to get memory info:', error);
// 返回默认值
return {
privateBytes: 0,
sharedBytes: 0,
heapUsed: 0,
heapTotal: 0,
systemTotal: 0,
systemFree: 0,
systemUsed: 0
};
} catch (osError) {
console.warn('Cannot get system memory info:', osError.message);
}
return {
// 进程内存使用情况
privateBytes: memoryUsage.rss, // Resident Set Size - 进程占用的物理内存
sharedBytes: memoryUsage.external, // 外部内存使用
heapUsed: memoryUsage.heapUsed, // JavaScript堆内存使用
heapTotal: memoryUsage.heapTotal, // JavaScript堆内存总量
// 系统内存信息
systemTotal: systemMemoryInfo.totalMemory || 0,
systemFree: systemMemoryInfo.freeMemory || 0,
systemUsed: systemMemoryInfo.usedMemory || 0
};
} catch (error) {
console.error('Failed to get memory info:', error);
// 返回默认值
return {
privateBytes: 0,
sharedBytes: 0,
heapUsed: 0,
heapTotal: 0,
systemTotal: 0,
systemFree: 0,
systemUsed: 0
};
}
});
// 添加更新窗口标题的API
ipcMain.handle('update-window-title', async (event, newTitle) => {
try {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.setTitle(newTitle);
return { success: true, message: '窗口标题更新成功' };
} else {
return { success: false, message: '主窗口不存在或已销毁' };
}
} catch (error) {
console.error('更新窗口标题失败:', error);
return { success: false, message: '更新窗口标题失败: ' + error.message };
}
});
// 获取错误日志计数
ipcMain.handle('get-error-log-count', async () => {
return { count: errorLogCount }
});
// 获取日志文件路径
ipcMain.handle('get-log-file-path', async () => {
return { path: logFilePath }
});
});
// 添加更新窗口标题的API
ipcMain.handle('update-window-title', async (event, newTitle) => {
try {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.setTitle(newTitle);
return { success: true, message: '窗口标题更新成功' };
} else {
return { success: false, message: '主窗口不存在或已销毁' };
}
} catch (error) {
console.error('更新窗口标题失败:', error);
return { success: false, message: '更新窗口标题失败: ' + error.message };
}
});
// 打开日志文件所在文件夹
ipcMain.handle('open-log-folder', async () => {
try {
const path = require('path');
const logDir = path.dirname(logFilePath);
require('electron').shell.openPath(logDir);
return { success: true, message: '日志文件夹已打开' };
} catch (error) {
console.error('打开日志文件夹失败:', error);
return { success: false, message: '打开日志文件夹失败: ' + error.message };
}
});
// 获取错误日志计数
ipcMain.handle('get-error-log-count', async () => {
return { count: errorLogCount }
});
// 获取本地IP地址
ipcMain.handle('get-local-ip', async () => {
try {
const ipInfo = getLocalIPAddresses();
if (ipInfo) {
return {
success: true,
ip: ipInfo.address,
interface: ipInfo.name,
netmask: ipInfo.netmask
};
} else {
return {
success: false,
message: '无法获取本地IP地址',
fallback: '127.0.0.1'
};
}
} catch (error) {
console.error('获取本地IP地址失败:', error);
return {
success: false,
message: '获取本地IP地址失败: ' + error.message,
fallback: '127.0.0.1'
};
}
});
// 获取日志文件路径
ipcMain.handle('get-log-file-path', async () => {
return { path: logFilePath }
});
// 窗口状态管理相关的IPC处理器
ipcMain.handle('reset-window-state', async () => {
try {
if (!windowStateManager) {
return {
success: false,
message: '窗口状态管理器未初始化'
// 打开日志文件所在文件夹
ipcMain.handle('open-log-folder', async () => {
try {
if (logFilePath) {
const logDir = path.dirname(logFilePath)
require('electron').shell.openPath(logDir)
return { success: true, message: '日志文件夹已打开' }
} else {
return { success: false, message: '日志文件路径未设置' }
}
} catch (error) {
console.error('打开日志文件夹失败:', error)
return { success: false, message: '打开日志文件夹失败: ' + error.message }
}
}
const result = windowStateManager.resetState()
return {
success: result,
message: result ? '窗口状态已重置' : '没有找到保存的窗口状态'
}
} catch (error) {
console.error('重置窗口状态失败:', error)
return {
success: false,
message: '重置窗口状态失败: ' + error.message
}
}
})
});
ipcMain.handle('get-window-state-info', async () => {
try {
if (!windowStateManager) {
return {
success: false,
message: '窗口状态管理器未初始化'
// 获取本地IP地址
ipcMain.handle('get-local-ip', async () => {
try {
const ipInfo = getLocalIPAddresses()
if (ipInfo) {
return {
success: true,
address: ipInfo.address,
name: ipInfo.name,
netmask: ipInfo.netmask,
family: ipInfo.family
}
} else {
return {
success: false,
message: '无法获取本地IP地址',
fallback: '127.0.0.1'
}
}
} catch (error) {
console.error('获取本地IP地址失败:', error)
return {
success: false,
message: '获取本地IP地址失败: ' + error.message,
fallback: '127.0.0.1'
};
}
}
const hasState = windowStateManager.hasSavedState()
const statePath = windowStateManager.getStatePath()
let currentState = null
if (hasState) {
});
// 窗口状态管理相关的IPC处理器
ipcMain.handle('reset-window-state', async () => {
try {
const stateData = fs.readFileSync(statePath, 'utf8')
currentState = JSON.parse(stateData)
if (!windowStateManager) {
return {
success: false,
message: '窗口状态管理器未初始化'
}
}
const result = windowStateManager.resetState()
return {
success: result,
message: result ? '窗口状态已重置' : '没有找到保存的窗口状态'
}
} catch (error) {
console.error('读取当前窗口状态失败:', error)
console.error('重置窗口状态失败:', error)
return {
success: false,
message: '重置窗口状态失败: ' + error.message
}
}
}
return {
hasSavedState: hasState,
statePath: statePath,
currentState: currentState
}
} catch (error) {
console.error('获取窗口状态信息失败:', error)
return {
success: false,
message: '获取窗口状态信息失败: ' + error.message
}
}
})
})
}); // 闭合 app.whenReady().then() 的回调函数
ipcMain.handle('get-window-state-info', async () => {
try {
if (!windowStateManager) {
return {
success: false,
message: '窗口状态管理器未初始化'
}
}
const hasState = windowStateManager.hasSavedState()
const statePath = windowStateManager.getStatePath()
let currentState = null
if (hasState) {
try {
const stateData = fs.readFileSync(statePath, 'utf8')
currentState = JSON.parse(stateData)
} catch (error) {
console.error('读取当前窗口状态失败:', error)
}
}
return {
hasSavedState: hasState,
statePath: statePath,
currentState: currentState
}
} catch (error) {
console.error('获取窗口状态信息失败:', error)
return {
success: false,
message: '获取窗口状态信息失败: ' + error.message
}
}
})
app.on('window-all-closed', () => {
// 由于已经在窗口 close 事件中处理了退出登录,这里直接退出
if (process.platform !== 'darwin') {
app.quit()
}
})
}); // 闭合 app.whenReady().then() 的回调函数
} else {
console.error('app对象不可用或whenReady方法不存在');
}
// 确保app对象可用后再注册事件监听器
if (app && typeof app.on === 'function') {
app.on('window-all-closed', () => {
// 由于已经在窗口 close 事件中处理了退出登录,这里直接退出
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) createWindow()
})
app.on('activate', () => {
if (mainWindow === null) createWindow()
})
} else {
console.error('app对象不可用,无法注册事件监听器');
}
// 添加错误处理
process.on('uncaughtException', (error) => {

548
gofaster/app/src/renderer/modules/role-management/views/RoleApiTest.vue

@ -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>

773
gofaster/backend/docs/docs.go

@ -24,7 +24,7 @@ const docTemplate = `{ @@ -24,7 +24,7 @@ const docTemplate = `{
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/users": {
"/auth/admin/users": {
"get": {
"description": "获取分页用户列表",
"consumes": [
@ -82,7 +82,7 @@ const docTemplate = `{ @@ -82,7 +82,7 @@ const docTemplate = `{
}
}
},
"/users/{id}": {
"/auth/admin/users/{id}": {
"get": {
"description": "根据ID获取用户详情",
"consumes": [
@ -260,9 +260,640 @@ const docTemplate = `{ @@ -260,9 +260,640 @@ const docTemplate = `{
}
}
}
},
"/auth/captcha": {
"get": {
"description": "生成图形验证码,用于登录验证",
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "生成验证码",
"responses": {
"200": {
"description": "验证码生成成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.CaptchaResponse"
}
}
}
]
}
}
}
}
},
"/auth/login": {
"post": {
"description": "用户登录接口,支持验证码验证和密码错误次数限制",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "用户登录",
"parameters": [
{
"description": "登录请求参数",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.LoginRequest"
}
}
],
"responses": {
"200": {
"description": "登录成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.LoginResponse"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"401": {
"description": "认证失败",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"423": {
"description": "账户被锁定",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/logout": {
"post": {
"description": "用户登出接口",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "用户登出",
"parameters": [
{
"description": "登出请求参数",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.LogoutRequest"
}
}
],
"responses": {
"200": {
"description": "登出成功",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/refresh": {
"post": {
"description": "使用刷新令牌获取新的访问令牌",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "刷新访问令牌",
"parameters": [
{
"description": "刷新令牌请求参数",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.RefreshTokenRequest"
}
}
],
"responses": {
"200": {
"description": "刷新成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.LoginResponse"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"401": {
"description": "刷新令牌无效",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/roles": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "分页获取角色列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "获取角色列表",
"parameters": [
{
"type": "integer",
"default": 1,
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 10,
"description": "每页数量",
"name": "pageSize",
"in": "query"
}
],
"responses": {
"200": {
"description": "获取成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/model.Role"
}
},
"page": {
"type": "integer"
},
"size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
}
}
}
]
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "创建新的角色",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "创建角色",
"parameters": [
{
"description": "角色信息",
"name": "role",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.Role"
}
}
],
"responses": {
"200": {
"description": "创建成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.Role"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/roles/{id}": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据ID获取角色详细信息",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "获取角色详情",
"parameters": [
{
"type": "integer",
"description": "角色ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "获取成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.Role"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"404": {
"description": "角色不存在",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"put": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据ID更新角色信息",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "更新角色",
"parameters": [
{
"type": "integer",
"description": "角色ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "角色信息",
"name": "role",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.Role"
}
}
],
"responses": {
"200": {
"description": "更新成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.Role"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据ID删除角色",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "删除角色",
"parameters": [
{
"type": "integer",
"description": "角色ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "删除成功",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/userinfo": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "获取当前登录用户的详细信息",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "获取用户信息",
"responses": {
"200": {
"description": "获取成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.UserInfo"
}
}
}
]
}
},
"401": {
"description": "未授权",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
}
},
"definitions": {
"model.CaptchaResponse": {
"type": "object",
"properties": {
"captcha_id": {
"type": "string"
},
"captcha_image": {
"description": "Base64编码的图片",
"type": "string"
},
"expires_in": {
"type": "integer"
}
}
},
"model.LoginRequest": {
"type": "object",
"required": [
"captcha",
"captcha_id",
"password",
"username"
],
"properties": {
"captcha": {
"type": "string"
},
"captcha_id": {
"type": "string"
},
"client_ip": {
"description": "客户端IP地址",
"type": "string"
},
"password": {
"type": "string",
"maxLength": 100,
"minLength": 6
},
"username": {
"type": "string",
"maxLength": 50,
"minLength": 3
}
}
},
"model.LoginResponse": {
"type": "object",
"properties": {
"expires_in": {
"type": "integer"
},
"force_change_password": {
"description": "是否需要强制修改密码",
"type": "boolean"
},
"refresh_token": {
"type": "string"
},
"token": {
"type": "string"
},
"token_type": {
"type": "string"
},
"user": {
"$ref": "#/definitions/model.UserInfo"
}
}
},
"model.LogoutRequest": {
"type": "object",
"required": [
"token"
],
"properties": {
"token": {
"type": "string"
}
}
},
"model.Permission": {
"type": "object",
"properties": {
@ -290,9 +921,43 @@ const docTemplate = `{ @@ -290,9 +921,43 @@ const docTemplate = `{
}
}
},
"model.PermissionInfo": {
"type": "object",
"properties": {
"action": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"resource": {
"type": "string"
}
}
},
"model.RefreshTokenRequest": {
"type": "object",
"required": [
"refresh_token"
],
"properties": {
"refresh_token": {
"type": "string"
}
}
},
"model.Role": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"created_at": {
"type": "string"
},
@ -316,6 +981,29 @@ const docTemplate = `{ @@ -316,6 +981,29 @@ const docTemplate = `{
}
}
},
"model.RoleInfo": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"permissions": {
"type": "array",
"items": {
"$ref": "#/definitions/model.PermissionInfo"
}
}
}
},
"model.User": {
"type": "object",
"properties": {
@ -325,9 +1013,25 @@ const docTemplate = `{ @@ -325,9 +1013,25 @@ const docTemplate = `{
"email": {
"type": "string"
},
"force_change_password": {
"description": "是否强制修改密码",
"type": "boolean"
},
"id": {
"type": "integer"
},
"last_login_at": {
"description": "最后登录时间",
"type": "string"
},
"last_login_ip": {
"description": "最后登录IP",
"type": "string"
},
"password_changed_at": {
"description": "密码最后修改时间",
"type": "string"
},
"phone": {
"type": "string"
},
@ -338,7 +1042,7 @@ const docTemplate = `{ @@ -338,7 +1042,7 @@ const docTemplate = `{
}
},
"status": {
"description": "1-正常 2-禁用",
"description": "1-正常 2-禁用 3-锁定",
"type": "integer"
},
"updated_at": {
@ -348,6 +1052,69 @@ const docTemplate = `{ @@ -348,6 +1052,69 @@ const docTemplate = `{
"type": "string"
}
}
},
"model.UserInfo": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"email": {
"type": "string"
},
"id": {
"type": "integer"
},
"last_login_at": {
"type": "string"
},
"last_login_ip": {
"type": "string"
},
"phone": {
"type": "string"
},
"roles": {
"type": "array",
"items": {
"$ref": "#/definitions/model.RoleInfo"
}
},
"status": {
"type": "integer"
},
"username": {
"type": "string"
}
}
},
"response.Response": {
"type": "object",
"properties": {
"code": {
"description": "响应状态码",
"type": "integer"
},
"data": {
"description": "响应数据"
},
"error": {
"description": "错误信息",
"type": "string"
},
"message": {
"description": "响应消息",
"type": "string"
}
}
}
},
"securityDefinitions": {
"BearerAuth": {
"description": "请输入 \"Bearer \" + JWT token,例如: \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"",
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
}
}`

773
gofaster/backend/docs/swagger.json

@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
"host": "localhost:8080",
"basePath": "/api",
"paths": {
"/users": {
"/auth/admin/users": {
"get": {
"description": "获取分页用户列表",
"consumes": [
@ -79,7 +79,7 @@ @@ -79,7 +79,7 @@
}
}
},
"/users/{id}": {
"/auth/admin/users/{id}": {
"get": {
"description": "根据ID获取用户详情",
"consumes": [
@ -257,9 +257,640 @@ @@ -257,9 +257,640 @@
}
}
}
},
"/auth/captcha": {
"get": {
"description": "生成图形验证码,用于登录验证",
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "生成验证码",
"responses": {
"200": {
"description": "验证码生成成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.CaptchaResponse"
}
}
}
]
}
}
}
}
},
"/auth/login": {
"post": {
"description": "用户登录接口,支持验证码验证和密码错误次数限制",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "用户登录",
"parameters": [
{
"description": "登录请求参数",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.LoginRequest"
}
}
],
"responses": {
"200": {
"description": "登录成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.LoginResponse"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"401": {
"description": "认证失败",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"423": {
"description": "账户被锁定",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/logout": {
"post": {
"description": "用户登出接口",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "用户登出",
"parameters": [
{
"description": "登出请求参数",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.LogoutRequest"
}
}
],
"responses": {
"200": {
"description": "登出成功",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/refresh": {
"post": {
"description": "使用刷新令牌获取新的访问令牌",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "刷新访问令牌",
"parameters": [
{
"description": "刷新令牌请求参数",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.RefreshTokenRequest"
}
}
],
"responses": {
"200": {
"description": "刷新成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.LoginResponse"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"401": {
"description": "刷新令牌无效",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/roles": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "分页获取角色列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "获取角色列表",
"parameters": [
{
"type": "integer",
"default": 1,
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"default": 10,
"description": "每页数量",
"name": "pageSize",
"in": "query"
}
],
"responses": {
"200": {
"description": "获取成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/model.Role"
}
},
"page": {
"type": "integer"
},
"size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
}
}
}
]
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "创建新的角色",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "创建角色",
"parameters": [
{
"description": "角色信息",
"name": "role",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.Role"
}
}
],
"responses": {
"200": {
"description": "创建成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.Role"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/roles/{id}": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据ID获取角色详细信息",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "获取角色详情",
"parameters": [
{
"type": "integer",
"description": "角色ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "获取成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.Role"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"404": {
"description": "角色不存在",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"put": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据ID更新角色信息",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "更新角色",
"parameters": [
{
"type": "integer",
"description": "角色ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "角色信息",
"name": "role",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.Role"
}
}
],
"responses": {
"200": {
"description": "更新成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.Role"
}
}
}
]
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"delete": {
"security": [
{
"BearerAuth": []
}
],
"description": "根据ID删除角色",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"角色管理"
],
"summary": "删除角色",
"parameters": [
{
"type": "integer",
"description": "角色ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "删除成功",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"400": {
"description": "请求参数错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "服务器内部错误",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/auth/userinfo": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"description": "获取当前登录用户的详细信息",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"认证"
],
"summary": "获取用户信息",
"responses": {
"200": {
"description": "获取成功",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.UserInfo"
}
}
}
]
}
},
"401": {
"description": "未授权",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
}
},
"definitions": {
"model.CaptchaResponse": {
"type": "object",
"properties": {
"captcha_id": {
"type": "string"
},
"captcha_image": {
"description": "Base64编码的图片",
"type": "string"
},
"expires_in": {
"type": "integer"
}
}
},
"model.LoginRequest": {
"type": "object",
"required": [
"captcha",
"captcha_id",
"password",
"username"
],
"properties": {
"captcha": {
"type": "string"
},
"captcha_id": {
"type": "string"
},
"client_ip": {
"description": "客户端IP地址",
"type": "string"
},
"password": {
"type": "string",
"maxLength": 100,
"minLength": 6
},
"username": {
"type": "string",
"maxLength": 50,
"minLength": 3
}
}
},
"model.LoginResponse": {
"type": "object",
"properties": {
"expires_in": {
"type": "integer"
},
"force_change_password": {
"description": "是否需要强制修改密码",
"type": "boolean"
},
"refresh_token": {
"type": "string"
},
"token": {
"type": "string"
},
"token_type": {
"type": "string"
},
"user": {
"$ref": "#/definitions/model.UserInfo"
}
}
},
"model.LogoutRequest": {
"type": "object",
"required": [
"token"
],
"properties": {
"token": {
"type": "string"
}
}
},
"model.Permission": {
"type": "object",
"properties": {
@ -287,9 +918,43 @@ @@ -287,9 +918,43 @@
}
}
},
"model.PermissionInfo": {
"type": "object",
"properties": {
"action": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"resource": {
"type": "string"
}
}
},
"model.RefreshTokenRequest": {
"type": "object",
"required": [
"refresh_token"
],
"properties": {
"refresh_token": {
"type": "string"
}
}
},
"model.Role": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"created_at": {
"type": "string"
},
@ -313,6 +978,29 @@ @@ -313,6 +978,29 @@
}
}
},
"model.RoleInfo": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"permissions": {
"type": "array",
"items": {
"$ref": "#/definitions/model.PermissionInfo"
}
}
}
},
"model.User": {
"type": "object",
"properties": {
@ -322,9 +1010,25 @@ @@ -322,9 +1010,25 @@
"email": {
"type": "string"
},
"force_change_password": {
"description": "是否强制修改密码",
"type": "boolean"
},
"id": {
"type": "integer"
},
"last_login_at": {
"description": "最后登录时间",
"type": "string"
},
"last_login_ip": {
"description": "最后登录IP",
"type": "string"
},
"password_changed_at": {
"description": "密码最后修改时间",
"type": "string"
},
"phone": {
"type": "string"
},
@ -335,7 +1039,7 @@ @@ -335,7 +1039,7 @@
}
},
"status": {
"description": "1-正常 2-禁用",
"description": "1-正常 2-禁用 3-锁定",
"type": "integer"
},
"updated_at": {
@ -345,6 +1049,69 @@ @@ -345,6 +1049,69 @@
"type": "string"
}
}
},
"model.UserInfo": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"email": {
"type": "string"
},
"id": {
"type": "integer"
},
"last_login_at": {
"type": "string"
},
"last_login_ip": {
"type": "string"
},
"phone": {
"type": "string"
},
"roles": {
"type": "array",
"items": {
"$ref": "#/definitions/model.RoleInfo"
}
},
"status": {
"type": "integer"
},
"username": {
"type": "string"
}
}
},
"response.Response": {
"type": "object",
"properties": {
"code": {
"description": "响应状态码",
"type": "integer"
},
"data": {
"description": "响应数据"
},
"error": {
"description": "错误信息",
"type": "string"
},
"message": {
"description": "响应消息",
"type": "string"
}
}
}
},
"securityDefinitions": {
"BearerAuth": {
"description": "请输入 \"Bearer \" + JWT token,例如: \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\"",
"type": "apiKey",
"name": "Authorization",
"in": "header"
}
}
}

485
gofaster/backend/docs/swagger.yaml

@ -1,5 +1,61 @@ @@ -1,5 +1,61 @@
basePath: /api
definitions:
model.CaptchaResponse:
properties:
captcha_id:
type: string
captcha_image:
description: Base64编码的图片
type: string
expires_in:
type: integer
type: object
model.LoginRequest:
properties:
captcha:
type: string
captcha_id:
type: string
client_ip:
description: 客户端IP地址
type: string
password:
maxLength: 100
minLength: 6
type: string
username:
maxLength: 50
minLength: 3
type: string
required:
- captcha
- captcha_id
- password
- username
type: object
model.LoginResponse:
properties:
expires_in:
type: integer
force_change_password:
description: 是否需要强制修改密码
type: boolean
refresh_token:
type: string
token:
type: string
token_type:
type: string
user:
$ref: '#/definitions/model.UserInfo'
type: object
model.LogoutRequest:
properties:
token:
type: string
required:
- token
type: object
model.Permission:
properties:
action:
@ -18,8 +74,30 @@ definitions: @@ -18,8 +74,30 @@ definitions:
updated_at:
type: string
type: object
model.PermissionInfo:
properties:
action:
type: string
description:
type: string
id:
type: integer
name:
type: string
resource:
type: string
type: object
model.RefreshTokenRequest:
properties:
refresh_token:
type: string
required:
- refresh_token
type: object
model.Role:
properties:
code:
type: string
created_at:
type: string
description:
@ -35,14 +113,41 @@ definitions: @@ -35,14 +113,41 @@ definitions:
updated_at:
type: string
type: object
model.RoleInfo:
properties:
code:
type: string
description:
type: string
id:
type: integer
name:
type: string
permissions:
items:
$ref: '#/definitions/model.PermissionInfo'
type: array
type: object
model.User:
properties:
created_at:
type: string
email:
type: string
force_change_password:
description: 是否强制修改密码
type: boolean
id:
type: integer
last_login_at:
description: 最后登录时间
type: string
last_login_ip:
description: 最后登录IP
type: string
password_changed_at:
description: 密码最后修改时间
type: string
phone:
type: string
roles:
@ -50,13 +155,50 @@ definitions: @@ -50,13 +155,50 @@ definitions:
$ref: '#/definitions/model.Role'
type: array
status:
description: 1-正常 2-禁用
description: 1-正常 2-禁用 3-锁定
type: integer
updated_at:
type: string
username:
type: string
type: object
model.UserInfo:
properties:
created_at:
type: string
email:
type: string
id:
type: integer
last_login_at:
type: string
last_login_ip:
type: string
phone:
type: string
roles:
items:
$ref: '#/definitions/model.RoleInfo'
type: array
status:
type: integer
username:
type: string
type: object
response.Response:
properties:
code:
description: 响应状态码
type: integer
data:
description: 响应数据
error:
description: 错误信息
type: string
message:
description: 响应消息
type: string
type: object
host: localhost:8080
info:
contact:
@ -71,7 +213,7 @@ info: @@ -71,7 +213,7 @@ info:
title: GoFaster API
version: "1.0"
paths:
/users:
/auth/admin/users:
get:
consumes:
- application/json
@ -110,7 +252,7 @@ paths: @@ -110,7 +252,7 @@ paths:
summary: 获取用户列表
tags:
- 用户管理
/users/{id}:
/auth/admin/users/{id}:
delete:
consumes:
- application/json
@ -229,6 +371,343 @@ paths: @@ -229,6 +371,343 @@ paths:
summary: 更新用户信息
tags:
- 用户管理
/auth/captcha:
get:
description: 生成图形验证码,用于登录验证
produces:
- application/json
responses:
"200":
description: 验证码生成成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.CaptchaResponse'
type: object
summary: 生成验证码
tags:
- 认证
/auth/login:
post:
consumes:
- application/json
description: 用户登录接口,支持验证码验证和密码错误次数限制
parameters:
- description: 登录请求参数
in: body
name: request
required: true
schema:
$ref: '#/definitions/model.LoginRequest'
produces:
- application/json
responses:
"200":
description: 登录成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.LoginResponse'
type: object
"400":
description: 请求参数错误
schema:
$ref: '#/definitions/response.Response'
"401":
description: 认证失败
schema:
$ref: '#/definitions/response.Response'
"423":
description: 账户被锁定
schema:
$ref: '#/definitions/response.Response'
summary: 用户登录
tags:
- 认证
/auth/logout:
post:
consumes:
- application/json
description: 用户登出接口
parameters:
- description: 登出请求参数
in: body
name: request
required: true
schema:
$ref: '#/definitions/model.LogoutRequest'
produces:
- application/json
responses:
"200":
description: 登出成功
schema:
$ref: '#/definitions/response.Response'
summary: 用户登出
tags:
- 认证
/auth/refresh:
post:
consumes:
- application/json
description: 使用刷新令牌获取新的访问令牌
parameters:
- description: 刷新令牌请求参数
in: body
name: request
required: true
schema:
$ref: '#/definitions/model.RefreshTokenRequest'
produces:
- application/json
responses:
"200":
description: 刷新成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.LoginResponse'
type: object
"400":
description: 请求参数错误
schema:
$ref: '#/definitions/response.Response'
"401":
description: 刷新令牌无效
schema:
$ref: '#/definitions/response.Response'
summary: 刷新访问令牌
tags:
- 认证
/auth/roles:
get:
consumes:
- application/json
description: 分页获取角色列表
parameters:
- default: 1
description: 页码
in: query
name: page
type: integer
- default: 10
description: 每页数量
in: query
name: pageSize
type: integer
produces:
- application/json
responses:
"200":
description: 获取成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
properties:
data:
items:
$ref: '#/definitions/model.Role'
type: array
page:
type: integer
size:
type: integer
total:
type: integer
type: object
type: object
"500":
description: 服务器内部错误
schema:
$ref: '#/definitions/response.Response'
security:
- BearerAuth: []
summary: 获取角色列表
tags:
- 角色管理
post:
consumes:
- application/json
description: 创建新的角色
parameters:
- description: 角色信息
in: body
name: role
required: true
schema:
$ref: '#/definitions/model.Role'
produces:
- application/json
responses:
"200":
description: 创建成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.Role'
type: object
"400":
description: 请求参数错误
schema:
$ref: '#/definitions/response.Response'
"500":
description: 服务器内部错误
schema:
$ref: '#/definitions/response.Response'
security:
- BearerAuth: []
summary: 创建角色
tags:
- 角色管理
/auth/roles/{id}:
delete:
consumes:
- application/json
description: 根据ID删除角色
parameters:
- description: 角色ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: 删除成功
schema:
$ref: '#/definitions/response.Response'
"400":
description: 请求参数错误
schema:
$ref: '#/definitions/response.Response'
"500":
description: 服务器内部错误
schema:
$ref: '#/definitions/response.Response'
security:
- BearerAuth: []
summary: 删除角色
tags:
- 角色管理
get:
consumes:
- application/json
description: 根据ID获取角色详细信息
parameters:
- description: 角色ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: 获取成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.Role'
type: object
"400":
description: 请求参数错误
schema:
$ref: '#/definitions/response.Response'
"404":
description: 角色不存在
schema:
$ref: '#/definitions/response.Response'
security:
- BearerAuth: []
summary: 获取角色详情
tags:
- 角色管理
put:
consumes:
- application/json
description: 根据ID更新角色信息
parameters:
- description: 角色ID
in: path
name: id
required: true
type: integer
- description: 角色信息
in: body
name: role
required: true
schema:
$ref: '#/definitions/model.Role'
produces:
- application/json
responses:
"200":
description: 更新成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.Role'
type: object
"400":
description: 请求参数错误
schema:
$ref: '#/definitions/response.Response'
"500":
description: 服务器内部错误
schema:
$ref: '#/definitions/response.Response'
security:
- BearerAuth: []
summary: 更新角色
tags:
- 角色管理
/auth/userinfo:
get:
consumes:
- application/json
description: 获取当前登录用户的详细信息
produces:
- application/json
responses:
"200":
description: 获取成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.UserInfo'
type: object
"401":
description: 未授权
schema:
$ref: '#/definitions/response.Response'
security:
- BearerAuth: []
summary: 获取用户信息
tags:
- 认证
schemes:
- http
securityDefinitions:
BearerAuth:
description: '请输入 "Bearer " + JWT token,例如: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."'
in: header
name: Authorization
type: apiKey
swagger: "2.0"

56
gofaster/backend/internal/auth/controller/role_controller.go

@ -22,6 +22,17 @@ func NewRoleController(roleService *service.RoleService) *RoleController { @@ -22,6 +22,17 @@ func NewRoleController(roleService *service.RoleService) *RoleController {
}
// CreateRole 创建角色
// @Summary 创建角色
// @Description 创建新的角色
// @Tags 角色管理
// @Accept json
// @Produce json
// @Param role body model.Role true "角色信息"
// @Success 200 {object} response.Response{data=model.Role} "创建成功"
// @Failure 400 {object} response.Response "请求参数错误"
// @Failure 500 {object} response.Response "服务器内部错误"
// @Security BearerAuth
// @Router /auth/roles [post]
func (c *RoleController) CreateRole(ctx *gin.Context) {
var role model.Role
if err := ctx.ShouldBindJSON(&role); err != nil {
@ -38,6 +49,18 @@ func (c *RoleController) CreateRole(ctx *gin.Context) { @@ -38,6 +49,18 @@ func (c *RoleController) CreateRole(ctx *gin.Context) {
}
// UpdateRole 更新角色
// @Summary 更新角色
// @Description 根据ID更新角色信息
// @Tags 角色管理
// @Accept json
// @Produce json
// @Param id path int true "角色ID"
// @Param role body model.Role true "角色信息"
// @Success 200 {object} response.Response{data=model.Role} "更新成功"
// @Failure 400 {object} response.Response "请求参数错误"
// @Failure 500 {object} response.Response "服务器内部错误"
// @Security BearerAuth
// @Router /auth/roles/{id} [put]
func (c *RoleController) UpdateRole(ctx *gin.Context) {
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
@ -63,6 +86,17 @@ func (c *RoleController) UpdateRole(ctx *gin.Context) { @@ -63,6 +86,17 @@ func (c *RoleController) UpdateRole(ctx *gin.Context) {
}
// DeleteRole 删除角色
// @Summary 删除角色
// @Description 根据ID删除角色
// @Tags 角色管理
// @Accept json
// @Produce json
// @Param id path int true "角色ID"
// @Success 200 {object} response.Response "删除成功"
// @Failure 400 {object} response.Response "请求参数错误"
// @Failure 500 {object} response.Response "服务器内部错误"
// @Security BearerAuth
// @Router /auth/roles/{id} [delete]
func (c *RoleController) DeleteRole(ctx *gin.Context) {
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
@ -80,6 +114,17 @@ func (c *RoleController) DeleteRole(ctx *gin.Context) { @@ -80,6 +114,17 @@ func (c *RoleController) DeleteRole(ctx *gin.Context) {
}
// GetRole 获取角色详情
// @Summary 获取角色详情
// @Description 根据ID获取角色详细信息
// @Tags 角色管理
// @Accept json
// @Produce json
// @Param id path int true "角色ID"
// @Success 200 {object} response.Response{data=model.Role} "获取成功"
// @Failure 400 {object} response.Response "请求参数错误"
// @Failure 404 {object} response.Response "角色不存在"
// @Security BearerAuth
// @Router /auth/roles/{id} [get]
func (c *RoleController) GetRole(ctx *gin.Context) {
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
@ -98,6 +143,17 @@ func (c *RoleController) GetRole(ctx *gin.Context) { @@ -98,6 +143,17 @@ func (c *RoleController) GetRole(ctx *gin.Context) {
}
// ListRoles 获取角色列表
// @Summary 获取角色列表
// @Description 分页获取角色列表
// @Tags 角色管理
// @Accept json
// @Produce json
// @Param page query int false "页码" default(1)
// @Param pageSize query int false "每页数量" default(10)
// @Success 200 {object} response.Response{data=object{data=[]model.Role,page=int,size=int,total=int}} "获取成功"
// @Failure 500 {object} response.Response "服务器内部错误"
// @Security BearerAuth
// @Router /auth/roles [get]
func (c *RoleController) ListRoles(ctx *gin.Context) {
pageStr := ctx.DefaultQuery("page", "1")
pageSizeStr := ctx.DefaultQuery("pageSize", "10")

55
gofaster/backend/internal/auth/controller/user_controller.go

@ -33,7 +33,7 @@ func NewUserController(userService *service.UserService) *UserController { @@ -33,7 +33,7 @@ func NewUserController(userService *service.UserService) *UserController {
// @Success 200 {object} map[string]interface{} "用户列表"
// @Failure 400 {object} map[string]string "请求参数错误"
// @Failure 500 {object} map[string]string "服务器内部错误"
// @Router /users [get]
// @Router /auth/admin/users [get]
func (c *UserController) ListUsers(ctx *gin.Context) {
// 获取分页参数,默认值 page=1, pageSize=10
pageStr := ctx.DefaultQuery("page", "1")
@ -77,7 +77,7 @@ func (c *UserController) ListUsers(ctx *gin.Context) { @@ -77,7 +77,7 @@ func (c *UserController) ListUsers(ctx *gin.Context) {
// @Success 201 {object} model.User "创建的用户信息"
// @Failure 400 {object} map[string]string "请求参数错误"
// @Failure 500 {object} map[string]string "服务器内部错误"
// @Router /users [post]
// @Router /auth/admin/users [post]
func (c *UserController) CreateUser(ctx *gin.Context) {
var user model.User
@ -105,7 +105,7 @@ func (c *UserController) CreateUser(ctx *gin.Context) { @@ -105,7 +105,7 @@ func (c *UserController) CreateUser(ctx *gin.Context) {
// @Failure 400 {object} map[string]string "无效的用户ID"
// @Failure 404 {object} map[string]string "用户不存在"
// @Failure 500 {object} map[string]string "服务器内部错误"
// @Router /users/{id} [get]
// @Router /auth/admin/users/{id} [get]
func (c *UserController) GetUser(ctx *gin.Context) {
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
@ -139,7 +139,7 @@ func (c *UserController) GetUser(ctx *gin.Context) { @@ -139,7 +139,7 @@ func (c *UserController) GetUser(ctx *gin.Context) {
// @Failure 400 {object} map[string]string "无效的用户ID或请求参数"
// @Failure 404 {object} map[string]string "用户不存在"
// @Failure 500 {object} map[string]string "服务器内部错误"
// @Router /users/{id} [put]
// @Router /auth/admin/users/{id} [put]
func (c *UserController) UpdateUser(ctx *gin.Context) {
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
@ -183,7 +183,7 @@ func (c *UserController) UpdateUser(ctx *gin.Context) { @@ -183,7 +183,7 @@ func (c *UserController) UpdateUser(ctx *gin.Context) {
// @Failure 400 {object} map[string]string "无效的用户ID"
// @Failure 404 {object} map[string]string "用户不存在"
// @Failure 500 {object} map[string]string "服务器内部错误"
// @Router /users/{id} [delete]
// @Router /auth/admin/users/{id} [delete]
func (c *UserController) DeleteUser(ctx *gin.Context) {
idStr := ctx.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
@ -203,48 +203,3 @@ func (c *UserController) DeleteUser(ctx *gin.Context) { @@ -203,48 +203,3 @@ func (c *UserController) DeleteUser(ctx *gin.Context) {
response.Success(ctx, "用户删除成功", nil)
}
// GetRoles godoc
// @Summary 获取角色列表
// @Description 获取分页角色列表
// @Tags 用户管理
// @Accept json
// @Produce json
// @Param page query int false "页码" default(1)
// @Param pageSize query int false "每页数量" default(100)
// @Success 200 {object} map[string]interface{} "角色列表"
// @Failure 400 {object} map[string]string "请求参数错误"
// @Failure 500 {object} map[string]string "服务器内部错误"
// @Router /roles [get]
func (c *UserController) GetRoles(ctx *gin.Context) {
// 获取分页参数,默认值 page=1, pageSize=100
pageStr := ctx.DefaultQuery("page", "1")
pageSizeStr := ctx.DefaultQuery("pageSize", "100")
page, err := strconv.Atoi(pageStr)
if err != nil || page < 1 {
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "无效的页码参数")
return
}
pageSize, err := strconv.Atoi(pageSizeStr)
if err != nil || pageSize < 1 || pageSize > 1000 {
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "无效的每页大小参数,范围1-1000")
return
}
// 调用服务层获取角色列表
roles, total, err := c.userService.GetRoles(ctx.Request.Context(), page, pageSize)
if err != nil {
response.Error(ctx, http.StatusInternalServerError, "获取角色列表失败", err.Error())
return
}
// 返回分页结果
response.Success(ctx, "获取角色列表成功", gin.H{
"data": roles,
"total": total,
"page": page,
"size": pageSize,
})
}

4
gofaster/backend/internal/auth/routes/auth_routes.go

@ -61,14 +61,13 @@ func RegisterAuthRoutes(router *gin.RouterGroup, db *gorm.DB, jwtSecret string) @@ -61,14 +61,13 @@ func RegisterAuthRoutes(router *gin.RouterGroup, db *gorm.DB, jwtSecret string)
// 管理员路由
admin := router.Group("/auth/admin")
admin.Use(middleware.JWTAuth(), middleware.Permission("auth", "admin"))
admin.Use(middleware.JWTAuth(), middleware.PermissionMiddleware(db, "auth", "admin"))
{
admin.GET("/users", userController.ListUsers)
admin.POST("/users", userController.CreateUser)
admin.GET("/users/:id", userController.GetUser)
admin.PUT("/users/:id", userController.UpdateUser)
admin.DELETE("/users/:id", userController.DeleteUser)
admin.GET("/roles", userController.GetRoles)
admin.POST("/users/:id/reset-password", passwordController.ResetPassword)
admin.PUT("/password-policy", passwordController.UpdatePasswordPolicy)
}
@ -78,7 +77,6 @@ func RegisterAuthRoutes(router *gin.RouterGroup, db *gorm.DB, jwtSecret string) @@ -78,7 +77,6 @@ func RegisterAuthRoutes(router *gin.RouterGroup, db *gorm.DB, jwtSecret string)
testAdmin.Use(middleware.JWTAuth()) // 只检查JWT,不检查权限
{
testAdmin.GET("/users", userController.ListUsers)
testAdmin.GET("/roles", userController.GetRoles)
}
// 注册资源管理路由

16
gofaster/backend/internal/auth/routes/role_routes.go

@ -16,11 +16,21 @@ func RegisterRoleRoutes(router *gin.RouterGroup, db *gorm.DB, jwtSecret string) @@ -16,11 +16,21 @@ func RegisterRoleRoutes(router *gin.RouterGroup, db *gorm.DB, jwtSecret string)
roleService := service.NewRoleService(roleRepo)
roleController := controller.NewRoleController(roleService)
// 角色管理路由组
roleGroup := router.Group("/roles")
// 角色管理路由组 - 修复路径配置
roleGroup := router.Group("/auth/roles")
{
// 临时测试路由 - 不需要认证
testGroup := roleGroup.Group("/test")
{
testGroup.GET("", roleController.ListRoles) // 获取角色列表
testGroup.POST("", roleController.CreateRole) // 创建角色
testGroup.GET("/:id", roleController.GetRole) // 获取角色详情
testGroup.PUT("/:id", roleController.UpdateRole) // 更新角色
testGroup.DELETE("/:id", roleController.DeleteRole) // 删除角色
}
// 需要权限验证的路由
roleGroup.Use(middleware.AuthMiddleware(jwtSecret))
roleGroup.Use(middleware.JWTAuth())
{
// 角色CRUD操作
roleGroup.GET("", roleController.ListRoles) // 获取角色列表

23
gofaster/backend/internal/auth/service/init_service.go

@ -14,11 +14,11 @@ import ( @@ -14,11 +14,11 @@ import (
type InitService struct {
db *gorm.DB
userRepo repository.UserRepository
roleRepo *repository.RoleRepo
permissionRepo *repository.PermissionRepo
roleRepo repository.RoleRepository
permissionRepo repository.PermissionRepository
}
func NewInitService(db *gorm.DB, userRepo repository.UserRepository, roleRepo *repository.RoleRepo, permissionRepo *repository.PermissionRepo) *InitService {
func NewInitService(db *gorm.DB, userRepo repository.UserRepository, roleRepo repository.RoleRepository, permissionRepo repository.PermissionRepository) *InitService {
return &InitService{
db: db,
userRepo: userRepo,
@ -48,8 +48,10 @@ func (s *InitService) InitSystem() error { @@ -48,8 +48,10 @@ func (s *InitService) InitSystem() error {
// initAdminRole 初始化超级管理员角色
func (s *InitService) initAdminRole() (*model.Role, error) {
ctx := context.Background()
// 检查角色是否已存在
role, err := s.roleRepo.FindByName("sysadmin")
role, err := s.roleRepo.GetByCode(ctx, "sysadmin")
if err == nil {
return role, nil
}
@ -63,18 +65,23 @@ func (s *InitService) initAdminRole() (*model.Role, error) { @@ -63,18 +65,23 @@ func (s *InitService) initAdminRole() (*model.Role, error) {
Description: "系统超级管理员,拥有所有权限",
}
if err := s.roleRepo.Create(adminRole); err != nil {
if err := s.roleRepo.Create(ctx, adminRole); err != nil {
return nil, err
}
// 获取所有权限
var permissions []model.Permission
if err := s.permissionRepo.FindAll(&permissions); err != nil {
permissions, _, err := s.permissionRepo.List(ctx, 0, 1000)
if err != nil {
return nil, err
}
// 为角色分配所有权限
if err := s.roleRepo.AssignPermissions(adminRole.ID, permissions); err != nil {
var permissionIDs []uint
for _, perm := range permissions {
permissionIDs = append(permissionIDs, perm.ID)
}
if err := s.roleRepo.AssignPermissions(ctx, adminRole.ID, permissionIDs); err != nil {
return nil, err
}

2
gofaster/backend/internal/auth/service/permission_service.go

@ -63,7 +63,7 @@ func (s *PermissionService) UpdatePermission(ctx context.Context, permission *mo @@ -63,7 +63,7 @@ func (s *PermissionService) UpdatePermission(ctx context.Context, permission *mo
// DeletePermission 删除权限
func (s *PermissionService) DeletePermission(ctx context.Context, id uint) error {
// 检查权限是否存在
existing, err := s.permissionRepo.GetByID(ctx, id)
_, err := s.permissionRepo.GetByID(ctx, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("权限不存在")

2
gofaster/backend/internal/auth/service/role_service.go

@ -61,7 +61,7 @@ func (s *RoleService) UpdateRole(ctx context.Context, role *model.Role) error { @@ -61,7 +61,7 @@ func (s *RoleService) UpdateRole(ctx context.Context, role *model.Role) error {
// DeleteRole 删除角色
func (s *RoleService) DeleteRole(ctx context.Context, id uint) error {
// 检查角色是否存在
existing, err := s.roleRepo.GetByID(ctx, id)
_, err := s.roleRepo.GetByID(ctx, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("角色不存在")

17
gofaster/backend/internal/auth/service/user_service.go

@ -53,20 +53,3 @@ func (s *UserService) Update(user *model.User) error { @@ -53,20 +53,3 @@ func (s *UserService) Update(user *model.User) error {
ctx := context.Background()
return s.repo.Update(ctx, user)
}
// GetRoles 获取角色列表
func (s *UserService) GetRoles(ctx context.Context, page, pageSize int) ([]*model.Role, int64, error) {
roleRepo := repository.NewRoleRepo(s.db)
roles, total, err := roleRepo.List(page, pageSize)
if err != nil {
return nil, 0, err
}
// 转换类型
var rolePtrs []*model.Role
for i := range roles {
rolePtrs = append(rolePtrs, &roles[i])
}
return rolePtrs, total, nil
}

2
gofaster/backend/internal/shared/middleware/jwt_middleware.go

@ -37,7 +37,7 @@ func JWTAuth() gin.HandlerFunc { @@ -37,7 +37,7 @@ func JWTAuth() gin.HandlerFunc {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// 返回密钥
// 返回密钥 - 使用配置中的密钥
return []byte("your-secret-key"), nil
})

BIN
gofaster/backend/main.exe

Binary file not shown.

29
gofaster/backend/main.go

@ -13,6 +13,11 @@ @@ -13,6 +13,11 @@
// @host localhost:8080
// @BasePath /api
// @schemes http
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
// @description 请输入 "Bearer " + JWT token,例如: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
package main
import (
@ -22,6 +27,7 @@ import ( @@ -22,6 +27,7 @@ import (
"gofaster/internal/shared/database"
"gofaster/internal/shared/logger"
"gofaster/internal/shared/middleware"
"net/http"
"time"
// 导入各模块
@ -118,8 +124,27 @@ func main() { @@ -118,8 +124,27 @@ func main() {
})
})
// Swagger路由
app.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
// Swagger路由配置
app.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler,
ginSwagger.URL("http://localhost:8080/swagger/doc.json"),
ginSwagger.DefaultModelsExpandDepth(-1),
))
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")
})
// 自定义Swagger UI页面
app.GET("/swagger-ui", func(c *gin.Context) {
c.File("./swagger-ui.html")
})
// 修复版本的Swagger UI页面(确保Authorize按钮显示)
app.GET("/swagger-ui-fixed", func(c *gin.Context) {
c.File("./swagger-ui-fixed.html")
})
// 启动服务器
log.Info("Starting server", zap.String("port", cfg.Server.Port))

73
gofaster/backend/swagger-ui-fixed.html

@ -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>

2
gofaster/backend/tmp/build-errors.log

@ -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

BIN
gofaster/backend/tmp/main.exe

Binary file not shown.

2
gofaster/dev-full.ps1

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
-3# GoFaster Full Stack Development Environment
# GoFaster Full Stack Development Environment
param(
[switch]$Debug,
[switch]$Watch,

118
gofaster/diagnose-swagger.ps1

@ -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

1
gofaster/start-backend-only.ps1

@ -0,0 +1 @@ @@ -0,0 +1 @@

99
gofaster/test-backend.ps1

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
# 后端服务测试脚本
param(
[switch]$StartBackend
)
Write-Host "🔍 后端服务诊断工具" -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 5
try {
$response = Invoke-WebRequest -Uri "http://localhost:8080/health" -TimeoutSec 5 -ErrorAction Stop
Write-Host "✅ 后端服务启动成功" -ForegroundColor Green
} catch {
Write-Host "❌ 后端服务启动失败" -ForegroundColor Red
}
}
}
Write-Host ""
# 测试API路由
Write-Host "🔍 测试API路由..." -ForegroundColor Yellow
$testRoutes = @(
@{Path="/api/auth/roles/test"; Method="GET"; Name="角色列表(测试)"},
@{Path="/api/auth/roles"; Method="GET"; Name="角色列表(正式)"},
@{Path="/api/auth/login"; Method="POST"; Name="登录接口"},
@{Path="/api/auth/captcha"; Method="GET"; Name="验证码接口"}
)
foreach ($route in $testRoutes) {
try {
$uri = "http://localhost:8080$($route.Path)"
if ($route.Method -eq "GET") {
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 3 -ErrorAction Stop
} else {
$response = Invoke-WebRequest -Uri $uri -Method $route.Method -TimeoutSec 3 -ErrorAction Stop
}
$statusColor = if ($response.StatusCode -eq 200) { "Green" } else { "Yellow" }
Write-Host "$($route.Name): $($response.StatusCode)" -ForegroundColor $statusColor
} catch {
$errorMsg = if ($_.Exception.Response) {
"HTTP $($_.Exception.Response.StatusCode)"
} else {
$_.Exception.Message
}
Write-Host "$($route.Name): $errorMsg" -ForegroundColor Red
}
}
Write-Host ""
# 检查数据库连接
Write-Host "🗄 检查数据库配置..." -ForegroundColor Yellow
if (Test-Path "backend/config.yaml") {
Write-Host "✅ 配置文件存在" -ForegroundColor Green
$config = Get-Content "backend/config.yaml" -Raw
if ($config -match "database") {
Write-Host "✅ 数据库配置存在" -ForegroundColor Green
} else {
Write-Host " 数据库配置可能不完整" -ForegroundColor Yellow
}
} else {
Write-Host "❌ 配置文件不存在" -ForegroundColor Red
}
Write-Host ""
# 显示可用的测试命令
Write-Host "💡 可用的测试命令:" -ForegroundColor Cyan
Write-Host " .\test-backend.ps1 -StartBackend # 启动后端服务并测试" -ForegroundColor White
Write-Host " curl http://localhost:8080/api/auth/roles/test # 测试角色API" -ForegroundColor White
Write-Host " curl http://localhost:8080/health # 检查服务健康状态" -ForegroundColor White
Write-Host ""
Write-Host "🔧 故障排除建议:" -ForegroundColor Cyan
Write-Host " 1. 确保后端服务正在运行" -ForegroundColor White
Write-Host " 2. 检查端口8080是否被占用" -ForegroundColor White
Write-Host " 3. 检查数据库连接配置" -ForegroundColor White
Write-Host " 4. 查看后端日志文件" -ForegroundColor White
Write-Host " 5. 确保所有依赖已安装" -ForegroundColor White

128
gofaster/test-swagger-auth.ps1

@ -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

157
gofaster/test-swagger.ps1

@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
# 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路由
Write-Host "🔍 测试Swagger路由..." -ForegroundColor Yellow
$swaggerRoutes = @(
@{Path="/swagger/index.html"; Name="Swagger UI"},
@{Path="/docs"; Name="文档重定向"},
@{Path="/api-docs"; Name="API文档重定向"}
)
foreach ($route in $swaggerRoutes) {
try {
$uri = "http://localhost:8080$($route.Path)"
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 3 -ErrorAction Stop
$statusColor = if ($response.StatusCode -eq 200) { "Green" } else { "Yellow" }
Write-Host "$($route.Name): $($response.StatusCode)" -ForegroundColor $statusColor
} catch {
$errorMsg = if ($_.Exception.Response) {
"HTTP $($_.Exception.Response.StatusCode)"
} else {
$_.Exception.Message
}
Write-Host "$($route.Name): $errorMsg" -ForegroundColor Red
}
}
Write-Host ""
# 测试API路由(无需认证)
Write-Host "🔍 测试无需认证的API路由..." -ForegroundColor Yellow
$publicRoutes = @(
@{Path="/api/auth/roles/test"; Method="GET"; Name="角色列表(测试)"},
@{Path="/api/auth/captcha"; Method="GET"; Name="验证码接口"},
@{Path="/api/auth/login"; Method="POST"; Name="登录接口"}
)
foreach ($route in $publicRoutes) {
try {
$uri = "http://localhost:8080$($route.Path)"
if ($route.Method -eq "GET") {
$response = Invoke-WebRequest -Uri $uri -TimeoutSec 3 -ErrorAction Stop
} else {
$response = Invoke-WebRequest -Uri $uri -Method $route.Method -TimeoutSec 3 -ErrorAction Stop
}
$statusColor = if ($response.StatusCode -eq 200) { "Green" } else { "Yellow" }
Write-Host "$($route.Name): $($response.StatusCode)" -ForegroundColor $statusColor
} catch {
$errorMsg = if ($_.Exception.Response) {
"HTTP $($_.Exception.Response.StatusCode)"
} else {
$_.Exception.Message
}
Write-Host "$($route.Name): $errorMsg" -ForegroundColor Red
}
}
Write-Host ""
# 测试需要认证的API路由
Write-Host "🔍 测试需要认证的API路由..." -ForegroundColor Yellow
$protectedRoutes = @(
@{Path="/api/auth/roles"; Method="GET"; Name="角色列表(正式)"},
@{Path="/api/auth/roles"; Method="POST"; Name="创建角色"},
@{Path="/api/auth/roles/1"; Method="GET"; Name="获取角色详情"}
)
foreach ($route in $protectedRoutes) {
try {
$uri = "http://localhost:8080$($route.Path)"
$headers = @{}
if ($route.Method -eq "GET") {
$response = Invoke-WebRequest -Uri $uri -Headers $headers -TimeoutSec 3 -ErrorAction Stop
} else {
$response = Invoke-WebRequest -Uri $uri -Method $route.Method -Headers $headers -TimeoutSec 3 -ErrorAction Stop
}
Write-Host " $($route.Name): $($response.StatusCode) (应该返回401)" -ForegroundColor Yellow
} catch {
if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 401) {
Write-Host "$($route.Name): 401 (正确返回未认证)" -ForegroundColor Green
} else {
$errorMsg = if ($_.Exception.Response) {
"HTTP $($_.Exception.Response.StatusCode)"
} else {
$_.Exception.Message
}
Write-Host "$($route.Name): $errorMsg" -ForegroundColor Red
}
}
}
Write-Host ""
# 显示访问信息
Write-Host "💡 访问信息:" -ForegroundColor Cyan
Write-Host " Swagger UI: http://localhost:8080/swagger/index.html" -ForegroundColor White
Write-Host " 文档重定向: http://localhost:8080/docs" -ForegroundColor White
Write-Host " API文档: http://localhost:8080/api-docs" -ForegroundColor White
Write-Host ""
Write-Host "🔧 身份验证说明:" -ForegroundColor Cyan
Write-Host " 1. 在Swagger UI中点击右上角的 'Authorize' 按钮" -ForegroundColor White
Write-Host " 2. 输入格式: Bearer <your-jwt-token>" -ForegroundColor White
Write-Host " 3. 先调用登录接口获取token" -ForegroundColor White
Write-Host " 4. 然后就可以测试需要认证的API了" -ForegroundColor White
Write-Host ""
Write-Host "🎯 测试步骤:" -ForegroundColor Cyan
Write-Host " 1. 访问 http://localhost:8080/swagger/index.html" -ForegroundColor White
Write-Host " 2. 测试 /api/auth/captcha 获取验证码" -ForegroundColor White
Write-Host " 3. 测试 /api/auth/login 进行登录" -ForegroundColor White
Write-Host " 4. 复制返回的access_token" -ForegroundColor White
Write-Host " 5. 点击 'Authorize' 输入: Bearer <token>" -ForegroundColor White
Write-Host " 6. 测试角色管理相关API" -ForegroundColor White
Loading…
Cancel
Save