token.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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, projID uint) (*Token, error) {
  24. if userID == 0 || projID == 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. ProjectID: projID,
  32. IBy: userID,
  33. IAt: &iat,
  34. }, nil
  35. }
  36. func GetTokenForAPI(userID, projID uint) (*Token, error) {
  37. if userID == 0 || projID == 0 {
  38. return nil, fmt.Errorf("id cannot be 0")
  39. }
  40. iat := time.Now()
  41. return &Token{
  42. SubKind: API,
  43. Sub: string(API),
  44. ProjectID: projID,
  45. IBy: userID,
  46. IAt: &iat,
  47. }, nil
  48. }
  49. func (t *Token) EncodeToken(conf *TokenGeneratorConf) (string, error) {
  50. token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
  51. "sub_kind": t.SubKind,
  52. "sub": t.Sub,
  53. "iby": t.IBy,
  54. "iat": fmt.Sprintf("%d", t.IAt.Unix()),
  55. "project_id": t.ProjectID,
  56. })
  57. // Sign and get the complete encoded token as a string using the secret
  58. return token.SignedString([]byte(conf.TokenSecret))
  59. }
  60. func GetTokenFromEncoded(tokenString string, conf *TokenGeneratorConf) (*Token, error) {
  61. token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  62. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  63. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  64. }
  65. return []byte(conf.TokenSecret), nil
  66. })
  67. if err != nil {
  68. return nil, fmt.Errorf("could not parse token: %v", err)
  69. }
  70. if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
  71. iby, err := strconv.ParseUint(fmt.Sprintf("%v", claims["iby"]), 10, 64)
  72. if err != nil {
  73. return nil, fmt.Errorf("invalid iby claim: %v", err)
  74. }
  75. projID, err := strconv.ParseUint(fmt.Sprintf("%v", claims["project_id"]), 10, 64)
  76. if err != nil {
  77. return nil, fmt.Errorf("invalid project_id claim: %v", err)
  78. }
  79. iatUnix, err := strconv.ParseInt(fmt.Sprintf("%v", claims["iat"]), 10, 64)
  80. if err != nil {
  81. return nil, fmt.Errorf("invalid iat claim: %v", err)
  82. }
  83. iat := time.Unix(iatUnix, 0)
  84. return &Token{
  85. SubKind: Subject(fmt.Sprintf("%v", claims["sub_kind"])),
  86. Sub: fmt.Sprintf("%v", claims["sub"]),
  87. IBy: uint(iby),
  88. IAt: &iat,
  89. ProjectID: uint(projID),
  90. }, nil
  91. }
  92. return nil, fmt.Errorf("invalid token")
  93. }