user.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package dbdata
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "time"
  7. "github.com/bjdgyc/anylink/pkg/utils"
  8. "github.com/xlzd/gotp"
  9. )
  10. // type User struct {
  11. // Id int `json:"id" xorm:"pk autoincr not null"`
  12. // Username string `json:"username" storm:"not null unique"`
  13. // Nickname string `json:"nickname"`
  14. // Email string `json:"email"`
  15. // // Password string `json:"password"`
  16. // PinCode string `json:"pin_code"`
  17. // OtpSecret string `json:"otp_secret"`
  18. // DisableOtp bool `json:"disable_otp"` // 禁用otp
  19. // Groups []string `json:"groups"`
  20. // Status int8 `json:"status"` // 1正常
  21. // SendEmail bool `json:"send_email"`
  22. // CreatedAt time.Time `json:"created_at"`
  23. // UpdatedAt time.Time `json:"updated_at"`
  24. // }
  25. func SetUser(v *User) error {
  26. var err error
  27. if v.Username == "" || len(v.Groups) == 0 {
  28. return errors.New("用户名或组错误")
  29. }
  30. planPass := v.PinCode
  31. // 自动生成密码
  32. if len(planPass) < 6 {
  33. planPass = utils.RandomRunes(8)
  34. }
  35. v.PinCode = planPass
  36. if v.OtpSecret == "" {
  37. v.OtpSecret = gotp.RandomSecret(32)
  38. }
  39. // 判断组是否有效
  40. ng := []string{}
  41. groups := GetGroupNames()
  42. for _, g := range v.Groups {
  43. if utils.InArrStr(groups, g) {
  44. ng = append(ng, g)
  45. }
  46. }
  47. if len(ng) == 0 {
  48. return errors.New("用户名或组错误")
  49. }
  50. v.Groups = ng
  51. v.UpdatedAt = time.Now()
  52. if v.Id > 0 {
  53. err = Set(v)
  54. } else {
  55. err = Add(v)
  56. }
  57. return err
  58. }
  59. // 验证用户登录信息
  60. func CheckUser(name, pwd, group string) error {
  61. // 获取登入的group数据
  62. groupData := &Group{}
  63. err := One("Name", group, groupData)
  64. if err != nil || groupData.Status != 1 {
  65. return fmt.Errorf("%s - %s", name, "用户组错误")
  66. }
  67. // 初始化Auth
  68. if len(groupData.Auth) == 0 {
  69. groupData.Auth["type"] = "local"
  70. }
  71. authType := groupData.Auth["type"].(string)
  72. // 本地认证方式
  73. if authType == "local" {
  74. return checkLocalUser(name, pwd, group)
  75. }
  76. // 其它认证方式, 支持自定义
  77. _, ok := authRegistry[authType]
  78. if !ok {
  79. return fmt.Errorf("%s %s", "未知的认证方式: ", authType)
  80. }
  81. auth := makeInstance(authType).(IUserAuth)
  82. return auth.checkUser(name, pwd, groupData)
  83. }
  84. // 验证本地用户登录信息
  85. func checkLocalUser(name, pwd, group string) error {
  86. // TODO 严重问题
  87. // return nil
  88. pl := len(pwd)
  89. if name == "" || pl < 6 {
  90. return fmt.Errorf("%s %s", name, "密码错误")
  91. }
  92. v := &User{}
  93. err := One("Username", name, v)
  94. if err != nil || v.Status != 1 {
  95. switch v.Status {
  96. case 0:
  97. return fmt.Errorf("%s %s", name, "用户不存在或用户已停用")
  98. case 2:
  99. return fmt.Errorf("%s %s", name, "用户已过期")
  100. }
  101. }
  102. // 判断用户组信息
  103. if !utils.InArrStr(v.Groups, group) {
  104. return fmt.Errorf("%s %s", name, "用户组错误")
  105. }
  106. // 判断otp信息
  107. pinCode := pwd
  108. if !v.DisableOtp {
  109. pinCode = pwd[:pl-6]
  110. otp := pwd[pl-6:]
  111. if !checkOtp(name, otp, v.OtpSecret) {
  112. return fmt.Errorf("%s %s", name, "动态码错误")
  113. }
  114. }
  115. // 判断用户密码
  116. if pinCode != v.PinCode {
  117. return fmt.Errorf("%s %s", name, "密码错误")
  118. }
  119. return nil
  120. }
  121. // 用户过期时间到达后,更新用户状态,并返回一个状态为过期的用户切片
  122. func CheckUserlimittime() (limitUser []interface{}) {
  123. if _, err := xdb.Where("limittime <= ?", time.Now()).And("status = ?", 1).Update(&User{Status: 2}); err != nil {
  124. return
  125. }
  126. user := make(map[int64]User)
  127. if err := xdb.Where("status != ?", 1).Find(user); err != nil {
  128. return
  129. }
  130. for _, v := range user {
  131. limitUser = append(limitUser, v.Username)
  132. }
  133. return
  134. }
  135. var (
  136. userOtpMux = sync.Mutex{}
  137. userOtp = map[string]time.Time{}
  138. )
  139. func init() {
  140. go func() {
  141. expire := time.Second * 60
  142. for range time.Tick(time.Second * 10) {
  143. tnow := time.Now()
  144. userOtpMux.Lock()
  145. for k, v := range userOtp {
  146. if tnow.After(v.Add(expire)) {
  147. delete(userOtp, k)
  148. }
  149. }
  150. userOtpMux.Unlock()
  151. }
  152. }()
  153. }
  154. // 判断令牌信息
  155. func checkOtp(name, otp, secret string) bool {
  156. key := fmt.Sprintf("%s:%s", name, otp)
  157. userOtpMux.Lock()
  158. defer userOtpMux.Unlock()
  159. // 令牌只能使用一次
  160. if _, ok := userOtp[key]; ok {
  161. // 已经存在
  162. return false
  163. }
  164. userOtp[key] = time.Now()
  165. totp := gotp.NewDefaultTOTP(secret)
  166. unix := time.Now().Unix()
  167. verify := totp.Verify(otp, int(unix))
  168. return verify
  169. }