在Golang中创建和验证一个JWT HMAC令牌的实例

246 阅读1分钟

在这个例子中,我们将使用HMAC HS256签名创建一个JWT令牌并进行验证。HSA是一种对称的签名方法,只使用一个秘密密钥。只有在令牌的创建者(服务器应用)和用户(客户端应用)都是100%信任的情况下,才能使用这种方法。如有疑问,可选择使用私钥和公钥的RSA。

main.go

你可以使用类似这样的东西来创建一个秘密:

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/you/auth/internal/pkg/token"
)

func main() {
	// You can inject this instance to where you need it.
	jwtToken := token.NewJWT([]byte("your-256-bit-static-secret"))

	// 1. Create a new JWT token.
	tok, err := jwtToken.Create(time.Hour, "Can be anything")
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("TOKEN:", tok)

	// 2. Validate an existing JWT token.
	content, err := jwtToken.Validate(tok)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("CONTENT:", content)
}

token.go

package token

import (
	"fmt"
	"time"

	"github.com/dgrijalva/jwt-go"
)

type JWT struct {
	key []byte
}

func NewJWT(key []byte) JWT {
	return JWT{
		key: key,
	}
}

func (j JWT) Create(ttl time.Duration, content interface{}) (string, error) {
	now := time.Now().UTC()

	claims := make(jwt.MapClaims)
	claims["dat"] = content             // Our custom data.
	claims["exp"] = now.Add(ttl).Unix() // The expiration time after which the token must be disregarded.
	claims["iat"] = now.Unix()          // The time at which the token was issued.
	claims["nbf"] = now.Unix()          // The time before which the token must be disregarded.

	token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(j.key)
	if err != nil {
		return "", fmt.Errorf("create: %w", err)
	}

	return token, nil
}

func (j JWT) Validate(token string) (interface{}, error) {
	tok, err := jwt.Parse(token, func(jwtToken *jwt.Token) (interface{}, error) {
		if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected method: %s", jwtToken.Header["alg"])
		}

		return j.key, nil
	})
	if err != nil {
		return nil, fmt.Errorf("validate: %w", err)
	}

	claims, ok := tok.Claims.(jwt.MapClaims)
	if !ok || !tok.Valid {
		return nil, fmt.Errorf("validate: invalid")
	}

	return claims["dat"], nil
}

测试

使用jwt.io来解码token和JSON Web Token(JWT),以了解更多关于JWT的一般信息:

$ go run -race main.go

TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXQiOiJDYW4gYmUgYW55dGhpbmciLCJleHAiOjE2MDQyNDAxMDUsImlhdCI6MTYwNDIzNjUwNSwibmJmIjoxNjA0MjM2NTA1fQ.iEkDvKJ2fscx20SDSM6QGxAe6S0nJYA9KTLZDTiiXVc

CONTENT: Can be anything