auth_service.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. package auth
  2. import (
  3. "crypto/rand"
  4. "encoding/base64"
  5. "errors"
  6. "eta/eta_mini_ht_api/common/component/cache"
  7. logger "eta/eta_mini_ht_api/common/component/log"
  8. "eta/eta_mini_ht_api/common/component/wechat"
  9. "eta/eta_mini_ht_api/common/exception"
  10. authUtils "eta/eta_mini_ht_api/common/utils/auth"
  11. "eta/eta_mini_ht_api/common/utils/jwt"
  12. "eta/eta_mini_ht_api/common/utils/redis"
  13. "eta/eta_mini_ht_api/common/utils/sms"
  14. stringUtils "eta/eta_mini_ht_api/common/utils/string"
  15. smsService "eta/eta_mini_ht_api/domian/sms"
  16. userService "eta/eta_mini_ht_api/domian/user"
  17. "fmt"
  18. "gorm.io/gorm"
  19. "strings"
  20. )
  21. var (
  22. smsSender sms.SMSClient
  23. wechatClient *wechat.Client
  24. redisCache *cache.RedisCache
  25. )
  26. func message() sms.SMSClient {
  27. if smsSender == nil {
  28. smsSender = sms.GetInstance()
  29. }
  30. return smsSender
  31. }
  32. func wx() *wechat.Client {
  33. if wechatClient == nil {
  34. wechatClient = wechat.GetInstance()
  35. }
  36. return wechatClient
  37. }
  38. func SendSMSCode(mobile string) (err error) {
  39. code := rd().GetString(redis.GenerateSmsKey(mobile))
  40. if stringUtils.IsEmptyOrNil(code) {
  41. code, err = authUtils.GenerateCode(6)
  42. if err != nil {
  43. logger.Warn("生成验证码失败:%v", err)
  44. return exception.New(exception.SMSCodeGenerateFailed)
  45. }
  46. codeDTO := smsService.CodeDTO{
  47. Mobile: mobile,
  48. Code: code,
  49. ExpireMinute: message().GetExpireMinute(),
  50. }
  51. //消息domain层
  52. var smid int
  53. smid, err = smsService.SendSMSCode(codeDTO)
  54. if err != nil {
  55. logger.Error("发送短信失败:%v", err)
  56. err = exception.New(exception.SendingSMSFailed)
  57. }
  58. logger.Debug("验证码:%v", code)
  59. _, err = message().SendSms(mobile, code, smid)
  60. if err != nil {
  61. logger.Error("发送短信失败:%v", err)
  62. err = exception.New(exception.SendingSMSFailed)
  63. }
  64. return
  65. }
  66. return exception.New(exception.SMSCodeAlreadySent)
  67. }
  68. func CheckUser(mobile string, code string) (err error) {
  69. smsCode := rd().GetString(redis.GenerateSmsKey(mobile))
  70. if stringUtils.IsEmptyOrNil(smsCode) {
  71. logger.Warn("验证码已过期:%v", code)
  72. codeDTO := smsService.CodeDTO{
  73. Mobile: mobile,
  74. Code: code,
  75. }
  76. _ = smsService.TryExpireCode(codeDTO)
  77. err = exception.New(exception.SMSCodeExpired)
  78. return
  79. }
  80. if smsCode != code {
  81. err = exception.New(exception.SMSCodeError)
  82. return
  83. }
  84. return nil
  85. }
  86. type LoginDTO struct {
  87. VerifyCode string
  88. Code string
  89. Mobile string
  90. }
  91. func Login(login LoginDTO) (token string, err error) {
  92. var user userService.UserDTO
  93. user, err = userService.GetUserByMobile(login.Mobile)
  94. if err != nil {
  95. if !errors.Is(err, gorm.ErrRecordNotFound) {
  96. err = exception.New(exception.UnknownError)
  97. return
  98. }
  99. //注册用户
  100. var wechatInfo wechat.WxUser
  101. //微信请求异常
  102. wechatInfo, err = wx().Login(login.Code)
  103. //微信客户端的异常不做处理,已经是EtaError
  104. if err != nil {
  105. return
  106. }
  107. user = initUser(wechatInfo, login)
  108. err = userService.RegisterTemplateUser(&user)
  109. if err != nil {
  110. err = exception.New(exception.TemplateUserCreateFailed)
  111. return
  112. }
  113. }
  114. token, err = jwt.CreateToken(user.OpenId, user.Mobile)
  115. if err != nil {
  116. err = exception.New(exception.GenerateTokenFailed)
  117. return
  118. }
  119. err = rd().SetString(redis.GenerateTokenKey(user.Mobile), token, 90*24*60*60)
  120. if err != nil {
  121. err = exception.New(exception.GenerateTokenFailed)
  122. return
  123. }
  124. codeDTO := smsService.CodeDTO{
  125. Mobile: login.Mobile,
  126. Code: login.VerifyCode,
  127. }
  128. //登录成功删除短信验证码,数据库留痕
  129. err = rd().Delete(redis.GenerateSmsKey(login.Mobile))
  130. if err != nil {
  131. logger.Error("清除redis 短信验证码失败,%v", err)
  132. _ = rd().SetString(redis.GenerateSmsKey(login.Mobile), "", 1)
  133. return "", err
  134. }
  135. _ = smsService.TryVerifiedCode(codeDTO)
  136. return
  137. }
  138. func BindMobile(userId int, mobile, verifyCode string) (err error) {
  139. err = userService.BindUserMobile(userId, mobile)
  140. if err != nil {
  141. err = exception.New(exception.BindMobileFailed)
  142. return
  143. }
  144. codeDTO := smsService.CodeDTO{
  145. Mobile: mobile,
  146. Code: verifyCode,
  147. }
  148. //登录成功删除短信验证码,数据库留痕
  149. err = rd().Delete(redis.GenerateSmsKey(mobile))
  150. if err != nil {
  151. logger.Error("清除redis 短信验证码失败,%v", err)
  152. _ = rd().SetString(redis.GenerateSmsKey(mobile), "", 1)
  153. return err
  154. }
  155. _ = smsService.TryVerifiedCode(codeDTO)
  156. return
  157. }
  158. func RefreshToken(code string) (token string, isBindMobile int, err error) {
  159. //注册用户
  160. var wechatInfo wechat.WxUser
  161. //微信请求异常
  162. wechatInfo, err = wx().Login(code)
  163. //微信客户端的异常不做处理,已经是EtaError
  164. if err != nil {
  165. fmt.Println("wx.Login,err:" + err.Error())
  166. return
  167. }
  168. user, err := userService.GetTemplateUserByOpenId(wechatInfo.OpenId)
  169. var isAdd bool
  170. if err != nil {
  171. if err == gorm.ErrRecordNotFound {
  172. isAdd = true
  173. } else {
  174. err = exception.New(exception.TemplateUserNotFound)
  175. return
  176. }
  177. }
  178. token, err = jwt.CreateToken(wechatInfo.OpenId, wechatInfo.OpenId)
  179. if err != nil {
  180. err = exception.New(exception.GenerateTokenFailed)
  181. return
  182. }
  183. err = rd().SetString(redis.GenerateTokenKey(wechatInfo.OpenId), token, 90*24*60*60)
  184. if err != nil {
  185. err = exception.New(exception.GenerateTokenFailed)
  186. return
  187. }
  188. if user.Mobile == "" {
  189. isBindMobile = 0
  190. } else {
  191. isBindMobile = 1
  192. }
  193. if isAdd {
  194. user.OpenId = wechatInfo.OpenId
  195. user.UnionId = wechatInfo.UnionId
  196. err = userService.RegisterTemplateUser(&user)
  197. }
  198. return
  199. }
  200. func GetAreaCodes() (list []userService.AreaCodeDTO, err error) {
  201. list, err = userService.GetAreaCodes()
  202. if err != nil {
  203. err = exception.New(exception.GetAreaCodesFailed)
  204. }
  205. return
  206. }
  207. func GetValidAreaCodes() (list []string) {
  208. str := rd().GetString(redis.ValidAreaCode)
  209. if str == "" {
  210. codes, err := userService.GetValidAreaCodes()
  211. if err != nil {
  212. return []string{}
  213. }
  214. var validCodes []string
  215. for _, code := range codes {
  216. validCodes = append(validCodes, code.CodeValue)
  217. }
  218. err = rd().SetString(redis.ValidAreaCode, strings.Join(validCodes, ","), 60*60)
  219. if err != nil {
  220. logger.Error("设置Redis区号失败:%v", err)
  221. list = validCodes
  222. }
  223. list = strings.Split(rd().GetString(redis.ValidAreaCode), ",")
  224. } else {
  225. list = strings.Split(str, ",")
  226. }
  227. return
  228. }
  229. func initUser(user wechat.WxUser, dto LoginDTO) userService.UserDTO {
  230. username := generateRandomUsername(user.OpenId)
  231. if stringUtils.IsBlank(username) {
  232. username = dto.Mobile
  233. }
  234. return userService.UserDTO{
  235. OpenId: user.OpenId,
  236. UnionId: user.UnionId,
  237. Username: username,
  238. Mobile: dto.Mobile,
  239. }
  240. }
  241. // GenerateRandomUsername 生成基于UnionId的随机用户名
  242. func generateRandomUsername(openId string) string {
  243. // 生成一个随机的4字节二进制数据
  244. randomBytes := make([]byte, 4)
  245. _, err := rand.Read(randomBytes)
  246. if err != nil {
  247. return ""
  248. }
  249. // 将随机字节转换为base64编码的URL安全字符串
  250. // 并去掉可能出现的等于号
  251. randomStr := strings.TrimRight(base64.URLEncoding.EncodeToString(randomBytes), "=")
  252. // 拼接UnionId和随机字符串
  253. username := fmt.Sprintf("%s_%s", openId, randomStr)
  254. return username
  255. }
  256. func rd() *cache.RedisCache {
  257. if redisCache == nil {
  258. redisCache = cache.GetInstance()
  259. }
  260. return redisCache
  261. }