token.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package token
  2. import (
  3. "crypto/rand"
  4. "errors"
  5. "fmt"
  6. "math/big"
  7. "time"
  8. "github.com/golang-jwt/jwt"
  9. "github.com/google/uuid"
  10. )
  11. var (
  12. ErrInvalidToken = errors.New("token is invalid")
  13. ErrExpiredToken = errors.New("token has expired")
  14. ErrTokenUnknown = errors.New("token unknown error")
  15. ErrNotEvenAToken = errors.New("not even a token")
  16. ErrUnhandleToken = errors.New("unhandel token")
  17. )
  18. type Maker interface {
  19. CreateToken(issuer, username string, duration time.Duration) (string, error)
  20. VerifyToken(token string) (*CustomClaims, error)
  21. }
  22. type CustomClaims struct {
  23. UserName string `json:"user_name"`
  24. jwt.StandardClaims
  25. }
  26. func NewCustomClaim(issuer, username string, duration time.Duration) (*CustomClaims, error) {
  27. tokenID, err := uuid.NewRandom()
  28. if err != nil {
  29. return nil, err
  30. }
  31. claims := CustomClaims{
  32. username,
  33. jwt.StandardClaims{
  34. Id: tokenID.String(),
  35. IssuedAt: time.Now().Unix(),
  36. ExpiresAt: time.Now().Add(duration).Unix(),
  37. Issuer: issuer,
  38. },
  39. }
  40. return &claims, nil
  41. }
  42. type JWTMaker struct {
  43. secretKey string
  44. }
  45. const minSecretKeySize = 32
  46. func NewJWTMaker(secretKey string) (Maker, error) {
  47. if len(secretKey) < minSecretKeySize {
  48. return nil, fmt.Errorf("invalid key size: must be at least %d characters", minSecretKeySize)
  49. }
  50. return &JWTMaker{secretKey}, nil
  51. }
  52. func (maker *JWTMaker) CreateToken(issuer, username string, duration time.Duration) (string, error) {
  53. customClaim, err := NewCustomClaim(issuer, username, duration)
  54. if err != nil {
  55. return "", err
  56. }
  57. jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, customClaim)
  58. return jwtToken.SignedString([]byte(maker.secretKey))
  59. }
  60. // VerifyToken checks if the token is valid or not
  61. func (maker *JWTMaker) VerifyToken(token string) (*CustomClaims, error) {
  62. keyFunc := func(token *jwt.Token) (interface{}, error) {
  63. _, ok := token.Method.(*jwt.SigningMethodHMAC)
  64. if !ok {
  65. return nil, ErrInvalidToken
  66. }
  67. return []byte(maker.secretKey), nil
  68. }
  69. jwtToken, err := jwt.ParseWithClaims(token, &CustomClaims{}, keyFunc)
  70. if err != nil {
  71. if verr, ok := err.(*jwt.ValidationError); ok {
  72. if verr.Errors&jwt.ValidationErrorMalformed != 0 {
  73. return nil, ErrNotEvenAToken
  74. } else if verr.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
  75. return nil, ErrExpiredToken
  76. } else {
  77. return nil, ErrUnhandleToken
  78. }
  79. } else {
  80. return nil, ErrTokenUnknown
  81. }
  82. }
  83. payload, ok := jwtToken.Claims.(*CustomClaims)
  84. if !ok {
  85. return nil, ErrInvalidToken
  86. }
  87. return payload, nil
  88. }
  89. func GenerateSecretKey() (string, error) {
  90. n := 120
  91. const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
  92. ret := make([]byte, n)
  93. for i := 0; i < n; i++ {
  94. num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
  95. if err != nil {
  96. return "", err
  97. }
  98. ret[i] = letters[num.Int64()]
  99. }
  100. return string(ret), nil
  101. }