123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- package token
- import (
- "crypto/rand"
- "errors"
- "fmt"
- "math/big"
- "time"
- "github.com/golang-jwt/jwt"
- "github.com/google/uuid"
- )
- var (
- ErrInvalidToken = errors.New("token is invalid")
- ErrExpiredToken = errors.New("token has expired")
- ErrTokenUnknown = errors.New("token unknown error")
- ErrNotEvenAToken = errors.New("not even a token")
- ErrUnhandleToken = errors.New("unhandel token")
- )
- type Maker interface {
- CreateToken(issuer, username string, duration time.Duration) (string, error)
- VerifyToken(token string) (*CustomClaims, error)
- }
- type CustomClaims struct {
- UserName string `json:"user_name"`
- jwt.StandardClaims
- }
- func NewCustomClaim(issuer, username string, duration time.Duration) (*CustomClaims, error) {
- tokenID, err := uuid.NewRandom()
- if err != nil {
- return nil, err
- }
- claims := CustomClaims{
- username,
- jwt.StandardClaims{
- Id: tokenID.String(),
- IssuedAt: time.Now().Unix(),
- ExpiresAt: time.Now().Add(duration).Unix(),
- Issuer: issuer,
- },
- }
- return &claims, nil
- }
- type JWTMaker struct {
- secretKey string
- }
- const minSecretKeySize = 32
- func NewJWTMaker(secretKey string) (Maker, error) {
- if len(secretKey) < minSecretKeySize {
- return nil, fmt.Errorf("invalid key size: must be at least %d characters", minSecretKeySize)
- }
- return &JWTMaker{secretKey}, nil
- }
- func (maker *JWTMaker) CreateToken(issuer, username string, duration time.Duration) (string, error) {
- customClaim, err := NewCustomClaim(issuer, username, duration)
- if err != nil {
- return "", err
- }
- jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, customClaim)
- return jwtToken.SignedString([]byte(maker.secretKey))
- }
- // VerifyToken checks if the token is valid or not
- func (maker *JWTMaker) VerifyToken(token string) (*CustomClaims, error) {
- keyFunc := func(token *jwt.Token) (interface{}, error) {
- _, ok := token.Method.(*jwt.SigningMethodHMAC)
- if !ok {
- return nil, ErrInvalidToken
- }
- return []byte(maker.secretKey), nil
- }
- jwtToken, err := jwt.ParseWithClaims(token, &CustomClaims{}, keyFunc)
- if err != nil {
- if verr, ok := err.(*jwt.ValidationError); ok {
- if verr.Errors&jwt.ValidationErrorMalformed != 0 {
- return nil, ErrNotEvenAToken
- } else if verr.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
- return nil, ErrExpiredToken
- } else {
- return nil, ErrUnhandleToken
- }
- } else {
- return nil, ErrTokenUnknown
- }
- }
- payload, ok := jwtToken.Claims.(*CustomClaims)
- if !ok {
- return nil, ErrInvalidToken
- }
- return payload, nil
- }
- func GenerateSecretKey() (string, error) {
- n := 120
- const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
- ret := make([]byte, n)
- for i := 0; i < n; i++ {
- num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
- if err != nil {
- return "", err
- }
- ret[i] = letters[num.Int64()]
- }
- return string(ret), nil
- }
|