oauth.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package model
  2. import (
  3. "errors"
  4. "strconv"
  5. "strings"
  6. )
  7. const OIDC_DEFAULT_SCOPES = "openid,profile,email"
  8. const (
  9. // make sure the value shouldbe lowercase
  10. OauthTypeGithub string = "github"
  11. OauthTypeGoogle string = "google"
  12. OauthTypeOidc string = "oidc"
  13. OauthTypeWebauth string = "webauth"
  14. PKCEMethodS256 string = "S256"
  15. PKCEMethodPlain string = "plain"
  16. )
  17. // Validate the oauth type
  18. func ValidateOauthType(oauthType string) error {
  19. switch oauthType {
  20. case OauthTypeGithub, OauthTypeGoogle, OauthTypeOidc, OauthTypeWebauth:
  21. return nil
  22. default:
  23. return errors.New("invalid Oauth type")
  24. }
  25. }
  26. const (
  27. UserEndpointGithub string = "https://api.github.com/user"
  28. IssuerGoogle string = "https://accounts.google.com"
  29. )
  30. type Oauth struct {
  31. IdModel
  32. Op string `json:"op"`
  33. OauthType string `json:"oauth_type"`
  34. ClientId string `json:"client_id"`
  35. ClientSecret string `json:"client_secret"`
  36. RedirectUrl string `json:"redirect_url"`
  37. AutoRegister *bool `json:"auto_register"`
  38. Scopes string `json:"scopes"`
  39. Issuer string `json:"issuer"`
  40. PkceEnable *bool `json:"pkce_enable"`
  41. PkceMethod string `json:"pkce_method"`
  42. TimeModel
  43. }
  44. // Helper function to format oauth info, it's used in the update and create method
  45. func (oa *Oauth) FormatOauthInfo() error {
  46. oauthType := strings.TrimSpace(oa.OauthType)
  47. err := ValidateOauthType(oa.OauthType)
  48. if err != nil {
  49. return err
  50. }
  51. switch oauthType {
  52. case OauthTypeGithub:
  53. oa.Op = OauthTypeGithub
  54. case OauthTypeGoogle:
  55. oa.Op = OauthTypeGoogle
  56. }
  57. // check if the op is empty, set the default value
  58. op := strings.TrimSpace(oa.Op)
  59. if op == "" && oauthType == OauthTypeOidc {
  60. oa.Op = OauthTypeOidc
  61. }
  62. // check the issuer, if the oauth type is google and the issuer is empty, set the issuer to the default value
  63. issuer := strings.TrimSpace(oa.Issuer)
  64. // If the oauth type is google and the issuer is empty, set the issuer to the default value
  65. if oauthType == OauthTypeGoogle && issuer == "" {
  66. oa.Issuer = IssuerGoogle
  67. }
  68. if oa.PkceEnable == nil {
  69. oa.PkceEnable = new(bool)
  70. *oa.PkceEnable = false
  71. }
  72. if oa.PkceMethod == "" {
  73. oa.PkceMethod = PKCEMethodS256
  74. }
  75. return nil
  76. }
  77. type OauthUser struct {
  78. OpenId string `json:"open_id" gorm:"not null;index"`
  79. Name string `json:"name"`
  80. Username string `json:"username"`
  81. Email string `json:"email"`
  82. VerifiedEmail bool `json:"verified_email,omitempty"`
  83. Picture string `json:"picture,omitempty"`
  84. }
  85. func (ou *OauthUser) ToUser(user *User, overideUsername bool) {
  86. if overideUsername {
  87. user.Username = ou.Username
  88. }
  89. user.Email = ou.Email
  90. user.Nickname = ou.Name
  91. user.Avatar = ou.Picture
  92. }
  93. type OauthUserBase struct {
  94. Name string `json:"name"`
  95. Email string `json:"email"`
  96. }
  97. type OidcUser struct {
  98. OauthUserBase
  99. Sub string `json:"sub"`
  100. VerifiedEmail bool `json:"email_verified"`
  101. PreferredUsername string `json:"preferred_username"`
  102. Picture string `json:"picture"`
  103. }
  104. func (ou *OidcUser) ToOauthUser() *OauthUser {
  105. var username string
  106. // 使用 PreferredUsername,如果不存在,降级到 Email 前缀
  107. if ou.PreferredUsername != "" {
  108. username = ou.PreferredUsername
  109. } else {
  110. username = strings.ToLower(ou.Email)
  111. }
  112. return &OauthUser{
  113. OpenId: ou.Sub,
  114. Name: ou.Name,
  115. Username: username,
  116. Email: ou.Email,
  117. VerifiedEmail: ou.VerifiedEmail,
  118. Picture: ou.Picture,
  119. }
  120. }
  121. type GithubUser struct {
  122. OauthUserBase
  123. Id int `json:"id"`
  124. Login string `json:"login"`
  125. AvatarUrl string `json:"avatar_url"`
  126. VerifiedEmail bool `json:"verified_email"`
  127. }
  128. func (gu *GithubUser) ToOauthUser() *OauthUser {
  129. username := strings.ToLower(gu.Login)
  130. return &OauthUser{
  131. OpenId: strconv.Itoa(gu.Id),
  132. Name: gu.Name,
  133. Username: username,
  134. Email: gu.Email,
  135. VerifiedEmail: gu.VerifiedEmail,
  136. Picture: gu.AvatarUrl,
  137. }
  138. }
  139. type OauthList struct {
  140. Oauths []*Oauth `json:"list"`
  141. Pagination
  142. }