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

使用golang-jwt验证JWT时出现signature is invalid问题求助

问题解决:golang-jwt验证JWT时提示"signature is invalid"

核心问题定位

从日志和代码可直接找到两个导致签名验证失败的原因:

  • 密钥不匹配:日志显示生成Token时使用的密钥是Indisputably-Salty-Orbit-7260-07erijgpeirgjpejgptrjgpptgjpritgpi4rtnghi,但验证中间件里硬编码的是keepmesecret,签名与验签用不同密钥必然导致验证失败。
  • Token被污染:日志中接收的Token末尾带有login字符串(如...Epvrwlogin),说明登录接口返回时把Token和额外的"login"字符串拼接了,导致解析的Token并非完整正确内容。

修复步骤

1. 统一签名密钥

将密钥抽为全局变量或配置项,确保生成与验证使用同一密钥:

// 全局统一密钥,替换为实际使用的密钥
var secretKey = "Indisputably-Salty-Orbit-7260-07erijgpeirgjpejgptrjgpptgjpritgpi4rtnghi"

// 修改验证中间件的密钥使用逻辑
func validateJWT(tokenString string) (*jwt.Token, error) {
    return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }
        return []byte(secretKey), nil
    })
}

// 修改登录接口的密钥使用逻辑
func RouteLogin(c echo.Context) error {
    username := c.FormValue("username")
    password := c.FormValue("password")

    if username == "admin" {
        if password != settings.Accounts.Admin.Password {
            return c.String(401, "Unauthorized")
        }
        return sendToken(c, secretKey, username)
    } else {
        accounts := settings.Accounts.GuestAccounts
        account, ok := accounts[username]
        if !ok {
            return c.String(404, "Not Found")
        }
        if account.Password != password {
            return c.String(401, "Unauthorized")
        }
        return sendToken(c, secretKey, username)
    }
}

2. 修复登录接口的返回逻辑

原登录接口调用sendToken后未直接返回,导致后续执行了return c.String(200, "login"),把Token与"login"字符串拼接返回,需修正为直接返回sendToken的结果:

func RouteLogin(c echo.Context) error {
    username := c.FormValue("username")
    password := c.FormValue("password")

    if username == "admin" {
        if password != settings.Accounts.Admin.Password {
            return c.String(401, "Unauthorized")
        }
        // 直接返回Token,避免后续拼接额外内容
        return sendToken(c, secretKey, username)
    } else {
        accounts := settings.Accounts.GuestAccounts
        account, ok := accounts[username]
        if !ok {
            return c.String(404, "Not Found")
        }
        if account.Password != password {
            return c.String(401, "Unauthorized")
        }
        return sendToken(c, secretKey, username)
    }
}

3. 优化Token提取逻辑(可选)

原代码用strings.Split提取Token时未做错误处理,若Header格式错误会直接panic,建议增加校验:

func Authenticator(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        authHeader := c.Request().Header.Get("Authorization")
        if authHeader == "" {
            return c.JSON(401, map[string]interface{}{"error": "Authorization header missing"})
        }
        parts := strings.Split(authHeader, "Bearer ")
        if len(parts) != 2 {
            return c.JSON(401, map[string]interface{}{"error": "Invalid Authorization format"})
        }
        tokenString := parts[1]
        
        token, err := validateJWT(tokenString)
        if err != nil {
            fmt.Println(err)
            return c.JSON(401, map[string]interface{}{"error": "Invalid token"})
        }
        if !token.Valid {
            return c.JSON(401, map[string]interface{}{"error": "Invalid token"})
        }

        claims := token.Claims.(jwt.MapClaims)
        c.Set("user", claims["username"])

        return next(c)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 20:50:54