first commit

This commit is contained in:
何昌清
2026-03-26 22:13:03 +08:00
parent bbe1faa363
commit a2685f7f1e
51 changed files with 11244 additions and 0 deletions

97
middle/middle_auth.go Normal file
View File

@@ -0,0 +1,97 @@
// Package middle auth_middleware.go
package middle
import (
"Quincy_admin/utils"
"net/http"
"github.com/gin-gonic/gin"
)
type AuthMiddleware struct {
Service *MService
}
func NewAuthMiddleware(Service *MService) *AuthMiddleware {
return &AuthMiddleware{
Service: Service,
}
}
// Auth 验证 X-Access-Token 的中间件
func (m *AuthMiddleware) Auth() gin.HandlerFunc {
return func(ctx *gin.Context) {
// 获取 X-Access-Token 头部
token := ctx.GetHeader("Authorization")
if token == "" {
utils.Error(ctx, http.StatusUnauthorized, "缺少访问令牌")
ctx.Abort()
return
}
user, err := utils.ParseToken(token)
if err != nil {
utils.Error(ctx, http.StatusUnauthorized, "无效的访问令牌")
ctx.Abort()
return
}
// 验证用户是否存在
newUser, err := m.Service.GetUserID(user.SessionCode)
if err != nil {
utils.Error(ctx, http.StatusUnauthorized, "用户不存在")
ctx.Abort()
return
}
if newUser.Status != 1 {
utils.Error(ctx, http.StatusUnauthorized, "用户已被锁定")
ctx.Abort()
return
}
// 使用 ctx.Set() 存储用户 ID角色ID供后续中间件读取
ctx.Set("user_id", newUser.ID)
ctx.Set("role_id", newUser.RoleCode)
ctx.Set("code", newUser.SessionCode)
// token 验证成功,继续处理请求
ctx.Next()
}
}
// Perm 验证权限
func (m *AuthMiddleware) Perm(perm string) gin.HandlerFunc {
return func(ctx *gin.Context) {
userIDInterface, exists := ctx.Get("user_id")
if !exists {
utils.Error(ctx, http.StatusUnauthorized, "权限校验错误用户ID不存在")
ctx.Abort()
return
}
userID, ok := userIDInterface.(int)
if !ok {
utils.Error(ctx, http.StatusUnauthorized, "权限校验错误用户ID类型错误")
ctx.Abort()
return
}
// 检查是否为超级管理员,如果是则跳过权限校验
if m.Service.IsSuperAdmin(userID) {
ctx.Next()
return
}
// 非超管账号检查权限
if err := m.Service.HasPermission(userID, perm); err != nil {
utils.Error(ctx, http.StatusForbidden, "没有权限")
ctx.Abort()
return
}
ctx.Next()
}
}

23
middle/middle_cors.go Normal file
View File

@@ -0,0 +1,23 @@
// Package middle auth_middleware.go
package middle
import (
"github.com/gin-gonic/gin"
)
// SetupCORS 返回CORS中间件函数
func SetupCORS() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Authorization")
c.Header("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}

72
middle/middle_logger.go Normal file
View File

@@ -0,0 +1,72 @@
// Package middle middle_logger.go
package middle
import (
"bytes"
"fmt"
"io"
"log"
"time"
"github.com/gin-gonic/gin"
)
func RequestResponseLogger() gin.HandlerFunc {
return func(ctx *gin.Context) {
// 保存原始请求体
var bodyBytes []byte
if ctx.Request.Body != nil {
bodyBytes, _ = io.ReadAll(ctx.Request.Body)
// 恢复请求体,供后续处理使用
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
// 获取查询参数
queryParams := ctx.Request.URL.Query().Encode()
// 获取请求头信息
var headers string
Token := ctx.GetHeader("X-Access-Token")
headers = fmt.Sprintf("X-Access-Token: %s; ", Token)
// 记录开始时间
startTime := time.Now()
// 继续处理请求
ctx.Next()
// 计算处理时间
latency := time.Since(startTime)
// 格式化日志内容
timestamp := time.Now().Format("2006/01/02 15:04:05")
// 格式化日志内容
logMessage := fmt.Sprintf("[GIN] Request | %3d | %13v | %15s | %-7s %s",
ctx.Writer.Status(),
latency,
ctx.ClientIP(),
ctx.Request.Method,
ctx.Request.URL.Path,
)
// 单独打印查询参数(带时间戳)
if queryParams != "" {
logMessage += fmt.Sprintf("\n%s [GIN] Params: %s", timestamp, queryParams)
}
// 单独打印请求体(带时间戳)
if len(bodyBytes) > 0 {
logMessage += fmt.Sprintf("\n%s [GIN] Body: %s", timestamp, string(bodyBytes))
}
// 单独打印请求头(带时间戳)
if headers != "" {
logMessage += fmt.Sprintf("\n%s [GIN] Headers: %s", timestamp, headers)
}
// 输出到控制台
log.Println(logMessage)
}
}

112
middle/middle_service.go Normal file
View File

@@ -0,0 +1,112 @@
// Package middle/middle_service.go
package middle
import (
"Quincy_admin/schemas"
"fmt"
"github.com/jmoiron/sqlx"
)
type MService struct {
db *sqlx.DB
}
func NewMiddleService(db *sqlx.DB) *MService {
return &MService{db: db}
}
// GetUserID 验证令牌并返回用户信息
//func (s *MService) GetUserID(scode string) (*schemas.UserInfo, error) {
// // 从Redis获取用户信息
// InitRedis := utils.GetRedis()
// ctx := utils.GetContext()
//
// // 尝试从Redis获取用户会话信息
// userInfoStr, err := InitRedis.Get(ctx, scode).Result()
// if err != nil {
// // Redis中未找到会话信息视为登录过期
// return nil, fmt.Errorf("登录已过期")
// }
//
// // 解析Redis中的用户信息
// var user schemas.UserInfo
// err = json.Unmarshal([]byte(userInfoStr), &user)
// if err != nil {
// return nil, fmt.Errorf("会话信息解析失败")
// }
//
// return &user, nil
//}
// GetUserID 验证令牌并返回用户ID
func (s *MService) GetUserID(scode string) (*schemas.UserInfo, error) {
// 实现令牌验证逻辑
query := `
SELECT
tb1.id,
COALESCE(tb2.role_id, 0) AS rolecode,
tb1.sessioncode,
tb1.username,
tb1.password,
tb1.nickname,
tb1.email,
tb1.avatar,
tb1.status,
tb1.register_time,
tb1.last_login_time
FROM
admin_user tb1
JOIN admin_user_role tb2 ON tb1.id = tb2.user_id
WHERE
sessioncode = ?
ORDER BY
tb1.id
LIMIT 1;
`
user := &schemas.UserInfo{}
err := s.db.Get(user, query, scode)
if err != nil {
return nil, err
}
return user, nil
}
// HasPermission 检查用户是否有特定权限
func (s *MService) HasPermission(userID int, permission string) error {
query := `
SELECT
COUNT(*) > 0 AS has_permission
FROM
admin_user au
JOIN admin_user_role aur ON au.id = aur.user_id
JOIN admin_role ar ON aur.role_id = ar.id
JOIN admin_role_permission arp ON ar.id = arp.role_id
JOIN admin_permission ap ON arp.permission_id = ap.id
WHERE
au.id = ?
AND ap.name = ?
`
var hasPermission bool
err := s.db.Get(&hasPermission, query, userID, permission)
if err != nil {
return err
}
fmt.Println(hasPermission)
// 根据权限检查结果返回相应错误
if !hasPermission {
return fmt.Errorf("user %d does not have permission %s", userID, permission)
}
return nil
}
// IsSuperAdmin 检查是否为超级管理员
func (s *MService) IsSuperAdmin(userID int) bool {
return userID == 1
}