gitee.com/h79/goutils@v1.22.10/auth/jwt/token.go (about)

     1  package jwt
     2  
     3  import (
     4  	"encoding/base64"
     5  	"errors"
     6  	"fmt"
     7  	"gitee.com/h79/goutils/auth/token"
     8  	"gitee.com/h79/goutils/common/result"
     9  	"gitee.com/h79/goutils/common/timer"
    10  	"github.com/golang-jwt/jwt/v5"
    11  	"time"
    12  )
    13  
    14  type UpdateJWTClaims func(tk token.Token) jwt.Claims
    15  
    16  // 保证 Token struct implement token.Token
    17  var _ token.Token = (*Token)(nil)
    18  
    19  type Token struct {
    20  	Uid     string       `json:"uid"`
    21  	Token   string       `json:"token"`
    22  	Session string       `json:"-"` //for server and server
    23  	Extend  string       `json:"-"`
    24  	Source  token.Source `json:"-"`
    25  	expire  timer.Expire
    26  	ujc     UpdateJWTClaims
    27  	key     token.Key
    28  	custom  interface{}
    29  	base64  bool
    30  }
    31  
    32  func NewToken(key token.Key, ujc UpdateJWTClaims, base64 bool) *Token {
    33  	return &Token{
    34  		ujc:    ujc,
    35  		key:    key,
    36  		base64: base64,
    37  	}
    38  }
    39  
    40  func (tk *Token) WithVar(key string, value interface{}) token.Token {
    41  	switch key {
    42  	case token.CSource:
    43  		tk.Source = value.(token.Source)
    44  	case token.CSession:
    45  		tk.Session = value.(string)
    46  	case token.CExtend:
    47  		tk.Extend = value.(string)
    48  	case token.CUid:
    49  		tk.Uid = value.(string)
    50  	case token.CCustom:
    51  		tk.custom = value
    52  	case token.CIssuedAt:
    53  		tk.expire.StartIn = value.(int64)
    54  	case token.CExpiresAt:
    55  		tk.expire.ExpireIn = value.(int64)
    56  	}
    57  	return tk
    58  }
    59  
    60  func (tk *Token) GetVar(key string) interface{} {
    61  	switch key {
    62  	case token.CSource:
    63  		return tk.Source
    64  	case token.CSession:
    65  		return tk.Session
    66  	case token.CUid:
    67  		return tk.Uid
    68  	case token.CBase64:
    69  		return tk.base64
    70  	case token.CCustom:
    71  		return tk.custom
    72  	case token.CExtend:
    73  		return tk.Extend
    74  	case token.CIssuedAt:
    75  		return tk.expire.StartIn
    76  	case token.CExpiresAt:
    77  		return tk.expire.ExpireIn
    78  	}
    79  	return ""
    80  }
    81  
    82  func (tk *Token) GetToken() string {
    83  	return tk.Token
    84  }
    85  
    86  // ExpireIn token.Token interface
    87  func (tk *Token) ExpireIn() int64 {
    88  	return tk.key.ExpireIn()
    89  }
    90  
    91  // Update token.Token interface
    92  func (tk *Token) Update() (string, error) {
    93  	jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, tk.jwtClaims())
    94  	tStr, err := jwtToken.SignedString(tk.key.Key())
    95  	if err != nil {
    96  		return "", err
    97  	}
    98  	if tk.base64 {
    99  		tk.Token = base64.StdEncoding.EncodeToString([]byte(tStr))
   100  	} else {
   101  		tk.Token = tStr
   102  	}
   103  	return tk.Token, nil
   104  }
   105  
   106  func (tk *Token) jwtClaims() jwt.Claims {
   107  	if tk.ujc != nil {
   108  		return tk.ujc(tk)
   109  	}
   110  	var ex = tk.expire
   111  	if tk.expire.StartIn <= 0 {
   112  		ex = timer.NowExpireWithSecond(tk.ExpireIn())
   113  	}
   114  	return &jwtClaims{
   115  		Subject:   tk.Uid,
   116  		IssuedAt:  jwt.NewNumericDate(time.Unix(ex.StartIn, 0)),
   117  		ExpiresAt: jwt.NewNumericDate(time.Unix(ex.ExpireIn, 0)),
   118  		Source:    tk.Source,
   119  		Session:   tk.Session,
   120  		Extend:    tk.Extend,
   121  	}
   122  }
   123  
   124  var defJWTFactory jwtFactory
   125  
   126  type jwtFactory struct {
   127  }
   128  
   129  func (f *jwtFactory) Create(key token.Key, opts ...token.Option) (token.Token, error) {
   130  	return NewToken(key, nil, token.IsBase64Enabled(opts...)), nil
   131  }
   132  
   133  func (f *jwtFactory) Decode(tk string, opts ...token.Option) (token.Token, error) {
   134  	if token.IsBase64Enabled(opts...) {
   135  		return DecodeToken(tk)
   136  	}
   137  	return DecodeTokenNoBase64(tk)
   138  }
   139  
   140  func (f *jwtFactory) Check(tk string, key token.Key, opts ...token.Option) (token.Token, error) {
   141  	if token.IsBase64Enabled(opts...) {
   142  		return VerifyToken(tk, key)
   143  	}
   144  	return VerifyTokenNoBase64(tk, key)
   145  }
   146  
   147  // DecodeToken 不需要认证,解包里面的信息
   148  func DecodeToken(tk string) (token.Token, error) {
   149  	bytes, er := base64.StdEncoding.DecodeString(tk)
   150  	if er != nil {
   151  		return nil, er
   152  	}
   153  	return DecodeTokenNoBase64(string(bytes))
   154  }
   155  
   156  func DecodeTokenNoBase64(tk string) (token.Token, error) {
   157  
   158  	// for 读取信息,不验证
   159  	tc := jwtClaims{}
   160  	jtk, err := jwt.ParseWithClaims(tk, &tc, nil)
   161  	if jtk != nil {
   162  		return tc.To(tk), nil
   163  	} else if errors.Is(err, jwt.ErrTokenMalformed) {
   164  		fmt.Println("That's not even a token")
   165  	} else if errors.Is(err, jwt.ErrTokenSignatureInvalid) {
   166  		// Invalid signature
   167  		fmt.Println("Invalid signature")
   168  	} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
   169  		// Token is either expired or not active yet
   170  		fmt.Println("Timing is everything")
   171  	} else {
   172  		fmt.Println("Couldn't handle this token:", err)
   173  	}
   174  	return nil, err
   175  }
   176  
   177  // VerifyToken 需要认证,解包里面的信息
   178  func VerifyToken(tk string, key token.Key) (token.Token, error) {
   179  	bytes, er := base64.StdEncoding.DecodeString(tk)
   180  	if er != nil {
   181  		return nil, er
   182  	}
   183  
   184  	return VerifyTokenNoBase64(string(bytes), key)
   185  }
   186  
   187  func VerifyTokenNoBase64(tk string, key token.Key) (token.Token, error) {
   188  
   189  	tc := jwtClaims{}
   190  	jtk, err := jwt.ParseWithClaims(tk, &tc, func(token *jwt.Token) (interface{}, error) {
   191  		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
   192  			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
   193  		}
   194  		return key.Key(), nil
   195  	})
   196  	if err == nil && jtk.Valid {
   197  		tok := tc.To(tk)
   198  		tok.key = key
   199  		return tok, nil
   200  	}
   201  	code := result.ErrToken
   202  	if errors.Is(err, jwt.ErrTokenMalformed) {
   203  		code |= result.TokenMalformed
   204  	} else if errors.Is(err, jwt.ErrTokenUnverifiable) {
   205  		code |= result.TokenUnVerify
   206  	} else if errors.Is(err, jwt.ErrTokenSignatureInvalid) {
   207  		code |= result.TokenSigned
   208  	} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
   209  		// Token is either expired or not active yet
   210  		code |= result.TokenExpired
   211  	} else {
   212  		code |= result.TokenOther
   213  	}
   214  	return nil, result.ErrCode(code).WithError(err)
   215  }
   216  
   217  type jwtClaims struct {
   218  	Source    token.Source     `json:"source"`
   219  	Session   string           `json:"session"`
   220  	Extend    string           `json:"extend"`
   221  	Subject   string           `json:"sub,omitempty"`
   222  	ExpiresAt *jwt.NumericDate `json:"exp,omitempty"`
   223  	IssuedAt  *jwt.NumericDate `json:"iat,omitempty"`
   224  }
   225  
   226  // GetExpirationTime implements the Claims interface.
   227  func (tc *jwtClaims) GetExpirationTime() (*jwt.NumericDate, error) {
   228  	return tc.ExpiresAt, nil
   229  }
   230  
   231  // GetNotBefore implements the Claims interface.
   232  func (tc *jwtClaims) GetNotBefore() (*jwt.NumericDate, error) {
   233  	return nil, nil
   234  }
   235  
   236  // GetIssuedAt implements the Claims interface.
   237  func (tc *jwtClaims) GetIssuedAt() (*jwt.NumericDate, error) {
   238  	return tc.IssuedAt, nil
   239  }
   240  
   241  // GetAudience implements the Claims interface.
   242  func (tc *jwtClaims) GetAudience() (jwt.ClaimStrings, error) {
   243  	return jwt.ClaimStrings{}, nil
   244  }
   245  
   246  // GetIssuer implements the Claims interface.
   247  func (tc *jwtClaims) GetIssuer() (string, error) {
   248  	return "", nil
   249  }
   250  
   251  // GetSubject implements the Claims interface.
   252  func (tc *jwtClaims) GetSubject() (string, error) {
   253  	return tc.Subject, nil
   254  }
   255  
   256  func (tc *jwtClaims) To(tk string) *Token {
   257  	return &Token{
   258  		Session: tc.Session,
   259  		Uid:     tc.Subject,
   260  		Token:   tk,
   261  		Extend:  tc.Extend,
   262  		Source:  tc.Source,
   263  		expire:  timer.Expire{StartIn: tc.IssuedAt.Unix(), ExpireIn: tc.ExpiresAt.Unix()},
   264  	}
   265  }