Go使用JWT

Go使用JWT

標籤(空格分隔):go,auth,jwt

訪問官網 【https://jwt.io/】

jwt生成的token,是三部分組成 由.分割
`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`
  • 第一部分:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    Header(頭部)
    { "alg": "HS256", // 加密算法 "typ": "JWT" // 類型 JWT }
  • 第二部分:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
    Payload(負載)
    { "sub": "1234567890", "name": "John Doe", "iat": 1516239022, // 簽發時間 "exp": 1516239022, // 過期時間 "issuer":"auth", // 簽發人 }
  • 第三部分:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    Signature(簽名)
    HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), 【your-256-bit-secret】 ) secret base64 encoded

我使用的第三方包是:https://github.com/dgrijalva/jwt-go

Encode 加密方式爲:RS512

package token

import (
	"car/shared/id"
	"crypto/rsa"
	"github.com/dgrijalva/jwt-go"
	"time"
)

type JWTTokenGen struct {
	privateKey *rsa.PrivateKey
	issuer     string
	nowFunc    func() time.Time
}

func NewJWTTokenGen(issuer string, privateKey *rsa.PrivateKey) *JWTTokenGen {
	return &JWTTokenGen{
		privateKey: privateKey,
		issuer:     issuer,
		nowFunc:    time.Now,
	}
}

func (j *JWTTokenGen) GeneratorToken(accountId id.AccountId, expired time.Duration) (string, error) {

	now := j.nowFunc().Unix()
	exp := now + int64(expired.Seconds())
	token := jwt.NewWithClaims(jwt.SigningMethodRS512, jwt.StandardClaims{
		ExpiresAt: exp,
		IssuedAt:  now,
		Issuer:    j.issuer,
		Subject:   accountId.String(),
	})
	return token.SignedString(j.privateKey)
}


# test測試

package token

import (
	"car/shared/id"
	"github.com/dgrijalva/jwt-go"
	"testing"
	"time"
)

const privateKey = `-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC3+K2kVZ8Rhbqd
Zm2lvbT1nxxxJKamY+4uyyeOeDkMZMuLxyg4fFAbGJ0yNyPFa7h+6foOUEQbwLvy
wZVOsaF7yQgMH7ROfS5v7C1i70FbjfkPblCQLnbwUB6p6yM+Dag68o1FpK91pVc7
WJr+ex8pWwt6Xva9t37tWabyXMorB55dTtYdKN3KPAy9kmA5rbJAhHfb64OABJwA
OwWhQk2ccq62O7Na9I4XZcRgMmdSkbaKHd5HWJKJ3KXt8jWQDNHDm71F9yMmSfqq
K7gOhcLWmsRiUQDYOHltGn8qhACTha69Rx1TRYWm/hyKzwpWlTBhM1BSL0cbG7ab
TDjuaHD1AgMBAAECggEAVDeJvc3YSJwwRneqQBIs8bfJvF2r0EW0tkUXsZeFfg/y
QeWEmv8FaLIG3ALz5B8g0TBo4P6LfyzmnQVTRTf5lYH8phgpYTja9i9mw4CFKdU/
K3ozdR1gIzh6IQzcED8OQRXh5/ywualb2nYAVfik1jiwc29fgo+qkhrVWuNxROqs
LsXlyMAodTZIAPnrFnT9XYtwhS4+JIraIe/7d3dy/VL8NN54tdfTj+nhA8r2K2/y
6tBNerndLCyulpTQdYYIpV4WWCwK0x9CRnk5uYI9cIihrm7uJ4cXMEHF9LozdI+Y
cijkHZ1j/GEBiVWDAf6Bjh7CesHWuduSl2uXPik9zQKBgQDdo6+g/cBfAOBgBHFx
mykOip45R8iFtVkQ6Kls+e/0o8h8oebYtbFB3WYDI+Ds6Oc6SoCejg2Gxhszcu1l
gUwedo1E5Yyuu0wXCB9+A/W/TEaYcb8SbBle/rRxf+WdVAFQajhPL+jC6drERUHG
9yjK75OWOaGfQl075NOlDUbu8wKBgQDUfgsg9kvkBP1BMi3b7+oKCveOtQz5LVin
89+/PqfwTGH+MyFGgCgXR/1Oc6wgBM3nK2xVwYHub65GhBpiSR1Vbx08H1+m5eat
CET4RVJJRAzMpF+MFWXlVe0aqHVgVPOfTkJm+CEthfsCgvsW0T/6IHsBDWXe1hIX
Qplj3baqdwKBgASoKMuIKV+VpCFAVqXdbbppfTOU54ivq8RoLw8kHT+VpWPA/xm0
j5njrf4I5fP0XM9ju1oZf/1B8lZdZtGIKvJE6Wj2LcOKGeot+INsT+CKGL2hPjOD
4/CUB3SPDGMG3dQztyUqy4g046zWC7DDhq7k48P3SAcRnOXiQ/Qm2EOzAoGANBaF
odneNpHmhtHHHg/MfhO8JXZKLNap0dndMiMoxaXjq41bDc4ihbp25IFEY0DqPE2P
q+HYeNtVjCGb2hX0I9ot/2vtZZsblbTeO0G67wzIWm28ojkoljQfABblVuzcH2Pu
sREICQG7yxzScgBvP2Aw5swi+aHeI2eG9E0IFvcCgYApo4CJVYUsYkujJUdFmN/s
28SVVnX0G5+qBMiPvmybsc9+Fl9a3BgsyC+uaX3RxMFZLCRTeKZNxJ3+TbulJ2Hf
zYelZmjw0cU2in3zSf+N/1w0B1yd+ISHB8KARQLGLdMfrrN22J4gS9seIi5p1Vxn
jsURET4gnIFKE01t7IlI+w==
-----END PRIVATE KEY-----`

func TestJWTTokenGen_GeneratorToken(t *testing.T) {

	pem, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
	if err != nil {
		t.Fatalf("parse rsa private key error: %v\n", err)
	}

	accountId := "o1dDm4g17xaNm6W3HBh9bzVMtW5Y"
	class := NewJWTTokenGen("car-auth", pem)
	class.nowFunc = func() time.Time {
		return time.Unix(1684209185, 0)
	}
	token, err := class.GeneratorToken(id.AccountId(accountId), 2*time.Hour)
	if err != nil {
		t.Errorf("genrator token error %v\n", err)
	}

	want := "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODQyMTYzODUsImlhdCI6MTY4NDIwOTE4NSwiaXNzIjoiY2FyLWF1dGgiLCJzdWIiOiJvMWREbTRnMTd4YU5tNlczSEJoOWJ6Vk10VzVZIn0.sHr9TgB1U8n0AQhIAoLCsBPyFaOcFda2DRMytbR6eXJS3D8y1iMLaA2FM9MvMj4iF4-EGcv4jHiGwGnDjbc-2kQVYheszm9cLFtLZ8FLRSBp_cLw-fCwy0_6_kcsLI3bLZdANxuaOHva9kNvL2jks-iLdQNB2HlKoaZafH24r7P1fUOHmzE0RbrKTYpPaAXxI38SBbtHk6lamJNQSfoKCrqYA2LcgUDUd0mQCCNBQHPrIntBBaV2oOwd61tOIkGrgDExFmqQ3c_kGTSenrZrUCGY28hx8FuG6v_w9jDYi6c-U-jAkiRyNVA3IkbaA_svQdvmLxGuMqxcCsrwkhyQ9g"
	if token != want {
		t.Errorf("want error \n want %q \n token %q \n", want, token)
	}
}

Decode 解密

package token

import (
	"crypto/rsa"
	"fmt"
	"github.com/dgrijalva/jwt-go"
)

type JWTTokenVerifier struct {
	PublicKey *rsa.PublicKey
}

func NewJWTTokenVerifier(key *rsa.PublicKey) *JWTTokenVerifier {
	return &JWTTokenVerifier{
		PublicKey: key,
	}
}

func (j *JWTTokenVerifier) Verify(token string) (string, error) {

	t, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
		return j.PublicKey, nil
	})

	if err != nil {
		return "", err
	}

	if !t.Valid {
		return "", fmt.Errorf("token is not valid")
	}
	claims, ok := t.Claims.(*jwt.StandardClaims)
	if !ok {
		return "", fmt.Errorf("token claims is not StandarClaims")
	}
	err = claims.Valid()
	if err != nil {
		return "", err
	}
	return claims.Subject, nil
}


# test測試

package token

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"testing"
)

const PublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAztkC5tzKUvwoy9gYVfgk
LqrybhF8eJ0hV/+vnmSxyuCC53Hyyk3IOlKX3cl62icqRr5oCM1KV9BvjzsZS8Pe
kcmCO2J8Z+EaaAhSq5wteoxEzmuMjyWWn2BhhF8ZjYeSckQy3BCtaCW7aNKMbklL
Q97FSvKIhYllwokqgPr8M9eHwAtiIHXRc5f+5VGqgSSVZFYNah7Rrdp1pbdJWNhV
l4nDcGQBKoB3VrISZgUJQyHIaGiL+Q/ehDUAiVXjQr/rveU8IgijfEK075vmMZXN
935rx4tR1AQDGgi3QO3muIw/1pziIo05VeSt0k3Vy+Jlb3K3ggk3dg97I/4mEmFE
vQIDAQAB
-----END PUBLIC KEY-----`

func TestJWTTokenVerifier_Verify(t *testing.T) {
	pem, err := jwt.ParseRSAPublicKeyFromPEM([]byte(PublicKey))
	if err != nil {
		t.Fatalf("parse public.key file error: %v\n", err)
	}
	class := NewJWTTokenVerifier(pem)
	verify, err := class.Verify("eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2ODQyMTY4OTMsImlhdCI6MTY4NDIxMTI4NiwiaXNzIjoiY2FyLWF1dGgiLCJzdWIiOiI2NDYxZmQ2YWYwYzQ1ZTllMDBhZDJhMDUifQ.WWsALGlLVzfKKy96cIHh0KI3CdP1MJy70SxBVWi89k10qJD5ib8haK-bz9OJDCd5ciBz_6YetLhmr9XSN1QaqdwmAyqr8NWhFhl_S8eb2hIkxO0rk010xQDcO4YZvhSHlJBm8S2HgTb_Lc1OISgZ18r7IupQe7ZrXV3exlNGygdh1mMmWUYP0LAKKpQpEHMQIfb7jbPpfS6W3bSXfrVysz2bJz2b-adpfea9oLYEzLoaw1TUmTWMeTXjjqycnqwN4ENt1s9LdekyOgQ0P2WvAKaA0ER38CmI2WtEEAxRYnIZASO0x591B24Ket4Tgh_va4rbJx1xeogcsZIqX6Z3sg")
	if err != nil {
		t.Fatalf("token verify error: %v\n", err)
	}
	fmt.Println(verify)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章