想巩固一下学到的东西,就想动手写一个注册登录的小项目,结果在JWT鉴权过程中卡住了,问题如下:
POST访问`/login`获得`token`,随后携带`token`GET访问`/`,`token`使用工具验证`token`正常签发,然后在i鉴权中间件里走了`Authorization token is wrong`分支,请问这是为什么?
另外有个小问题就是,签发的`token`仅仅丢到了客户端,不需要保存吗?
- package: github.com/golang-jwt/jwt/v5
model
```go
type User struct {
*gorm.Model
UserName string `form:"userName"`
PassWord string `form:"passWord"`
}
```
---
JWT SignedToken
```go
func (j *JWT) Signed(user *models.User) string {
v, _ := vp.GetCfg()
key := v.GetString("kwt.key")
sg := jwt.NewWithClaims(jwt.SigningMethodHS256, &ArkClaims{
MapClaims: jwt.MapClaims{
"iss": "ark", // 签发者
"sub": user.UserName, // 受众
"iat": time.Now().Unix(), // 签发时间
"exp": time.Now().Add(time.Hour).Unix(), // 过期时间
},
})
token, _ := sg.SignedString([]byte(key))
return token
}
```
JWT AuthToken
```go
func (j *JWT) Auth(tokenString string) error {
vi, _ := vp.GetCfg()
key := vi.GetString("jwt.key")
token, _ := jwt.ParseWithClaims(tokenString, &ArkClaims{}, 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 key, nil
})
if !token.Valid {
return errors.New("token not valid")
}
return nil
}
```
Auth Middlware
```go
func AuthMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
// 获取请求头中的 Authorization
BearerToken := ctx.GetHeader("Authorization")
if BearerToken == "" {
ctx.JSON(http.StatusUnauthorized, gin.H{
"msg": "Authorization token is missing",
})
ctx.Abort()
return
}
token := BearerToken[len("Bearer "):]
fmt.Println(token)
// 验证 token 是否有效
newJWT := auth.NewJWT()
err := newJWT.Auth(token)
if err != nil {
ctx.JSON(http.StatusUnauthorized, gin.H{
"msg": "Authorization token is wrong",
})
ctx.Abort()
return
}
ctx.Next()
}
}
```
谢谢指点,我在验证逻辑中用切片吧Bearer去掉了。错误原因是:签名用了[]byte(key),验证用的key,虽然打印出来两者无异,但是这小细节实在是浪费了很多精力。
#2
更多评论
1、jwt的token不需要保存在服务器端(验证的过程就是解密,如果解密出错,token就是错的,最好在签名的时候加上客户端的唯一标识,比如IP地址啥的,以防token拷贝在不同的主机上访问服务);
2、在auth阶段,你在header里读出了token,但是这个token加了“Bear ”,需要把这个去掉后再验证token。你的代码中少了这段代码;
#1