使用 golang-jwt 验证 jwt 令牌时遇到一些问题。很确定我正确地形成了令牌,因为我能够打印它们并且它们返回正常,但是当我尝试解析它们并提取声明时,我收到一条错误,指出签名无效。
我正在为我的 API 使用 echo 框架,以防万一。
这是我的身份验证中间件功能
func validateJWT(tokenString string) (*jwt.Token, error) {
// hard coded for now
secretKey := "keepmesecret"
return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(secretKey), nil
})
}
func Authenticator(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Get the token from the header
tokenString := strings.Split(c.Request().Header.Get("Authorization"), "Bearer ")[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)
// Set the user in the context
c.Set("user", claims["username"])
return next(c)
}
}
这是我的代币创建
func createToken(secretKey string, username string) (string, error) {
claim := jwt.MapClaims{
"username": username,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)
tokenString, err := token.SignedString([]byte(secretKey))
if err != nil {
return "", err
}
return tokenString, nil
}
func sendToken(c echo.Context, secretKey string, username string) error {
token, err := createToken(secretKey, username)
if err != nil {
return c.String(500, "Internal Server Error")
}
return c.String(200, token)
}
// login
func RouteLogin(c echo.Context) error {
secretKey := "keepmesecret"
username := c.FormValue("username")
password := c.FormValue("password")
// if username is not admin get all guest account info
if username == "admin" {
if password != settings.Accounts.Admin.Password {
return c.String(401, "Unauthorized")
} else {
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")
}
sendToken(c, secretKey, username)
}
return c.String(200, "login")
}
添加一些日志信息
Sending token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTUwNjExMzUsInVzZXJuYW1lIjoiZ3Vlc3QifQ.hbF88eu6fGs6F0S9Ttvv6eu8_mT_Iv7rBHvGq8Epvrw using secret key: Indisputably-Salty-Orbit-7260-07erijgpeirgjpejgptrjgpptgjpritgpi4rtnghi
2024-05-06T15:52:15+10:00 | 200 | 2.5633ms | 127.0.0.1 | POST /api/auth/login
Received token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTUwNjExMzUsInVzZXJuYW1lIjoiZ3Vlc3QifQ.hbF88eu6fGs6F0S9Ttvv6eu8_mT_Iv7rBHvGq8Epvrwlogin using secret key: Indisputably-Salty-Orbit-7260-07erijgpeirgjpejgptrjgpptgjpritgpi4rtnghi
signature is invalid
2024-05-06T15:52:24+10:00 | 401 | 2.7255ms | 127.0.0.1 | GET /api/navigate/?pathname=/
根据评论,问题就在这里:
} else {
...
sendToken(c, secretKey, username)
}
return c.String(200, "login")
sendToken
称为 c.String(200, token)
,发送将字符串的内容传输到客户端。 String
的实现调用Blob
,它写入标头(如果已经完成,将发出警告),然后写入数据。因为 String
被调用两次(一次在 sendToken
中,然后在 return c.String
中再次调用),所以输出将是附加了 login
的标记(即 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTUwNjExMzUsInVzZXJuYW1lIjoiZ3Vlc3QifQ.hbF88eu6fGs6F0S9Ttvv6eu8_mT_Iv7rBHvGq8Epvrwlogin
)。
因此发送到客户端的令牌附加了文本
login
,这意味着当您尝试解析它时会收到错误。发现此类问题的最简单方法通常只是添加日志记录来检查您拥有的值是否符合您的预期。