# Star-Go-APP **Repository Path**: chenwm-star/star-go-app ## Basic Information - **Project Name**: Star-Go-APP - **Description**: Star-Go-App 是一个基于 Go 语言和 Gin 框架构建的现代化企业级 Web API 应用程序,采用模块化分层架构设计,内置完整的项目管理工具和企业级认证授权系统,提供开箱即用的用户管理、权限控制、数据库管理、缓存系统、日志记录等功能。 - **Primary Language**: Go - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-05-30 - **Last Updated**: 2025-05-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: Go语言, Google, Gin, 鉴权 ## README # Star-Go-App 企业级模块化Web API框架 ## 🌟 项目概述 Star-Go-App 是一个基于 Go 语言和 Gin 框架构建的现代化企业级 Web API 应用程序,采用**模块化分层架构**设计,内置**完整的项目管理工具**和**企业级认证授权系统**,提供开箱即用的用户管理、权限控制、数据库管理、缓存系统、日志记录等功能。 ## 🚀 项目特点 ### ✨ 核心特性 - 🏗️ **模块化架构**: 插件式模块设计,支持快速扩展和热插拔 - 🛠️ **项目管理工具**: 内置命令行管理工具,支持数据库迁移、用户管理、应用创建 - 🔐 **企业级认证**: 完整的JWT认证体系,支持角色权限控制 - 📊 **数据库管理**: 基于GORM的自动迁移和管理 - 🎯 **分层架构**: Controllers → Services → Repositories → Models 清晰分层 - 🔄 **自动注册**: 模块自动发现和注册机制 - 📝 **完整日志**: 基于Zap的高性能日志系统 - ⚡ **高性能缓存**: 支持Redis和内存缓存 ### 🎯 适用场景 - 🏢 企业级后台管理系统 - 🔗 微服务API网关 - 📱 移动应用后端服务 - 🌐 SaaS平台基础架构 - 🛒 电商平台API服务 ## 📋 技术栈 | 组件 | 技术选型 | 版本 | |------|----------|------| | **Web框架** | Gin | v1.10.0 | | **数据库ORM** | GORM | v1.25.12 | | **数据库** | MySQL | 8.0+ | | **缓存** | Redis | 6.0+ | | **配置管理** | Viper | v1.19.0 | | **日志系统** | Zap + Lumberjack | v1.27.0 | | **JWT认证** | golang-jwt/jwt/v5 | v5.2.1 | | **密码加密** | golang.org/x/crypto | latest | | **命令行工具** | Cobra | latest | ## 🏗️ 项目架构 ### 完整目录结构 ``` star-go-app/ ├── main.go # 🚀 应用程序入口 ├── config.yaml # ⚙️ 配置文件 ├── manage.bat # 🔧 Windows管理脚本 ├── manage.sh # 🔧 Linux/Mac管理脚本 ├── cmd/ # 📟 命令行工具 │ └── manage.go # 项目管理工具主程序 ├── scripts/ # 📜 脚本文件 │ └── quick_commands.bat # 快捷操作菜单 ├── internal/ # 🏠 内部应用代码 │ ├── apps/ # 📦 应用模块 │ │ ├── apps.go # 应用注册与管理 │ │ └── auth/ # 🔐 认证模块 │ │ ├── module.go # 模块定义 │ │ ├── routes.go # 路由注册 │ │ ├── controllers/ # 🎮 控制器层 │ │ ├── services/ # 🔧 业务逻辑层 │ │ ├── repositories/ # 📂 数据访问层 │ │ ├── models/ # 📋 数据模型层 │ │ └── serializers/ # 🔄 序列化层 │ ├── domain/ # 🏛️ 领域层 │ │ └── entities/ # 实体定义 │ └── router/ # 🛣️ 路由管理 │ └── registry.go # 模块注册器 ├── pkg/ # 📚 可复用包 │ ├── core/ # ⚡ 核心功能 │ │ ├── app.go # 应用核心 │ │ └── init.go # 初始化逻辑 │ ├── infra/ # 🏭 基础设施层 │ │ ├── cache/ # 💾 缓存管理 │ │ ├── config/ # ⚙️ 配置管理 │ │ ├── database/ # 🗄️ 数据库连接与迁移 │ │ └── logger/ # 📝 日志系统 │ ├── middleware/ # 🔀 中间件 │ └── common/ # 🛠️ 通用工具 │ └── utils/ # 工具函数 └── resources/ # 📁 资源文件 └── logs/ # 日志文件目录 ``` ### 架构设计原则 #### 🎯 分层架构 ``` ┌─────────────────┐ │ Controllers │ ← HTTP请求处理、参数验证、响应返回 ├─────────────────┤ │ Services │ ← 业务逻辑处理、规则验证、事务管理 ├─────────────────┤ │ Repositories │ ← 数据访问、数据库操作、缓存管理 ├─────────────────┤ │ Models │ ← 数据模型、实体定义、关系映射 └─────────────────┘ ``` #### 🔧 模块化设计 - **独立模块**: 每个功能模块完全独立,可单独开发和测试 - **统一接口**: 所有模块实现 `Module` 接口 - **自动注册**: 通过 `INSTALLED_APPS` 配置自动发现和注册 - **热插拔**: 支持模块的动态加载和卸载 ## 🗄️ 数据模型设计 ### 基础模型 BaseModel 所有业务模型都继承自 `BaseModel`,提供通用字段和方法: ```go // internal/domain/entities/base_model/base_model.go type BaseModel struct { ID uint64 `gorm:"primarykey" json:"id"` // 主键ID CreatedAt time.Time `json:"created_at"` // 创建时间 UpdatedAt time.Time `json:"updated_at"` // 更新时间 DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 删除时间(软删除) } // 通用状态常量 const ( StatusActive = 1 // 活跃 StatusInactive = 0 // 非活跃 StatusBanned = -1 // 已禁用 ) ``` ### 用户模型 User ```go // internal/apps/auth/models/user.go type User struct { base_model.BaseModel // 继承基础模型 Username string `gorm:"size:50;uniqueIndex;not null" json:"username"` // 用户名 Password string `gorm:"size:100;not null" json:"-"` // 密码 Email string `gorm:"size:100;uniqueIndex;not null" json:"email"` // 邮箱 Phone string `gorm:"size:20" json:"phone"` // 电话 Nickname string `gorm:"size:50" json:"nickname"` // 昵称 IsSuperuser bool `gorm:"default:false" json:"is_superuser"` // 是否是超级管理员 RoleID uint `gorm:"default:3" json:"role_id"` // 角色ID Role *Role `gorm:"foreignKey:RoleID" json:"role,omitempty"` // 角色关联 Status int `gorm:"default:1" json:"status"` // 状态 LastLogin *time.Time `json:"last_login"` // 最后登录时间 } func (User) TableName() string { return "star_users" } ``` ### 角色模型 Role ```go // internal/apps/auth/models/role.go type Role struct { base_model.BaseModel Name string `gorm:"size:50;uniqueIndex;not null" json:"name"` // 角色名称 Code string `gorm:"size:50;uniqueIndex;not null" json:"code"` // 角色编码 Description string `gorm:"size:200" json:"description"` // 角色描述 Permissions Permissions `gorm:"type:json" json:"permissions"` // 角色权限 } // 自定义权限类型,支持JSON序列化 type Permissions []string func (p *Permissions) Scan(value any) error { bytes, ok := value.([]byte) if !ok { return errors.New("类型断言为[]byte失败") } return json.Unmarshal(bytes, p) } func (p Permissions) Value() (driver.Value, error) { return json.Marshal(p) } ``` ### 数据库关系设计 ``` ┌─────────────────┐ ┌─────────────────┐ │ Users │ │ Roles │ ├─────────────────┤ ├─────────────────┤ │ id (PK) │ │ id (PK) │ │ username (UK) │ ──→ │ name (UK) │ │ email (UK) │ │ code (UK) │ │ role_id (FK) │ │ permissions │ │ is_superuser │ │ description │ │ status │ └─────────────────┘ │ last_login │ └─────────────────┘ ┌─────────────────┐ │ Token Sessions │ ├─────────────────┤ │ id (PK) │ │ user_id (FK) │ ──→ Users │ refresh_token │ │ expires_at │ │ device_info │ └─────────────────┘ ``` ## 🏗️ 四层架构模板 ### 📋 1. Model 层 (数据模型层) **职责**: 定义数据结构、数据库关系、业务实体 ```go // internal/apps/blog/models/article.go package models import ( "star-go-app/internal/domain/entities/base_model" ) // Article 文章模型示例 type Article struct { base_model.BaseModel Title string `gorm:"size:200;not null" json:"title"` // 文章标题 Content string `gorm:"type:text" json:"content"` // 文章内容 Summary string `gorm:"size:500" json:"summary"` // 文章摘要 AuthorID uint64 `gorm:"not null" json:"author_id"` // 作者ID Author *User `gorm:"foreignKey:AuthorID" json:"author"` // 作者关联 CategoryID uint `gorm:"not null" json:"category_id"` // 分类ID Category *Category `gorm:"foreignKey:CategoryID" json:"category"` // 分类关联 Status int `gorm:"default:1" json:"status"` // 状态:1发布 0草稿 ViewCount int `gorm:"default:0" json:"view_count"` // 浏览次数 PublishedAt *time.Time `json:"published_at"` // 发布时间 } func (Article) TableName() string { return "blog_articles" } // 业务方法 func (a *Article) IsPublished() bool { return a.Status == 1 && a.PublishedAt != nil } func (a *Article) CanEditBy(userID uint64) bool { return a.AuthorID == userID } ``` ### 📦 2. Repository 层 (数据访问层) **职责**: 数据库操作、缓存管理、数据持久化 ```go // internal/apps/blog/repositories/article_repository.go package repositories import ( "star-go-app/internal/apps/blog/models" "star-go-app/pkg/infra/database" "gorm.io/gorm" ) // ArticleRepository 文章仓储接口 type ArticleRepository interface { // 基础CRUD Create(article *models.Article) error GetByID(id uint64) (*models.Article, error) Update(article *models.Article) error Delete(id uint64) error // 业务查询 GetPublishedList(offset, limit int) ([]*models.Article, int64, error) GetByAuthor(authorID uint64, offset, limit int) ([]*models.Article, int64, error) GetByCategory(categoryID uint, offset, limit int) ([]*models.Article, int64, error) // 统计查询 CountByAuthor(authorID uint64) (int64, error) IncrementViewCount(id uint64) error } // articleRepository 文章仓储实现 type articleRepository struct { db *gorm.DB } func NewArticleRepository() ArticleRepository { return &articleRepository{ db: database.GetDB(), } } // Create 创建文章 func (r *articleRepository) Create(article *models.Article) error { return r.db.Create(article).Error } // GetByID 根据ID获取文章 func (r *articleRepository) GetByID(id uint64) (*models.Article, error) { var article models.Article err := r.db.Preload("Author").Preload("Category").First(&article, id).Error if err != nil { return nil, err } return &article, nil } // GetPublishedList 获取已发布文章列表 func (r *articleRepository) GetPublishedList(offset, limit int) ([]*models.Article, int64, error) { var articles []*models.Article var total int64 // 查询条件:已发布且未删除 query := r.db.Where("status = ? AND published_at IS NOT NULL", 1) // 获取总数 if err := query.Model(&models.Article{}).Count(&total).Error; err != nil { return nil, 0, err } // 获取分页数据,按发布时间倒序 err := query.Preload("Author").Preload("Category"). Order("published_at DESC"). Offset(offset).Limit(limit). Find(&articles).Error return articles, total, err } // IncrementViewCount 增加浏览次数 func (r *articleRepository) IncrementViewCount(id uint64) error { return r.db.Model(&models.Article{}).Where("id = ?", id). UpdateColumn("view_count", gorm.Expr("view_count + ?", 1)).Error } ``` ### 🔧 3. Service 层 (业务逻辑层) **职责**: 业务规则、数据校验、事务管理、领域逻辑 ```go // internal/apps/blog/services/article_service.go package services import ( "errors" "time" "star-go-app/internal/apps/blog/models" "star-go-app/internal/apps/blog/repositories" "star-go-app/internal/apps/blog/serializers" ) // ArticleService 文章服务 type ArticleService struct { articleRepo repositories.ArticleRepository userRepo repositories.UserRepository // 依赖注入其他仓储 } func NewArticleService() *ArticleService { return &ArticleService{ articleRepo: repositories.NewArticleRepository(), userRepo: repositories.NewUserRepository(), } } // CreateArticle 创建文章 func (s *ArticleService) CreateArticle(req *serializers.CreateArticleRequest, authorID uint64) (*serializers.ArticleResponse, error) { // 1. 业务规则验证 if err := s.validateArticleData(req); err != nil { return nil, err } // 2. 检查作者权限 author, err := s.userRepo.GetByID(authorID) if err != nil { return nil, errors.New("作者不存在") } // 3. 创建文章实体 article := &models.Article{ Title: req.Title, Content: req.Content, Summary: req.Summary, AuthorID: authorID, CategoryID: req.CategoryID, Status: req.Status, } // 4. 如果是发布状态,设置发布时间 if req.Status == 1 { now := time.Now() article.PublishedAt = &now } // 5. 保存到数据库 if err := s.articleRepo.Create(article); err != nil { return nil, err } // 6. 获取完整信息并返回 return s.getArticleResponse(article.ID) } // GetArticleDetail 获取文章详情 func (s *ArticleService) GetArticleDetail(id uint64, userID *uint64) (*serializers.ArticleDetailResponse, error) { // 1. 获取文章 article, err := s.articleRepo.GetByID(id) if err != nil { return nil, err } // 2. 权限检查:未发布文章只有作者可以查看 if !article.IsPublished() && (userID == nil || *userID != article.AuthorID) { return nil, errors.New("文章不存在") } // 3. 增加浏览次数(异步处理,不影响响应速度) go func() { s.articleRepo.IncrementViewCount(id) }() // 4. 构建响应 return s.toArticleDetailResponse(article), nil } // PublishArticle 发布文章 func (s *ArticleService) PublishArticle(id uint64, userID uint64) error { // 1. 获取文章 article, err := s.articleRepo.GetByID(id) if err != nil { return err } // 2. 权限检查 if !article.CanEditBy(userID) { return errors.New("无权限操作此文章") } // 3. 状态检查 if article.IsPublished() { return errors.New("文章已发布") } // 4. 更新状态 article.Status = 1 now := time.Now() article.PublishedAt = &now return s.articleRepo.Update(article) } // 私有辅助方法 func (s *ArticleService) validateArticleData(req *serializers.CreateArticleRequest) error { if req.Title == "" { return errors.New("标题不能为空") } if len(req.Title) > 200 { return errors.New("标题长度不能超过200字符") } if req.Content == "" { return errors.New("内容不能为空") } return nil } ``` ### 🎮 4. Controller 层 (控制器层) **职责**: HTTP请求处理、参数绑定、响应格式化、路由处理 ```go // internal/apps/blog/controllers/article_controller.go package controllers import ( "strconv" "star-go-app/internal/apps/blog/services" "star-go-app/internal/apps/blog/serializers" "star-go-app/pkg/common/utils/response" "star-go-app/pkg/infra/logger" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // ArticleController 文章控制器 type ArticleController struct { articleService *services.ArticleService } func NewArticleController() *ArticleController { return &ArticleController{ articleService: services.NewArticleService(), } } // CreateArticle 创建文章 // @Summary 创建文章 // @Description 创建新文章 // @Tags 文章管理 // @Accept json // @Produce json // @Param request body serializers.CreateArticleRequest true "创建文章请求" // @Success 200 {object} response.Response{data=serializers.ArticleResponse} // @Failure 400 {object} response.Response // @Router /api/articles [post] func (ac *ArticleController) CreateArticle(c *gin.Context) { // 1. 参数绑定 var req serializers.CreateArticleRequest if err := c.ShouldBindJSON(&req); err != nil { logger.GetLogger().Error("创建文章参数绑定失败", zap.Error(err)) response.FailWithMessage(c, response.INVALID_PARAMS, "请求参数错误: "+err.Error(), nil) return } // 2. 获取当前用户ID userID, exists := c.Get("user_id") if !exists { response.FailWithMessage(c, response.UNAUTHORIZED, "用户未登录", nil) return } // 3. 调用服务层 article, err := ac.articleService.CreateArticle(&req, userID.(uint64)) if err != nil { logger.GetLogger().Error("创建文章失败", zap.Error(err)) response.FailWithMessage(c, response.ERROR, err.Error(), nil) return } // 4. 返回成功响应 logger.GetLogger().Info("文章创建成功", zap.Uint64("article_id", article.ID)) response.SuccessWithMessage(c, "文章创建成功", article) } // GetArticleDetail 获取文章详情 // @Summary 获取文章详情 // @Description 根据ID获取文章详情 // @Tags 文章管理 // @Param id path int true "文章ID" // @Success 200 {object} response.Response{data=serializers.ArticleDetailResponse} // @Router /api/articles/{id} [get] func (ac *ArticleController) GetArticleDetail(c *gin.Context) { // 1. 解析路径参数 idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil { response.FailWithMessage(c, response.INVALID_PARAMS, "文章ID格式错误", nil) return } // 2. 获取当前用户ID(可选) var userID *uint64 if uid, exists := c.Get("user_id"); exists { if id := uid.(uint64); id > 0 { userID = &id } } // 3. 调用服务层 article, err := ac.articleService.GetArticleDetail(id, userID) if err != nil { logger.GetLogger().Error("获取文章详情失败", zap.Error(err), zap.Uint64("id", id)) response.FailWithMessage(c, response.NOT_FOUND, err.Error(), nil) return } // 4. 返回成功响应 response.SuccessWithMessage(c, "获取文章详情成功", article) } // GetArticleList 获取文章列表 // @Summary 获取文章列表 // @Description 分页获取文章列表 // @Tags 文章管理 // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(10) // @Param category_id query int false "分类ID筛选" // @Success 200 {object} response.Response{data=serializers.ArticleListResponse} // @Router /api/articles [get] func (ac *ArticleController) GetArticleList(c *gin.Context) { // 1. 绑定查询参数 var req serializers.ArticleListRequest if err := c.ShouldBindQuery(&req); err != nil { response.FailWithMessage(c, response.INVALID_PARAMS, "查询参数错误: "+err.Error(), nil) return } // 2. 设置默认值和边界检查 if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = 10 } if req.PageSize > 100 { req.PageSize = 100 } // 3. 调用服务层 articleList, err := ac.articleService.GetPublishedArticleList(&req) if err != nil { logger.GetLogger().Error("获取文章列表失败", zap.Error(err)) response.FailWithMessage(c, response.ERROR, err.Error(), nil) return } // 4. 返回成功响应 response.SuccessWithMessage(c, "获取文章列表成功", articleList) } // PublishArticle 发布文章 // @Summary 发布文章 // @Description 将草稿文章发布 // @Tags 文章管理 // @Param id path int true "文章ID" // @Success 200 {object} response.Response // @Router /api/articles/{id}/publish [put] func (ac *ArticleController) PublishArticle(c *gin.Context) { // 1. 解析参数 idStr := c.Param("id") id, err := strconv.ParseUint(idStr, 10, 64) if err != nil { response.FailWithMessage(c, response.INVALID_PARAMS, "文章ID格式错误", nil) return } // 2. 获取当前用户 userID, exists := c.Get("user_id") if !exists { response.FailWithMessage(c, response.UNAUTHORIZED, "用户未登录", nil) return } // 3. 调用服务层 err = ac.articleService.PublishArticle(id, userID.(uint64)) if err != nil { logger.GetLogger().Error("发布文章失败", zap.Error(err), zap.Uint64("id", id)) response.FailWithMessage(c, response.ERROR, err.Error(), nil) return } // 4. 返回成功响应 logger.GetLogger().Info("文章发布成功", zap.Uint64("id", id)) response.SuccessWithMessage(c, "文章发布成功", nil) } ``` ### 📄 5. Serializers 层 (序列化层) **职责**: 请求参数验证、响应数据格式化、数据传输对象定义 ```go // internal/apps/blog/serializers/article_serializer.go package serializers import "time" // CreateArticleRequest 创建文章请求 type CreateArticleRequest struct { Title string `json:"title" binding:"required,max=200" validate:"required"` // 文章标题 Content string `json:"content" binding:"required" validate:"required"` // 文章内容 Summary string `json:"summary" binding:"max=500"` // 文章摘要 CategoryID uint `json:"category_id" binding:"required,min=1" validate:"required"` // 分类ID Status int `json:"status" binding:"oneof=0 1"` // 状态:0草稿 1发布 } // ArticleListRequest 文章列表请求 type ArticleListRequest struct { Page int `form:"page" binding:"min=1"` // 页码 PageSize int `form:"page_size" binding:"min=1,max=100"` // 每页数量 CategoryID *uint `form:"category_id" binding:"omitempty,min=1"` // 分类筛选 } // ArticleResponse 文章响应 type ArticleResponse struct { ID uint64 `json:"id"` // 文章ID Title string `json:"title"` // 标题 Summary string `json:"summary"` // 摘要 AuthorID uint64 `json:"author_id"` // 作者ID AuthorName string `json:"author_name"` // 作者名称 CategoryID uint `json:"category_id"` // 分类ID Status int `json:"status"` // 状态 ViewCount int `json:"view_count"` // 浏览次数 PublishedAt *time.Time `json:"published_at"` // 发布时间 CreatedAt time.Time `json:"created_at"` // 创建时间 UpdatedAt time.Time `json:"updated_at"` // 更新时间 } // ArticleDetailResponse 文章详情响应 type ArticleDetailResponse struct { ArticleResponse // 继承基础响应 Content string `json:"content"` // 文章内容 } // ArticleListResponse 文章列表响应 type ArticleListResponse struct { List []ArticleResponse `json:"list"` // 文章列表 Total int64 `json:"total"` // 总数 Page int `json:"page"` // 当前页 PageSize int `json:"page_size"` // 每页数量 TotalPages int `json:"total_pages"` // 总页数 } ``` ### 🔄 四层交互流程 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 请求处理流程 │ └─────────────────────────────────────────────────────────────────┘ 1. HTTP Request → Controller ↓ 2. Controller 参数验证、解析 ↓ 3. Controller → Service (调用业务逻辑) ↓ 4. Service 业务规则验证、事务管理 ↓ 5. Service → Repository (数据操作) ↓ 6. Repository → Database/Cache ↓ 7. Database → Repository (返回数据) ↓ 8. Repository → Service (返回模型) ↓ 9. Service 业务处理、数据转换 ↓ 10. Service → Controller (返回DTO) ↓ 11. Controller 格式化响应 ↓ 12. HTTP Response ← Controller ``` ## 🛠️ 项目管理工具 ### 快速使用 #### Windows用户 ```bash # 方式1: 使用交互式菜单(推荐新手) commands.bat # 方式2: 直接使用命令行 go run cmd/manage.go --help ``` #### Linux/Mac用户 ```bash # 直接使用命令行 go run cmd/manage.go --help ``` ### 📋 管理工具功能 #### 🗄️ 数据库管理 ```bash # 执行数据库迁移(初始化项目) go run cmd/manage.go db migrate # 重置数据库(危险操作) go run cmd/manage.go db reset ``` #### 👥 用户管理 ```bash # 创建超级管理员 go run cmd/manage.go user create-superuser # 修改用户密码 go run cmd/manage.go user change-password # 列出所有用户 go run cmd/manage.go user list ``` #### 🎫 Token管理 ```bash # 清除过期Token go run cmd/manage.go token clear-expired # 清除所有Token(强制所有用户重新登录) go run cmd/manage.go token clear-all ``` #### 📱 应用管理 ```bash # 创建新应用模块 go run cmd/manage.go app create # 列出所有应用 go run cmd/manage.go app list # 启动管理面板(预留功能) go run cmd/manage.go app panel ``` ### 🚀 项目初始化流程 1. **数据库迁移** ```bash go run cmd/manage.go db migrate ``` 2. **创建管理员** ```bash go run cmd/manage.go user create-superuser ``` 3. **启动项目** ```bash go run main.go ``` 4. **验证安装** ```bash curl http://localhost:8080/ ``` ## 🔐 鉴权系统详解 ### 认证架构 Star-Go-App 采用基于JWT的双Token认证机制: ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ AccessToken │ │ RefreshToken │ │ TokenBlacklist │ │ (15分钟) │ │ (7天) │ │ (黑名单) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 🔑 Token机制 #### AccessToken (访问令牌) - **有效期**: 15分钟 - **用途**: API请求认证 - **包含信息**: 用户ID、角色ID、权限列表 - **刷新机制**: 通过RefreshToken自动刷新 #### RefreshToken (刷新令牌) - **有效期**: 1天 - **用途**: 刷新AccessToken - **存储**: 数据库 + 客户端 - **安全**: 一次性使用,刷新后失效 ### 👑 角色权限系统 #### 预定义角色 ```go const ( RoleAdmin = "admin" // 管理员 - 所有权限 RoleUser = "user" // 普通用户 - 基础权限 RoleGuest = "guest" // 访客 - 只读权限 ) ``` #### 权限定义 ```go const ( PermAll = "*" // 所有权限 PermUserRead = "user:read" // 用户读取 PermUserWrite = "user:write" // 用户写入 PermUserDelete = "user:delete" // 用户删除 // ... 更多权限 ) ``` ### 🛡️ 权限拦截机制 #### 1. 全局认证中间件 ```go // 在 pkg/middleware/auth.go 中 func RequireAuth() gin.HandlerFunc { return func(c *gin.Context) { // 1. 提取Token token := extractToken(c) // 2. 验证Token claims, err := utils.ParseAccessToken(token) if err != nil { response.Unauthorized(c, "无效的访问令牌") return } // 3. 检查黑名单 if isTokenBlacklisted(token) { response.Unauthorized(c, "令牌已失效") return } // 4. 设置用户上下文 c.Set("user_id", claims.UserID) c.Set("role_id", claims.RoleID) c.Set("permissions", claims.Permissions) c.Next() } } ``` #### 2. 角色权限中间件 ```go // 检查特定角色 func RequireRole(role string) gin.HandlerFunc { return func(c *gin.Context) { userRole := c.GetString("user_role") if userRole != role { response.Forbidden(c, "权限不足") return } c.Next() } } // 检查特定权限 func RequirePermission(permission string) gin.HandlerFunc { return func(c *gin.Context) { permissions := c.GetStringSlice("permissions") if !hasPermission(permissions, permission) { response.Forbidden(c, "权限不足") return } c.Next() } } ``` ### 🎯 实际使用示例 #### 路由权限配置 ```go // internal/apps/auth/routes.go func (m *Module) registerRoutes(router *gin.RouterGroup) { // 公开路由 - 无需认证 authGroup := router.Group("") { authGroup.POST("/login", authController.Login) authGroup.POST("/refresh", authController.RefreshToken) } // 需要登录的路由 userGroup := router.Group("/users") userGroup.Use(middleware.RequireAuth()) // 全局认证 { // 普通用户可访问 userGroup.GET("/profile", userController.GetProfile) // 只有管理员可访问 adminGroup := userGroup.Group("") adminGroup.Use(middleware.RequireRole("admin")) { adminGroup.GET("", userController.GetUserList) adminGroup.POST("", userController.CreateUser) adminGroup.DELETE("/:id", userController.DeleteUser) } // 需要特定权限 permGroup := userGroup.Group("") permGroup.Use(middleware.RequirePermission("user:write")) { permGroup.PUT("/:id", userController.UpdateUser) } } } ``` #### 控制器中的权限检查 ```go // controllers/user_controller.go func (uc *UserController) UpdateUser(c *gin.Context) { // 获取当前用户信息 currentUserID := c.GetUint64("user_id") targetUserID := c.Param("id") // 检查是否是管理员或本人 if !uc.isAdminOrSelf(c, currentUserID, targetUserID) { response.Forbidden(c, "只能修改自己的信息") return } // 业务逻辑... } func (uc *UserController) isAdminOrSelf(c *gin.Context, currentUserID uint64, targetUserID string) bool { // 检查是否是管理员 permissions := c.GetStringSlice("permissions") if hasPermission(permissions, "*") { return true } // 检查是否是本人 if strconv.FormatUint(currentUserID, 10) == targetUserID { return true } return false } ``` ### 🔧 认证配置 #### config.yaml 配置 ```yaml jwt: enable_advanced_auth: true # 启用高级认证功能 secret_key: "your-secret-key" # JWT密钥 issuer: "star-go-app" # 签发者 access_token_expire: 900 # 访问令牌过期时间(秒) - 15分钟 refresh_token_expire: 604800 # 刷新令牌过期时间(秒) - 7天 ``` ### 🛠️ 认证流程 #### 1. 用户登录 ``` POST /api/auth/login { "username": "admin", "password": "123456" } Response: { "code": 200, "message": "登录成功", "data": { "access_token": "eyJhbGc...", "refresh_token": "eyJhbGc...", "user": { "id": 1, "username": "admin", "role": "admin" } } } ``` #### 2. API请求 ``` GET /api/users Headers: Authorization: Bearer eyJhbGc... ``` #### 3. Token刷新 ``` POST /api/auth/refresh { "refresh_token": "eyJhbGc..." } Response: { "access_token": "new_access_token", "refresh_token": "new_refresh_token" } ``` #### 4. 登出 ``` POST /api/auth/logout Headers: Authorization: Bearer eyJhbGc... ``` ### 🔒 安全特性 #### Token安全 - **双Token机制**: 降低Token泄露风险 - **自动过期**: AccessToken短期有效 - **黑名单机制**: 实时撤销Token - **一次性刷新**: RefreshToken使用后立即失效 #### 权限安全 - **最小权限原则**: 用户只获得必需权限 - **角色继承**: 支持权限继承关系 - **动态权限**: 支持运行时权限检查 - **审计日志**: 记录所有权限相关操作 #### 会话安全 - **设备管理**: 跟踪用户登录设备 - **异地登录检测**: 检测异常登录 - **并发会话控制**: 限制同时登录数量 - **强制下线**: 管理员可强制用户下线 ## 🚀 快速开始 ### 环境要求 - Go 1.21+ - MySQL 8.0+ - Redis 6.0+ (可选) ### 安装步骤 1. **克隆项目** ```bash git clone https://github.com/your-org/star-go-app.git cd star-go-app ``` 2. **安装依赖** ```bash go mod download ``` 3. **配置数据库** ```yaml # config.yaml database: host: "localhost" port: 3306 username: "root" password: "your-password" dbname: "star_go_app" ``` 4. **初始化项目** ```bash # 数据库迁移 manage.bat db migrate # 创建管理员 manage.bat user create-superuser ``` 5. **启动服务** ```bash go run main.go ``` 6. **测试API** ```bash curl http://localhost:8080/api/auth/verify ``` ## 🔄 开发新模块 ### 使用管理工具创建 ```bash manage.bat app create # 输入应用名称: blog ``` ### 手动创建步骤 1. **创建目录结构** ``` internal/apps/blog/ ├── module.go ├── routes.go ├── controllers/ ├── services/ ├── repositories/ └── models/ ``` 2. **实现Module接口** ```go // internal/apps/blog/module.go type Module struct{} func (m *Module) Name() string { return "blog" } func (m *Module) RegisterRoutes(router *gin.RouterGroup) { RegisterRoutes(router) } func (m *Module) Initialize() error { return nil } ``` 3. **注册模块** ```go // internal/apps/apps.go var INSTALLED_APPS = map[string]AppInfo{ "auth": { Description: "用户认证模块", NewModule: func() Module { return auth.NewModule() }, }, "blog": { Description: "博客模块", NewModule: func() Module { return blog.NewModule() }, }, } ``` ## 📚 API文档 ### 认证相关API - `POST /api/auth/login` - 用户登录 - `POST /api/auth/logout` - 用户登出 - `POST /api/auth/refresh` - 刷新Token - `POST /api/auth/verify` - 验证Token ### 用户管理API - `GET /api/users` - 获取用户列表 - `POST /api/users` - 创建用户 - `GET /api/users/:id` - 获取用户详情 - `PUT /api/users/:id` - 更新用户信息 - `DELETE /api/users/:id` - 删除用户 ### 角色管理API - `GET /api/roles` - 获取角色列表 - `POST /api/roles` - 创建角色 - `PUT /api/roles/:id` - 更新角色 - `DELETE /api/roles/:id` - 删除角色 ## 🤝 贡献指南 1. Fork 项目 2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) 4. 推送到分支 (`git push origin feature/AmazingFeature`) 5. 打开 Pull Request ## 📄 许可证 本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 ## 🆘 常见问题 **Q: 如何重置管理员密码?** A: 使用命令 `manage.bat user change-password` **Q: Token过期后如何处理?** A: 客户端应监听401响应,自动使用RefreshToken刷新AccessToken **Q: 如何添加新的权限?** A: 在models/role.go中定义新权限常量,然后在相应的中间件中使用 **Q: 数据库迁移失败怎么办?** A: 检查数据库连接配置,确保MySQL服务正常运行 --- **🌟 Star Go App - 让企业级API开发更简单!**