You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将JWT自定义Claim的Id从CheckToken中间件传递到campaign.Attack函数

解决方案:通过 Request Context 传递用户ID

我来给你一个Go生态里标准且好用的解决方案——利用*http.Request的Context来传递这类请求级别的上下文数据,完全不用修改http.HandlerFunc的签名,完美适配你的场景。

下面是具体的修改步骤:

1. 定义自定义Context Key(避免命名冲突)

首先在token.go里定义一个私有类型作为Context的Key,这样能避免和其他包的key产生命名冲突,是Go里的最佳实践:

package token

import (
    "context"
    "strings"
    "log"
    "net/http"
    "github.com/dgrijalva/jwt-go"
)

// 定义私有类型作为Context的Key,防止和其他包的key冲突
type contextKey string

const userIdKey contextKey = "userId"

type MyCustomClaims struct {
    Id int `json:"id"` // 用户ID
    jwt.StandardClaims
}

2. 修改CheckToken中间件,将用户ID存入Request Context

你之前的CheckToken返回值里的MyCustomClaims其实是多余的,中间件只需要返回http.HandlerFunc就够了。现在调整代码,在验证token成功后,把claims.Id存入请求的Context:

func CheckToken(next http.HandlerFunc) http.HandlerFunc {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        authorizationHeader := req.Header.Get("authorization")
        if authorizationHeader != "" {
            bearerToken := strings.Split(authorizationHeader, " ")
            if len(bearerToken) == 2 {
                token, err := jwt.ParseWithClaims(bearerToken[1], &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
                    return []byte("magicword"), nil
                })
                if token.Valid {
                    if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
                        log.Println(claims.Id)
                        // 将用户ID存入Request的Context
                        req = req.WithContext(context.WithValue(req.Context(), userIdKey, claims.Id))
                        // 继续执行后续的handler
                        next(w, req)
                    } else {
                        log.Println(err)
                        http.Error(w, "无效的Token声明", http.StatusUnauthorized)
                    }
                } else if ve, ok := err.(*jwt.ValidationError); ok {
                    if ve.Errors&jwt.ValidationErrorMalformed != 0 {
                        http.Error(w, "Token格式错误", http.StatusBadRequest)
                    } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
                        http.Error(w, "Token已过期或尚未生效", http.StatusUnauthorized)
                    } else {
                        http.Error(w, "无效的Token", http.StatusUnauthorized)
                    }
                } else {
                    http.Error(w, "解析Token失败", http.StatusInternalServerError)
                }
            } else {
                http.Error(w, "Authorization头格式错误", http.StatusBadRequest)
            }
        } else {
            http.Error(w, "需要Authorization头", http.StatusUnauthorized)
        }
    })
}

我补充了一些错误处理的返回逻辑,让你的中间件更健壮,避免出现无响应的情况。

3. 在campaign.Attack中从Context读取用户ID

修改campaign.go里的Attack函数,从请求的Context中取出之前存入的用户ID即可:

package campaign

import (
    "log"
    "net/http"
    "你的项目模块路径/token" // 替换成你token包的实际导入路径
)

func Attack(w http.ResponseWriter, req *http.Request) {
    log.Println("attack")
    // 从Context中读取用户ID
    userId, ok := req.Context().Value(token.userIdKey).(int)
    if !ok {
        http.Error(w, "从Context中获取用户ID失败", http.StatusInternalServerError)
        return
    }
    // 现在你可以正常使用userId了
    log.Printf("发起攻击的用户ID:%d", userId)
    // 这里写你的业务逻辑...
}

记得把你的项目模块路径/token替换成你项目中token包的实际导入路径。

4. 修正main.go中的路由注册

因为我们调整了CheckToken的返回值,不过你原来的路由注册代码完全可以正常工作,不需要修改:

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/attack", token.CheckToken(campaign.Attack)).Methods("GET", "OPTIONS")
    log.Fatal(http.ListenAndServe(":3000", handlers.CORS(handlers.AllowedOrigins([]string{"*"}), handlers.AllowedHeaders([]string{"Content-Type", "authorization"}))(router)))
}

这种方法的优势:

  • 完全遵循Go HTTP标准库的设计,不需要修改Handler的签名,兼容性拉满
  • Context是请求级别的,数据只会在当前请求的生命周期内存在,不会有并发安全问题
  • 通过自定义的contextKey避免了命名冲突,类型更安全

内容的提问来源于stack exchange,提问作者licorpolo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:01:13