token.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package token
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. "github.com/dgrijalva/jwt-go"
  7. )
  8. type Subject string
  9. const (
  10. User Subject = "user"
  11. API Subject = "api"
  12. )
  13. type TokenGeneratorConf struct {
  14. TokenSecret string
  15. }
  16. type Token struct {
  17. SubKind Subject `json:"sub_kind"`
  18. Sub string `json:"sub"`
  19. ProjectID uint `json:"project_id"`
  20. IBy uint `json:"iby"`
  21. IAt *time.Time `json:"iat"`
  22. }
  23. func GetTokenForUser(userID uint) (*Token, error) {
  24. if userID == 0 {
  25. return nil, fmt.Errorf("id cannot be 0")
  26. }
  27. iat := time.Now()
  28. return &Token{
  29. SubKind: User,
  30. Sub: fmt.Sprintf("%d", userID),
  31. IBy: userID,
  32. IAt: &iat,
  33. }, nil
  34. }
  35. func GetTokenForAPI(userID, projID uint) (*Token, error) {
  36. if userID == 0 || projID == 0 {
  37. return nil, fmt.Errorf("id cannot be 0")
  38. }
  39. iat := time.Now()
  40. return &Token{
  41. SubKind: API,
  42. Sub: string(API),
  43. ProjectID: projID,
  44. IBy: userID,
  45. IAt: &iat,
  46. }, nil
  47. }
  48. func (t *Token) EncodeToken(conf *TokenGeneratorConf) (string, error) {
  49. token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
  50. "sub_kind": t.SubKind,
  51. "sub": t.Sub,
  52. "iby": t.IBy,
  53. "iat": fmt.Sprintf("%d", t.IAt.Unix()),
  54. "project_id": t.ProjectID,
  55. })
  56. // Sign and get the complete encoded token as a string using the secret
  57. return token.SignedString([]byte(conf.TokenSecret))
  58. }
  59. func GetTokenFromEncoded(tokenString string, conf *TokenGeneratorConf) (*Token, error) {
  60. token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  61. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  62. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  63. }
  64. return []byte(conf.TokenSecret), nil
  65. })
  66. if err != nil {
  67. return nil, fmt.Errorf("could not parse token: %v", err)
  68. }
  69. if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
  70. iby, err := strconv.ParseUint(fmt.Sprintf("%v", claims["iby"]), 10, 64)
  71. if err != nil {
  72. return nil, fmt.Errorf("invalid iby claim: %v", err)
  73. }
  74. projID, err := strconv.ParseUint(fmt.Sprintf("%v", claims["project_id"]), 10, 64)
  75. if err != nil {
  76. return nil, fmt.Errorf("invalid project_id claim: %v", err)
  77. }
  78. iatUnix, err := strconv.ParseInt(fmt.Sprintf("%v", claims["iat"]), 10, 64)
  79. if err != nil {
  80. return nil, fmt.Errorf("invalid iat claim: %v", err)
  81. }
  82. iat := time.Unix(iatUnix, 0)
  83. return &Token{
  84. SubKind: Subject(fmt.Sprintf("%v", claims["sub_kind"])),
  85. Sub: fmt.Sprintf("%v", claims["sub"]),
  86. IBy: uint(iby),
  87. IAt: &iat,
  88. ProjectID: uint(projID),
  89. }, nil
  90. }
  91. return nil, fmt.Errorf("invalid token")
  92. }