补齐 HTTP 层:实现用户模块、路由与中间件接线、COS 上传及优雅启动
- 新增用户与上传错误码文件及 Recovery 中间件 - 修复 router.go 导入与中间件链,注册用户路由并补 handler 错误码导入 - 补充用户状态常量与 UserGetByWechatOpenID 查询,修订刷新令牌 dto - 移除 upload 包 OTel 调用,新增 FileUploadCos 上传封装 - 实现 UserService 微信登录/刷新令牌/我的信息/改资料/上传头像 - 裁剪 main.go 配置段并移除 OTel 桥接,补启动与优雅退出 - 新增 configs 示例配置、global 配置结构及 go.mod 依赖
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user