package auth import ( "applet/app/utils/cache" "errors" "fmt" "github.com/dgrijalva/jwt-go" "time" ) // GenToken 生成JWT func GenToken(uid int64) (string, error) { // 创建一个我们自己的声明 c := JWTUser{ Uid: uid, StandardClaims: jwt.StandardClaims{ ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间 Issuer: "egg_app", // 签发人 }, } // 使用指定的签名方法创建签名对象 tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, c) // 使用指定的secret签名并获得完整的编码后的字符串token token, err := tokenClaims.SignedString(Secret) if err != nil { return "", err } // 缓存token cacheKey := fmt.Sprintf(TokenKey, uid) _, err = cache.SetEx(cacheKey, token, TokenCacheTime) if err != nil { return "", err } return token, nil } // ParseToken 解析JWT func ParseToken(tokenString string) (*JWTUser, string, error) { // 解析token token, err := jwt.ParseWithClaims(tokenString, &JWTUser{}, func(token *jwt.Token) (i interface{}, err error) { return Secret, nil }) if err != nil { return nil, "", err } if claims, ok := token.Claims.(*JWTUser); ok && token.Valid { // 校验token正确性 if claims.StandardClaims.ExpiresAt < time.Now().Unix() { // 校验token时效性 return nil, "", errors.New("token is expired") } //TODO::单设备验证 cacheKey := fmt.Sprintf(TokenKey, claims.Uid) cJwt, err1 := cache.GetString(cacheKey) if err != nil { return nil, "", err1 } if cJwt != tokenString && cJwt != "" { return nil, "", errors.New("token expired") } // TODO::判断Token快过期,就创建新的token(7天) if !claims.VerifyExpiresAt(time.Now().Add(time.Hour*24*7).Unix(), false) { newToken, _ := GenToken(claims.Uid) return claims, newToken, nil } // TODO::判断缓存是否为空,若为空则填补 if cJwt == "" { _, err = cache.SetEx(cacheKey, token, CalculateSecondsUntilExpiry(time.Unix(claims.ExpiresAt, 0))) if err != nil { return nil, "", err } } return claims, "", err } return nil, "", errors.New("invalid token") } // CalculateSecondsUntilExpiry 计算 Token 距离现在的过期时间还有多少秒 func CalculateSecondsUntilExpiry(expiryTime time.Time) int { return int(expiryTime.Sub(time.Now()).Seconds()) }