Files
zhengchiliu ff9add8655 补齐 HTTP 层:实现用户模块、路由与中间件接线、COS 上传及优雅启动
- 新增用户与上传错误码文件及 Recovery 中间件
- 修复 router.go 导入与中间件链,注册用户路由并补 handler 错误码导入
- 补充用户状态常量与 UserGetByWechatOpenID 查询,修订刷新令牌 dto
- 移除 upload 包 OTel 调用,新增 FileUploadCos 上传封装
- 实现 UserService 微信登录/刷新令牌/我的信息/改资料/上传头像
- 裁剪 main.go 配置段并移除 OTel 桥接,补启动与优雅退出
- 新增 configs 示例配置、global 配置结构及 go.mod 依赖
2026-09-27 15:02:01 +08:00

76 lines
2.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"context"
"errors"
"log/slog"
"strings"
"git.lzcwy.cn/zhengchiliu/zt-online-game-backend/pkg/app"
"git.lzcwy.cn/zhengchiliu/zt-online-game-backend/pkg/errcode"
"git.lzcwy.cn/zhengchiliu/zt-online-game-backend/pkg/lzcwyjwt"
"github.com/gin-gonic/gin"
)
type ctxKey string
const (
userIDKey ctxKey = "userID"
)
func JWTAuth() gin.HandlerFunc {
return func(c *gin.Context) {
response := app.NewResponse(c)
// 1. 从 Authorization 头取 token:Bearer xxx.yyy.zzz
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
slog.WarnContext(c.Request.Context(), "jwt auth: authorization header missing",
"method", c.Request.Method, "path", c.Request.URL.Path, "ip", c.ClientIP())
response.ToErrorResponse(errcode.UnauthorizedTokenMissing)
c.Abort()
return
}
parts := strings.SplitN(authHeader, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
slog.WarnContext(c.Request.Context(), "jwt auth: invalid authorization format",
"method", c.Request.Method, "path", c.Request.URL.Path, "ip", c.ClientIP())
response.ToErrorResponse(errcode.UnauthorizedTokenError.WithDetails("invalid Authorization format"))
c.Abort()
return
}
// 2. 解析 token
claims, err := lzcwyjwt.ParseAccessToken(parts[1])
if err != nil {
switch {
case errors.Is(err, lzcwyjwt.ErrTokenExpired):
slog.InfoContext(c.Request.Context(), "jwt auth: token expired", "path", c.Request.URL.Path)
response.ToErrorResponse(errcode.UnauthorizedTokenTimeout)
case errors.Is(err, lzcwyjwt.ErrTokenWrongType):
slog.WarnContext(c.Request.Context(), "jwt auth: token type mismatch", "path", c.Request.URL.Path)
response.ToErrorResponse(errcode.UnauthorizedTokenError.WithDetails("token type mismatch"))
default:
slog.WarnContext(c.Request.Context(), "jwt auth: parse token failed",
"path", c.Request.URL.Path, "ip", c.ClientIP(), "error", err)
response.ToErrorResponse(errcode.UnauthorizedTokenError.WithDetails(err.Error()))
}
c.Abort()
return
}
// 4. 把 userID注入 context
ctx := context.WithValue(c.Request.Context(), userIDKey, claims.UserID)
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
// GetUserID 从 context 取登录用户 ID(在 handler 里用)
func GetUserID(ctx context.Context) (int64, bool) {
uid, ok := ctx.Value(userIDKey).(int64)
return uid, ok
}