store.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package auth
  2. import (
  3. "encoding/json"
  4. "time"
  5. "github.com/google/uuid"
  6. "github.com/tidwall/buntdb"
  7. )
  8. type TokenStore interface {
  9. Create(info TokenInfo) error
  10. RemoveByAccess(access string) error
  11. RemoveByRefresh(refresh string) error
  12. GetByAccess(access string) (TokenInfo, error)
  13. GetByRefresh(refresh string) (TokenInfo, error)
  14. }
  15. // NewMemoryTokenStore create a token Store instance based on memory
  16. func NewMemoryTokenStore() (TokenStore, error) {
  17. return NewFileTokenStore(":memory:")
  18. }
  19. // NewFileTokenStore create a token Store instance based on file
  20. func NewFileTokenStore(filename string) (TokenStore, error) {
  21. db, err := buntdb.Open(filename)
  22. if err != nil {
  23. return nil, err
  24. }
  25. return &Store{db: db}, nil
  26. }
  27. // Store token storage based on buntdb(https://github.com/tidwall/buntdb)
  28. type Store struct {
  29. db *buntdb.DB
  30. }
  31. func (ts *Store) remove(key string) error {
  32. err := ts.db.Update(func(tx *buntdb.Tx) error {
  33. _, err := tx.Delete(key)
  34. return err
  35. })
  36. if err == buntdb.ErrNotFound {
  37. return nil
  38. }
  39. return err
  40. }
  41. func (ts *Store) getData(key string) (TokenInfo, error) {
  42. var ti TokenInfo
  43. err := ts.db.View(func(tx *buntdb.Tx) error {
  44. jv, err := tx.Get(key)
  45. if err != nil {
  46. return err
  47. }
  48. var tm Token
  49. err = json.Unmarshal([]byte(jv), &tm)
  50. if err != nil {
  51. return err
  52. }
  53. ti = &tm
  54. return nil
  55. })
  56. if err != nil {
  57. if err == buntdb.ErrNotFound {
  58. return nil, nil
  59. }
  60. return nil, err
  61. }
  62. return ti, nil
  63. }
  64. func (ts *Store) getBasicID(key string) (string, error) {
  65. var basicID string
  66. err := ts.db.View(func(tx *buntdb.Tx) error {
  67. v, err := tx.Get(key)
  68. if err != nil {
  69. return err
  70. }
  71. basicID = v
  72. return nil
  73. })
  74. if err != nil {
  75. if err == buntdb.ErrNotFound {
  76. return "", nil
  77. }
  78. return "", err
  79. }
  80. return basicID, nil
  81. }
  82. // Create and Store the new token information
  83. func (ts *Store) Create(info TokenInfo) error {
  84. ct := time.Now()
  85. jv, err := json.Marshal(info)
  86. if err != nil {
  87. return err
  88. }
  89. return ts.db.Update(func(tx *buntdb.Tx) error {
  90. basicID := uuid.Must(uuid.NewRandom()).String()
  91. aexp := info.GetAccessExpiresIn()
  92. rexp := aexp
  93. expires := true
  94. if refresh := info.GetRefresh(); refresh != "" {
  95. rexp = info.GetRefreshCreateAt().Add(info.GetRefreshExpiresIn()).Sub(ct)
  96. if aexp.Seconds() > rexp.Seconds() {
  97. aexp = rexp
  98. }
  99. expires = info.GetRefreshExpiresIn() != 0
  100. _, _, err = tx.Set(refresh, basicID, &buntdb.SetOptions{Expires: expires, TTL: rexp})
  101. if err != nil {
  102. return err
  103. }
  104. }
  105. _, _, err = tx.Set(basicID, string(jv), &buntdb.SetOptions{Expires: expires, TTL: rexp})
  106. if err != nil {
  107. return err
  108. }
  109. _, _, err = tx.Set(info.GetAccess(), basicID, &buntdb.SetOptions{Expires: expires, TTL: aexp})
  110. return err
  111. })
  112. }
  113. // RemoveByAccess use the access token to delete the token information
  114. func (ts *Store) RemoveByAccess(access string) error {
  115. return ts.remove(access)
  116. }
  117. // RemoveByRefresh use the refresh token to delete the token information
  118. func (ts *Store) RemoveByRefresh(refresh string) error {
  119. return ts.remove(refresh)
  120. }
  121. // GetByAccess use the access token for token information data
  122. func (ts *Store) GetByAccess(access string) (TokenInfo, error) {
  123. basicID, err := ts.getBasicID(access)
  124. if err != nil {
  125. return nil, err
  126. }
  127. return ts.getData(basicID)
  128. }
  129. // GetByRefresh use the refresh token for token information data
  130. func (ts *Store) GetByRefresh(refresh string) (TokenInfo, error) {
  131. basicID, err := ts.getBasicID(refresh)
  132. if err != nil {
  133. return nil, err
  134. }
  135. return ts.getData(basicID)
  136. }