废话不多说,直接上代码
package main import ( "errors" "fmt" "github.com/dgrijalva/jwt-go" "log" "time" ) // 一些常量 var ( TokenExpired error = errors.New("Token is expired") TokenNotValidYet error = errors.New("Token not active yet") TokenMalformed error = errors.New("That's not even a token") TokenInvalid error = errors.New("Couldn't handle this token:") SignKey string = "newtrekWang" hmacSampleSecret string = "xTcDKckjG37IrfRoCs35uEc13mF%vuNYlBM%gLznpVmN6yoEEj1H6F9wpjBfmq7k" ) type JWT struct { SigningKey []byte } type CustomClaims struct { Subject int64 `json:"sub"` Prv string `json:"prv"` jwt.StandardClaims } func NewJWT(secret string) *JWT { return &JWT{SigningKey: []byte(secret)} } //创建token func (j *JWT) CreateToken(claims CustomClaims) (string, error) { token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims res, err := token.SignedString(j.SigningKey) fmt.Println("err:", err) return res, err } //解析token func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { log.Panicln("unexpected signing method") return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return j.SigningKey, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { return claims, nil } return nil, TokenInvalid } //更新token func (j *JWT) RefreshToken(tokenString string) (string, error) { token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { return j.SigningKey, nil }) if err != nil { return "", err } if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix() return j.CreateToken(*claims) } return "", TokenInvalid } func (j *JWT) GenerateToken(uid int64) (string, error) { now := int64(time.Now().Unix()) claims := CustomClaims{ uid, "23bd5c8949f600adb39e701c400872db7a5976f7", jwt.StandardClaims{ IssuedAt: now, NotBefore: now - 60, ExpiresAt: now + 1000, Issuer: "man", }, } token, err := j.CreateToken(claims) if err != nil { return "", err } return token, nil } func main() { jwt.TimeFunc = time.Now tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjciLCJleHAiOjE1ODI5NDM1NTEsImlhdCI6MTU4Mjk0MjU1MSwiaXNzIjoibWFuIiwibmJmIjoxNTgyOTQyNDkxfQ.KTP1RWWaHpcPknNTiYeE-iAY9qOJscdJ5r5BbNlYCho" j := NewJWT(hmacSampleSecret) // Parse takes the token string and a function for looking up the key. The latter is especially // useful if you use multiple keys for your application. The standard is to use 'kid' in the // head of the token to identify which key to use, but the parsed token (head and claims) is provided // to the callback, providing flexibility. claims, err := j.ParseToken(tokenString) if err == nil { fmt.Printf("user id:%d\n", claims.Subject) fmt.Printf("%+v\n", claims) } else { fmt.Println(err.Error()) } new_token, err := j.GenerateToken(1) if err != nil { fmt.Println(err.Error()) return } fmt.Println(new_token) }
hmacSampleSecret
是 JWT 的密钥23bd5c8949f600adb39e701c400872db7a5976f7
这个是 Laravel JWT 为了辨别 Token 是哪个 Model 发的添加的自定义字段prv
,其实这个字段可以用预定义的某个字段来实现的Subject
用于存放 ID,也就是sub
字段注意里面的过期时间。
另外,JWT 是没有失效这一说说法的。这是因为 PHP Laravel 封装的太死了。如果要失效,可以添加一个
last_login
字段当作 JWT 的issue at
。然后每次校验的时候检查下last_login
字段是否一样即可。如果你不想用last_login
,那么可以用其它字段,只要每次登录自动会改变即可。很多东西,没必要搞自己那么一套
《本文》有 0 条评论