refactor(middleware): 重构权限中间件以统一上下文管理

- 引入 utils.UserContext 结构体统一管理用户上下文信息
- 创建新的上下文键 UserContent 用于存储用户信息
- 移除分散的 context.Value 调用,改用结构化数据传递
- 修正 context.WithValue 返回值未被正确使用的逻辑错误
- 更新 logout_logic.go 中的 Token 和用户ID获取方式
- 删除冗余的 Token 清理和提取函数
- 新增 context_util.go 文件提供上下文工具方法
- 简化 logout 接口中的上下文数据访问逻辑
This commit is contained in:
huanglei19951029 2025-12-16 16:36:30 +08:00
parent a9f61e0fb2
commit 5aabd0a3a8
5 changed files with 64 additions and 61 deletions

View File

@ -3,14 +3,14 @@ package user
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"github.com/saas-mingyang/mingyang-admin-common/i18n" "github.com/saas-mingyang/mingyang-admin-common/i18n"
"mingyang-admin-app-api/internal/svc" "mingyang-admin-app-api/internal/svc"
"mingyang-admin-app-api/internal/types" "mingyang-admin-app-api/internal/types"
"mingyang-admin-app-rpc/types/app" "mingyang-admin-app-rpc/types/app"
"net/http" "mingyang-admin-app-rpc/utils"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -37,16 +37,20 @@ func (l *LogoutLogic) Logout() (resp *types.BaseMsgResp, err error) {
n := runtime.Stack(buf, false) n := runtime.Stack(buf, false)
l.Logger.Infof("Logout call stack:\n%s", buf[:n]) l.Logger.Infof("Logout call stack:\n%s", buf[:n])
token := l.getTokenFromContext() userContent, err := l.getTokenFromContext()
l.Infof("Starting Logout RPC call at: %v", time.Now()) if err != nil {
return nil, err
}
l.Info("UserContent: %v", userContent)
l.Infof("Starting Logout RPC call at: %v", time.Now())
// 记录goroutine ID // 记录goroutine ID
goID := getGoroutineID() goID := getGoroutineID()
l.Logger.Infof("Goroutine ID: %d", goID) l.Logger.Infof("Goroutine ID: %d", goID)
_, err = l.svcCtx.AppRpc.LogoutUser(l.ctx, &app.UserToken{ _, err = l.svcCtx.AppRpc.LogoutUser(l.ctx, &app.UserToken{
AccessToken: token, AccessToken: userContent.Token,
UserId: l.getUserIDFromContext(), UserId: userContent.UserID,
}) })
l.Logger.Infof("Finished Logout RPC call at: %v", time.Now()) l.Logger.Infof("Finished Logout RPC call at: %v", time.Now())
@ -68,50 +72,12 @@ func getGoroutineID() uint64 {
} }
// 从上下文中获取 Token // 从上下文中获取 Token
func (l *LogoutLogic) getTokenFromContext() string { func (l *LogoutLogic) getTokenFromContext() (*utils.UserContext, error) {
// 尝试不同的 key 从上下文中获取 Token requestContext := utils.GetRequestContext(l.ctx)
keys := []string{"token", "access_token", "jwt_token", "auth_token"} if requestContext == nil {
return nil, errors.New("invalid request context")
for _, key := range keys {
if token, ok := l.ctx.Value(key).(string); ok && token != "" {
return l.cleanToken(token)
} }
} return requestContext, nil
return ""
}
// 清理 Token 字符串,移除 "Bearer " 前缀
func (l *LogoutLogic) cleanToken(token string) string {
if token == "" {
return ""
}
token = strings.TrimSpace(token)
// 移除 "Bearer " 前缀
if strings.HasPrefix(strings.ToLower(token), "bearer ") {
token = token[7:]
}
return token
}
// 从 Authorization Header 中提取 Token
func (l *LogoutLogic) extractTokenFromAuthHeader(ctx context.Context) string {
// 尝试从请求上下文获取 Request 对象
if req, ok := ctx.Value("http_request").(*http.Request); ok {
authHeader := req.Header.Get("Authorization")
if authHeader != "" {
return l.cleanToken(authHeader)
}
}
return ""
}
// 从上下文中获取用户ID
func (l *LogoutLogic) getUserIDFromContext() uint64 {
// 在AuthMiddleware中我们将用户ID放入了context
if userID, ok := l.ctx.Value("userId").(uint64); ok {
return userID
}
return 0
} }
// 获取 Token 过期时间 // 获取 Token 过期时间

View File

@ -49,6 +49,9 @@ func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err erro
RefreshTokenExpires: token.RefreshTokenExpires.Seconds, RefreshTokenExpires: token.RefreshTokenExpires.Seconds,
}, },
UserInfo: &types.UserInfo{ UserInfo: &types.UserInfo{
BaseIDInfo: types.BaseIDInfo{
Id: user.Id,
},
Username: user.Username, Username: user.Username,
NickName: user.NickName, NickName: user.NickName,
Avatar: user.Avatar, Avatar: user.Avatar,

View File

@ -13,6 +13,7 @@ import (
"mingyang-admin-app-api/internal/types" "mingyang-admin-app-api/internal/types"
"mingyang-admin-app-rpc/appclient" "mingyang-admin-app-rpc/appclient"
"mingyang-admin-app-rpc/types/app" "mingyang-admin-app-rpc/types/app"
"mingyang-admin-app-rpc/utils"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -109,20 +110,19 @@ func (m *AuthorityMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
// 创建新的上下文,包含 Token 和用户信息 // 创建新的上下文,包含 Token 和用户信息
ctx := r.Context() ctx := r.Context()
ctx = context.WithValue(ctx, "token", fromToken)
ctx = context.WithValue(ctx, "userId", token.UserId)
ctx = context.WithValue(ctx, "tokenClaims", token)
// 获取客户端 IP
clientIP := getClientIP(r)
ctx = context.WithValue(ctx, "client_ip", clientIP)
// 获取 User-Agent
userAgent := r.UserAgent()
ctx = context.WithValue(ctx, "user_agent", userAgent)
// 构建请求信息
content := &utils.UserContext{
Token: fromToken,
UserID: token.UserId,
TokenClaims: token,
ClientIP: getClientIP(r),
UserAgent: r.UserAgent(),
}
// 修正:必须接收 context.WithValue 的返回值
newContent := context.WithValue(ctx, utils.UserContent, content)
// 将新上下文设置到请求中 // 将新上下文设置到请求中
r = r.WithContext(ctx) r = r.WithContext(newContent)
// 调用下一个处理器 // 调用下一个处理器
next(w, r) next(w, r)

View File

@ -0,0 +1 @@
package server

33
rpc/utils/context_util.go Normal file
View File

@ -0,0 +1,33 @@
package utils
import (
"context"
"mingyang-admin-app-rpc/types/app"
)
const (
UserContent = "userContent"
)
// UserContext RequestContext 请求上下文信息API 和 RPC 共享)
type UserContext struct {
Token string // 原始 token 字符串
UserID uint64 // 用户ID
TokenClaims *app.AuthInfoResp // token 解析后的 claims
ClientIP string // 客户端IP
UserAgent string // User-Agent
}
// GetRequestContext 从上下文获取请求上下文RPC 层)
// 从上下文获取请求上下文
func GetRequestContext(ctx context.Context) *UserContext {
value := ctx.Value(UserContent)
if value == nil {
return nil
}
reqCtx, ok := value.(*UserContext)
if !ok {
return nil
}
return reqCtx
}