jwt

package module
v0.0.0-...-7fbe588 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 2, 2024 License: MIT Imports: 16 Imported by: 0

README

JWT

本專案主要參考golang-jwt所製作,目的是為了更了解JWT

Usage

請參考:

學習

  • 演算法: 要做JWT之前應該對一些加密、驗證的算法有一些了解,因此建議可以參考crypto_test.go
  • 實作: 在演算法了解之後,可以嘗試用某幾種演算法去實作,HMAC是最簡單去做的,因為它是對稱式加密,沒有公鑰和私鑰,可以參考此次的提交
  • ISigningMethod: 在實做了幾種演算法之後,就可以找到相關的規律,可以將這些內容包裝在interface之中, commit

有些演算法比較特別(例如:ecdsa),為了要迎合接口的定義,需要特別安排加簽出來的內容

與golang-jwt的差異

自定義驗證

它在Parse之後就能使用token.Valid來判斷該jwt字串是否合法

本專案對此需要進一步的判斷才能得知,可以傳入自定義的Header驗證邏輯,或者Validate驗證函數

此內容請參考parser.validate


不預先註冊簽章方法

golang-jwt預設有幫忙註冊好演算法的方法名稱,因此其實他們並沒有特別提供header的驗證,會自動做好

本專案對此不提供預先的註冊,純粹讓使用者自己定義,因為並非所有伺服器都有支持很多種的加簽演算法

另外當您自己提供之後,也能對整個過程更清楚,而不會被語法糖所寵壞。

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidKey            = errors.New("key is invalid")
	ErrInvalidKeyType        = errors.New("key is of invalid type")
	ErrSignatureInvalid      = errors.New("signature is invalid")
	ErrHashUnavailable       = errors.New("the requested hash function is unavailable")
	ErrTokenMalformed        = errors.New("token is malformed")
	ErrTokenKeyFuncUnknown   = errors.New("token key func unknown")
	ErrTokenSignatureInvalid = errors.New("token signature is invalid")

	ErrTokenRequiredClaimMissing = errors.New("token is missing required claim")
	ErrClaimRequired             = errors.New("claim is required")

	ErrTokenInvalidAudience  = errors.New("token has invalid audience")
	ErrTokenExpired          = errors.New("token is expired")
	ErrTokenUsedBeforeIssued = errors.New("token used before issued")
	ErrTokenInvalidIssuer    = errors.New("token has invalid issuer")
	ErrTokenInvalidSubject   = errors.New("token has invalid subject")
	ErrTokenNotValidYet      = errors.New("token is not valid yet")
	ErrTokenInvalidId        = errors.New("token has invalid id")
	ErrTokenInvalidClaims    = errors.New("token has invalid claims")
	ErrInvalidType           = errors.New("invalid type for claim")
)
View Source
var ErrECDSAVerification = fmt.Errorf("%w %w",
	errors.New("ecdsa: verification error"),
	ErrSignatureInvalid,
)
View Source
var ErrEd25519Verification = fmt.Errorf("%w %w",
	errors.New("ed25519: verification error"),
	ErrSignatureInvalid,
)

ErrEd25519Verification 使其可以被兩種錯誤類型判別

View Source
var MarshalSingleStringAsArray = true

MarshalSingleStringAsArray 如果數值只是一個字串,就會把它變放進到slice裡面,即 "my-str" => ["my-str"]

View Source
var TimePrecision = time.Second

Functions

func GenSignBytes

func GenSignBytes(header map[string]any, claims IClaims) ([]byte, error)

GenSignBytes 依據header, claims生成出jwt需要被加簽的內容

func GenerateToken

func GenerateToken(method ISigningMethod, claims IClaims, key any) ([]byte, error)

Types

type ClaimStrings

type ClaimStrings []string

ClaimStrings 自定義了json.Unmarshal, json.MarshalJSON 為了 input => output string => [string] (需要透過 jwt.MarshalSingleStringAsArray 設定(預設啟用)) []any => []string

func (ClaimStrings) MarshalJSON

func (s ClaimStrings) MarshalJSON() (b []byte, err error)

func (*ClaimStrings) UnmarshalJSON

func (s *ClaimStrings) UnmarshalJSON(data []byte) (err error)

type IClaims

type IClaims interface {
	GetExpirationTime() (*NumericDate, error)
	GetIssuedAt() (*NumericDate, error)
	GetNotBefore() (*NumericDate, error)
	GetIssuer() (string, error)
	GetSubject() (string, error)
	GetAudience() (ClaimStrings, error)
}

IClaims https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely {exp, iat, nbf, iss, sub, aud} 之所以提供這個方法,只是為了在驗證的時候,可以避免用map打key的方式 另外因為驗證的時後claims我們能得到的資訊只有字串,所以這邊的工作還要負責把字串轉換成合適的型別

type ISigningMethod

type ISigningMethod interface {
	// AlgName HS256, RS512, ...
	AlgName() string

	// Sign SigningMethodHMAC.Sign, SigningMethodRSA.Sign
	Sign(signingBytes []byte, key any) ([]byte, error)

	// Verify SigningMethodHMAC.Verify, SigningMethodRSA.Verify
	Verify(signingBytes []byte,
		signature []byte,
		key any,
	) error
}

type KeyFunc

type KeyFunc func(*Token) (key any, err error)

KeyFunc 回傳值 key 為 ISigningMethod.Verify 所用到的key,因此可以根據token的類型去回傳特定的鑰匙 另外你也可以回傳 []key 的型態 請參考 parser.validate

type MapClaims

type MapClaims map[string]any

func (MapClaims) GetAudience

func (m MapClaims) GetAudience() (ClaimStrings, error)

GetAudience implements the Claims interface.

func (MapClaims) GetExpirationTime

func (m MapClaims) GetExpirationTime() (*NumericDate, error)

GetExpirationTime implements the Claims interface.

func (MapClaims) GetIssuedAt

func (m MapClaims) GetIssuedAt() (*NumericDate, error)

GetIssuedAt implements the Claims interface.

func (MapClaims) GetIssuer

func (m MapClaims) GetIssuer() (string, error)

GetIssuer implements the Claims interface.

func (MapClaims) GetNotBefore

func (m MapClaims) GetNotBefore() (*NumericDate, error)

GetNotBefore implements the Claims interface.

func (MapClaims) GetSubject

func (m MapClaims) GetSubject() (string, error)

GetSubject implements the Claims interface.

type NumericDate

type NumericDate struct {
	time.Time
}

NumericDate represents a JSON numeric date value, as referenced at https://datatracker.ietf.org/doc/html/rfc7519#section-2. 主要就是時間,但我們希望可以依據 jwt.TimePrecision 來變化爬取的規則

func NewNumericDate

func NewNumericDate(t time.Time) *NumericDate

func (NumericDate) MarshalJSON

func (date NumericDate) MarshalJSON() (b []byte, err error)

func (*NumericDate) UnmarshalJSON

func (date *NumericDate) UnmarshalJSON(b []byte) (err error)

type RegisteredClaims

type RegisteredClaims struct {
	// the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
	Issuer string `json:"iss,omitempty"`

	// the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
	Subject string `json:"sub,omitempty"`

	// the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
	// 我們希望他可以支持[]string, string兩種模式
	// 以及如果是傳入[]any,我們希望會變成[]string,這都是標準json對[]string或者string,沒辦法辦到的,所以我們需要自定義型別
	Audience ClaimStrings `json:"aud,omitempty"`

	// the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
	ExpiresAt *NumericDate `json:"exp,omitempty"`

	// the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
	NotBefore *NumericDate `json:"nbf,omitempty"`

	// the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
	IssuedAt *NumericDate `json:"iat,omitempty"`

	// the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
	ID string `json:"jti,omitempty"`
}

RegisteredClaims are a structured version of the JWT Claims Set, restricted to Registered Claim Names, as referenced at https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 在section-4.1就是以Registered Claim Names當作標題,所以此struct就用 RegisteredClaims 當成名稱

This type can be used on its own, but then additional private and public claims embedded in the JWT will not be parsed. The typical use-case therefore is embedded to this in a user-defined claim type.

See examples for how to use this with your own claim types. 這些項目為目前已經被註冊進去的標準

func (RegisteredClaims) GetAudience

func (c RegisteredClaims) GetAudience() (ClaimStrings, error)

GetAudience implements the IClaims interface.

func (RegisteredClaims) GetExpirationTime

func (c RegisteredClaims) GetExpirationTime() (*NumericDate, error)

GetExpirationTime implements the IClaims interface.

func (RegisteredClaims) GetIssuedAt

func (c RegisteredClaims) GetIssuedAt() (*NumericDate, error)

GetIssuedAt implements the IClaims interface.

func (RegisteredClaims) GetIssuer

func (c RegisteredClaims) GetIssuer() (string, error)

GetIssuer implements the IClaims interface.

func (RegisteredClaims) GetNotBefore

func (c RegisteredClaims) GetNotBefore() (*NumericDate, error)

GetNotBefore implements the IClaims interface.

func (RegisteredClaims) GetSubject

func (c RegisteredClaims) GetSubject() (string, error)

GetSubject implements the IClaims interface.

type SigningMethodECDSA

type SigningMethodECDSA struct {
	Name       string
	Hash       crypto.Hash
	KeyBitSize int
}
var (
	SigningMethodECDSA256 *SigningMethodECDSA
	SigningMethodECDSA384 *SigningMethodECDSA
	SigningMethodECDSA512 *SigningMethodECDSA
)

func (*SigningMethodECDSA) AlgName

func (m *SigningMethodECDSA) AlgName() string

AlgName implements the ISigningMethod interface

func (*SigningMethodECDSA) Sign

func (m *SigningMethodECDSA) Sign(signingBytes []byte, ecdsaPrivateKey any) ([]byte, error)

Sign implements the ISigningMethod interface

func (*SigningMethodECDSA) Verify

func (m *SigningMethodECDSA) Verify(signingBytes []byte, signature []byte, key any) error

Verify implements the ISigningMethod interface

type SigningMethodED25519

type SigningMethodED25519 struct{}

func (*SigningMethodED25519) AlgName

func (m *SigningMethodED25519) AlgName() string

AlgName implements the ISigningMethod interface

func (*SigningMethodED25519) Sign

func (m *SigningMethodED25519) Sign(signingBytes []byte, key any) ([]byte, error)

Sign implements the ISigningMethod interface

func (*SigningMethodED25519) Verify

func (m *SigningMethodED25519) Verify(signingBytes []byte, signature []byte, key any) error

Verify implements the ISigningMethod interface

type SigningMethodHMAC

type SigningMethodHMAC struct {
	Name string
	Hash crypto.Hash // Hash本質是一個uint
}
var (
	SigningMethodHMAC256 *SigningMethodHMAC
	SigningMethodHMAC384 *SigningMethodHMAC
	SigningMethodHMAC512 *SigningMethodHMAC
)

func (*SigningMethodHMAC) AlgName

func (m *SigningMethodHMAC) AlgName() string

func (*SigningMethodHMAC) Sign

func (m *SigningMethodHMAC) Sign(signingBytes []byte, key any) ([]byte, error)

func (*SigningMethodHMAC) Verify

func (m *SigningMethodHMAC) Verify(
	signingBytes []byte,
	signature []byte,
	key any,
) (err error)

type SigningMethodRSA

type SigningMethodRSA struct {
	Name string
	Hash crypto.Hash // 假設你用crypto.SHA512,那麼import必須要包含"crypto/sha512",否則會報錯
}
var (
	SigningMethodRSA256 *SigningMethodRSA
	SigningMethodRSA384 *SigningMethodRSA
	SigningMethodRSA512 *SigningMethodRSA
)

func (*SigningMethodRSA) AlgName

func (m *SigningMethodRSA) AlgName() string

func (*SigningMethodRSA) Sign

func (m *SigningMethodRSA) Sign(signingBytes []byte, key any) ([]byte, error)

func (*SigningMethodRSA) Verify

func (m *SigningMethodRSA) Verify(
	signingBytes []byte,
	signature []byte,
	key any,
) (err error)

type Token

type Token struct {
	Header map[string]any
	Claims IClaims
	// ISigningMethod // 不鑲嵌它,因為如果使用者直接調用這個方法,會需要處理前置header, claims要被URLEncode之後才能動作
	SigningMethod ISigningMethod
}

func New

func New(signingMethod ISigningMethod) *Token

func NewWithClaims

func NewWithClaims(signingMethod ISigningMethod, claims IClaims) *Token

func (*Token) SignedBytes

func (t *Token) SignedBytes(key any) ([]byte, error)

SignedBytes 取得到完整的jwt字串內容

func (*Token) SigningBytes

func (t *Token) SigningBytes() ([]byte, error)

SigningBytes 取得要被加簽的內容

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL