安装 当前最新版本为v4版本,新增了 Go 模块支持,但依旧保留了向后兼容性
1 go get -u github.com/golang-jwt/jwt/v4
官方规定的一些声明Claims(载荷) 这些声明都是可选的,不强制的。只是为后续操作提供方便,可操作性的起始点数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type RegisteredClaims struct { Issuer string `json:"iss,omitempty"` Subject string `json:"sub,omitempty"` Audience ClaimStrings `json:"aud,omitempty"` ExpiresAt *NumericDate `json:"exp,omitempty"` NotBefore *NumericDate `json:"nbf,omitempty"` IssuedAt *NumericDate `json:"iat,omitempty"` ID string `json:"jti,omitempty"` }
对称加密 (例如 HSA)仅使用一个密钥。这可能是最简单的签名方法,因为任何[]byte都可以用作有效的秘密。它们在计算上的使用速度也略快一些,尽管这很少有关系。当令牌的生产者和消费者都受信任,甚至是同一个系统时,对称签名方法效果最好。由于相同的密钥用于签名和验证令牌,因此您无法轻松分发密钥以进行验证。
代码实现 生成token 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const signKey = "this is your sign key" type CustomClaims struct { jwt.RegisteredClaims Email string `json:"email"` } func (*helloApi) CreateToken(r *ghttp.Request) { nowTime := time.Now() userId := "123456" appName := "coolcar" expireIn := 7 * 24 * time.Hour var token = jwt.NewWithClaims(jwt.SigningMethodHS256, CustomClaims{ RegisteredClaims: jwt.RegisteredClaims{ Issuer: appName, Subject: userId, ExpiresAt: jwt.NewNumericDate(nowTime.Add(expireIn)), NotBefore: jwt.NewNumericDate(nowTime), IssuedAt: jwt.NewNumericDate(nowTime), }, Email: "595929049@qq.com" , }) tokenString, _ := token.SignedString([]byte (signKey)) _ = r.Response.WriteJson(g.Map{ "token" : tokenString, "expire_in" : int (expireIn.Seconds()), }) }
使用token 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func (*helloApi) ParseToken(r *ghttp.Request) { tokenString := r.GetHeader("authorization" ) tokenString = strings.TrimPrefix(tokenString, "Bearer " ) token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func (token *jwt.Token) (interface {}, error ) { return []byte (signKey), nil }) claims, ok := token.Claims.(*CustomClaims) if !ok || !token.Valid { if errors.Is(err, jwt.ErrTokenMalformed) { r.Response.WriteExit("That's not even a token" ) } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) { r.Response.WriteExit("Timing is everything" ) } else { r.Response.WriteExit("Couldn't handle this token:" , err) } } _ = r.Response.WriteJson(g.Map{ "email" : claims.Email, "user_id" : claims.Subject, "app_name" : claims.Issuer, }) }
非对称加密 (例如 RSA)使用不同的密钥来签名和验证令牌。这使得使用私钥生成令牌成为可能,并允许任何消费者访问公钥进行验证。
代码实现 生成token 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 const privateKey = `-----BEGIN PRIVATE KEY----- MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAs57i3yugK3vbC6G2 UVTw8Vk7BMARaSN1W6ouF59X2N/8ocMbchNxofEudf/2X6Us2V1srFgvPC/CE1N2 ncDMXwIDAQABAkAT6VwbAzoJN/yrSGzujSz8hDi/qQ8FCbI7zBy576cMWnCKFwTT KDWfxaW9sISqsiHFoBiq0EHj99H0/x6o014pAiEA4g7yxcu2m6yOQSlaWsA9vHnd vuhrPcgXWQfQTqDGodUCIQDLaVrbH4H71uV/svegy4dG8T7U4c8/mil3x9qOowPb YwIhALn7DmUIyn2dI5Qcj4emLaSIppTP5pr3qa3HretifsjZAiBHkdsw7CYdCSCY zMyKG/KOCIX1+zmjhEeA6KXCuCK8RwIgC2synVWxCtKMJdj782Ksw5+rh8fM56Si tmgaHfusqJw= -----END PRIVATE KEY-----` type CustomClaims struct { jwt.RegisteredClaims Email string `json:"email"` } func (*helloApi) CreateToken(r *ghttp.Request) { nowTime := time.Now() userId := "123456" appName := "coolcar" expireIn := 7 * 24 * time.Hour var token = jwt.NewWithClaims(jwt.SigningMethodRS256, CustomClaims{ RegisteredClaims: jwt.RegisteredClaims{ Issuer: appName, Subject: userId, ExpiresAt: jwt.NewNumericDate(nowTime.Add(expireIn)), NotBefore: jwt.NewNumericDate(nowTime), IssuedAt: jwt.NewNumericDate(nowTime), }, Email: "595929049@qq.com" , }) privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte (privateKey)) if err != nil { log.Fatal("parse rsa private key error :" , err) } tokenString, _ := token.SignedString(privateKey) _ = r.Response.WriteJson(g.Map{ "token" : tokenString, "expire_in" : int (expireIn.Seconds()), }) }
结果 1 2 3 4 { "expire_in" : 604800 , "token" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjb29sY2FyIiwic3ViIjoiMTIzNDU2IiwiZXhwIjoxNjYwODA2OTYzLCJuYmYiOjE2NjAyMDIxNjMsImlhdCI6MTY2MDIwMjE2MywiZW1haWwiOiI1OTU5MjkwNDlAcXEuY29tIn0.cr4KPReapVGyiFjmNqGPEIIUrFLSO8PgpoWVFmMnWEzFzd9RBpwJdSLywcE5k7nrwpR9TexPk-hRnxgBta3t5w" }
使用token 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const publicKey = `-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALOe4t8roCt72wuhtlFU8PFZOwTAEWkj dVuqLhefV9jf/KHDG3ITcaHxLnX/9l+lLNldbKxYLzwvwhNTdp3AzF8CAwEAAQ== -----END PUBLIC KEY-----` func (*helloApi) ParseToken(r *ghttp.Request) { tokenString := r.GetHeader("authorization" ) tokenString = strings.TrimPrefix(tokenString, "Bearer " ) token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func (token *jwt.Token) (interface {}, error ) { return jwt.ParseRSAPublicKeyFromPEM([]byte (publicKey)) }) claims, ok := token.Claims.(*CustomClaims) if !ok || !token.Valid { if errors.Is(err, jwt.ErrTokenMalformed) { r.Response.WriteExit("That's not even a token" ) } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) { r.Response.WriteExit("Timing is everything" ) } else { r.Response.WriteExit("Couldn't handle this token:" , err) } } _ = r.Response.WriteJson(g.Map{ "email" : claims.Email, "user_id" : claims.Subject, "app_name" : claims.Issuer, }) }
结果 1 2 3 4 5 { "app_name" : "coolcar" , "email" : "595929049@qq.com" , "user_id" : "123456" }