auth.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package model
  17. import (
  18. "crypto/rand"
  19. "net/http"
  20. "github.com/golang-jwt/jwt/v5"
  21. "github.com/siyuan-note/logging"
  22. )
  23. type Account struct {
  24. Username string
  25. Password string
  26. Token string
  27. }
  28. type AccountsMap map[string]*Account
  29. type ClaimsKeyType string
  30. const (
  31. XAuthTokenKey = "X-Auth-Token"
  32. ClaimsContextKey = "claims"
  33. iss = "siyuan-publish-reverse-proxy-server"
  34. sub = "publish"
  35. aud = "siyuan-kernel"
  36. ClaimsKeyRole string = "role"
  37. )
  38. var (
  39. accountsMap = AccountsMap{}
  40. key = make([]byte, 32)
  41. )
  42. func GetBasicAuthAccount(username string) *Account {
  43. return accountsMap[username]
  44. }
  45. func InitAccounts() {
  46. accountsMap = AccountsMap{
  47. "": &Account{}, // 匿名用户
  48. }
  49. for _, account := range Conf.Publish.Auth.Accounts {
  50. accountsMap[account.Username] = &Account{
  51. Username: account.Username,
  52. Password: account.Password,
  53. }
  54. }
  55. InitJWT()
  56. }
  57. func InitJWT() {
  58. if _, err := rand.Read(key); err != nil {
  59. logging.LogErrorf("generate JWT signing key failed: %s", err)
  60. return
  61. }
  62. for username, account := range accountsMap {
  63. // REF: https://golang-jwt.github.io/jwt/usage/create/
  64. t := jwt.NewWithClaims(
  65. jwt.SigningMethodHS256,
  66. jwt.MapClaims{
  67. "iss": iss,
  68. "sub": sub,
  69. "aud": aud,
  70. "jti": username,
  71. ClaimsKeyRole: RoleReader,
  72. },
  73. )
  74. if token, err := t.SignedString(key); err != nil {
  75. logging.LogErrorf("JWT signature failed: %s", err)
  76. return
  77. } else {
  78. account.Token = token
  79. }
  80. }
  81. }
  82. func ParseJWT(tokenString string) (*jwt.Token, error) {
  83. // REF: https://golang-jwt.github.io/jwt/usage/parse/
  84. return jwt.Parse(
  85. tokenString,
  86. func(token *jwt.Token) (interface{}, error) {
  87. return key, nil
  88. },
  89. jwt.WithIssuer(iss),
  90. jwt.WithSubject(sub),
  91. jwt.WithAudience(aud),
  92. )
  93. }
  94. func ParseXAuthToken(r *http.Request) *jwt.Token {
  95. tokenString := r.Header.Get(XAuthTokenKey)
  96. if tokenString != "" {
  97. if token, err := ParseJWT(tokenString); err != nil {
  98. logging.LogErrorf("JWT parse failed: %s", err)
  99. } else {
  100. return token
  101. }
  102. }
  103. return nil
  104. }
  105. func GetTokenClaims(token *jwt.Token) jwt.MapClaims {
  106. return token.Claims.(jwt.MapClaims)
  107. }
  108. func GetClaimRole(claims jwt.MapClaims) Role {
  109. if role := claims[ClaimsKeyRole]; role != nil {
  110. return Role(role.(float64))
  111. }
  112. return RoleVisitor
  113. }