123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- package auth
- import (
- "crypto/rand"
- "encoding/base64"
- "errors"
- "eta/eta_mini_ht_api/common/component/cache"
- logger "eta/eta_mini_ht_api/common/component/log"
- "eta/eta_mini_ht_api/common/component/wechat"
- "eta/eta_mini_ht_api/common/exception"
- authUtils "eta/eta_mini_ht_api/common/utils/auth"
- "eta/eta_mini_ht_api/common/utils/jwt"
- "eta/eta_mini_ht_api/common/utils/redis"
- "eta/eta_mini_ht_api/common/utils/sms"
- stringUtils "eta/eta_mini_ht_api/common/utils/string"
- smsService "eta/eta_mini_ht_api/domian/sms"
- userService "eta/eta_mini_ht_api/domian/user"
- "fmt"
- "gorm.io/gorm"
- "strings"
- )
- var (
- smsSender sms.SMSClient
- wechatClient *wechat.Client
- redisCache *cache.RedisCache
- )
- func message() sms.SMSClient {
- if smsSender == nil {
- smsSender = sms.GetInstance()
- }
- return smsSender
- }
- func wx() *wechat.Client {
- if wechatClient == nil {
- wechatClient = wechat.GetInstance()
- }
- return wechatClient
- }
- func SendSMSCode(mobile string) (err error) {
- code := rd().GetString(redis.GenerateSmsKey(mobile))
- if stringUtils.IsEmptyOrNil(code) {
- code, err = authUtils.GenerateCode(6)
- if err != nil {
- logger.Warn("生成验证码失败:%v", err)
- return exception.New(exception.SMSCodeGenerateFailed)
- }
- codeDTO := smsService.CodeDTO{
- Mobile: mobile,
- Code: code,
- ExpireMinute: message().GetExpireMinute(),
- }
- //消息domain层
- var smid int
- smid, err = smsService.SendSMSCode(codeDTO)
- if err != nil {
- logger.Error("发送短信失败:%v", err)
- err = exception.New(exception.SendingSMSFailed)
- }
- logger.Debug("验证码:%v", code)
- _, err = message().SendSms(mobile, code, smid)
- if err != nil {
- logger.Error("发送短信失败:%v", err)
- err = exception.New(exception.SendingSMSFailed)
- }
- return
- }
- return exception.New(exception.SMSCodeAlreadySent)
- }
- func CheckUser(mobile string, code string) (err error) {
- smsCode := rd().GetString(redis.GenerateSmsKey(mobile))
- if stringUtils.IsEmptyOrNil(smsCode) {
- logger.Warn("验证码已过期:%v", code)
- codeDTO := smsService.CodeDTO{
- Mobile: mobile,
- Code: code,
- }
- _ = smsService.TryExpireCode(codeDTO)
- err = exception.New(exception.SMSCodeExpired)
- return
- }
- if smsCode != code {
- err = exception.New(exception.SMSCodeError)
- return
- }
- return nil
- }
- type LoginDTO struct {
- VerifyCode string
- Code string
- Mobile string
- }
- func Login(login LoginDTO) (token string, err error) {
- var user userService.UserDTO
- user, err = userService.GetUserByMobile(login.Mobile)
- if err != nil {
- if !errors.Is(err, gorm.ErrRecordNotFound) {
- err = exception.New(exception.UnknownError)
- return
- }
- //注册用户
- var wechatInfo wechat.WxUser
- //微信请求异常
- wechatInfo, err = wx().Login(login.Code)
- //微信客户端的异常不做处理,已经是EtaError
- if err != nil {
- return
- }
- user = initUser(wechatInfo, login)
- err = userService.RegisterTemplateUser(&user)
- if err != nil {
- err = exception.New(exception.TemplateUserCreateFailed)
- return
- }
- }
- token, err = jwt.CreateToken(user.OpenId, user.Mobile)
- if err != nil {
- err = exception.New(exception.GenerateTokenFailed)
- return
- }
- err = rd().SetString(redis.GenerateTokenKey(user.Mobile), token, 90*24*60*60)
- if err != nil {
- err = exception.New(exception.GenerateTokenFailed)
- return
- }
- codeDTO := smsService.CodeDTO{
- Mobile: login.Mobile,
- Code: login.VerifyCode,
- }
- //登录成功删除短信验证码,数据库留痕
- err = rd().Delete(redis.GenerateSmsKey(login.Mobile))
- if err != nil {
- logger.Error("清除redis 短信验证码失败,%v", err)
- _ = rd().SetString(redis.GenerateSmsKey(login.Mobile), "", 1)
- return "", err
- }
- _ = smsService.TryVerifiedCode(codeDTO)
- return
- }
- func BindMobile(userId int, mobile, verifyCode string) (err error) {
- err = userService.BindUserMobile(userId, mobile)
- if err != nil {
- err = exception.New(exception.BindMobileFailed)
- return
- }
- codeDTO := smsService.CodeDTO{
- Mobile: mobile,
- Code: verifyCode,
- }
- //登录成功删除短信验证码,数据库留痕
- err = rd().Delete(redis.GenerateSmsKey(mobile))
- if err != nil {
- logger.Error("清除redis 短信验证码失败,%v", err)
- _ = rd().SetString(redis.GenerateSmsKey(mobile), "", 1)
- return err
- }
- _ = smsService.TryVerifiedCode(codeDTO)
- return
- }
- func RefreshToken(code string) (token string, isBindMobile int, err error) {
- //注册用户
- var wechatInfo wechat.WxUser
- //微信请求异常
- wechatInfo, err = wx().Login(code)
- //微信客户端的异常不做处理,已经是EtaError
- if err != nil {
- fmt.Println("wx.Login,err:" + err.Error())
- return
- }
- user, err := userService.GetTemplateUserByOpenId(wechatInfo.OpenId)
- var isAdd bool
- if err != nil {
- if err == gorm.ErrRecordNotFound {
- isAdd = true
- } else {
- err = exception.New(exception.TemplateUserNotFound)
- return
- }
- }
- token, err = jwt.CreateToken(wechatInfo.OpenId, wechatInfo.OpenId)
- if err != nil {
- err = exception.New(exception.GenerateTokenFailed)
- return
- }
- err = rd().SetString(redis.GenerateTokenKey(wechatInfo.OpenId), token, 90*24*60*60)
- if err != nil {
- err = exception.New(exception.GenerateTokenFailed)
- return
- }
- if user.Mobile == "" {
- isBindMobile = 0
- } else {
- isBindMobile = 1
- }
- if isAdd {
- user.OpenId = wechatInfo.OpenId
- user.UnionId = wechatInfo.UnionId
- err = userService.RegisterTemplateUser(&user)
- }
- return
- }
- func GetAreaCodes() (list []userService.AreaCodeDTO, err error) {
- list, err = userService.GetAreaCodes()
- if err != nil {
- err = exception.New(exception.GetAreaCodesFailed)
- }
- return
- }
- func GetValidAreaCodes() (list []string) {
- str := rd().GetString(redis.ValidAreaCode)
- if str == "" {
- codes, err := userService.GetValidAreaCodes()
- if err != nil {
- return []string{}
- }
- var validCodes []string
- for _, code := range codes {
- validCodes = append(validCodes, code.CodeValue)
- }
- err = rd().SetString(redis.ValidAreaCode, strings.Join(validCodes, ","), 60*60)
- if err != nil {
- logger.Error("设置Redis区号失败:%v", err)
- list = validCodes
- }
- list = strings.Split(rd().GetString(redis.ValidAreaCode), ",")
- } else {
- list = strings.Split(str, ",")
- }
- return
- }
- func initUser(user wechat.WxUser, dto LoginDTO) userService.UserDTO {
- username := generateRandomUsername(user.OpenId)
- if stringUtils.IsBlank(username) {
- username = dto.Mobile
- }
- return userService.UserDTO{
- OpenId: user.OpenId,
- UnionId: user.UnionId,
- Username: username,
- Mobile: dto.Mobile,
- }
- }
- // GenerateRandomUsername 生成基于UnionId的随机用户名
- func generateRandomUsername(openId string) string {
- // 生成一个随机的4字节二进制数据
- randomBytes := make([]byte, 4)
- _, err := rand.Read(randomBytes)
- if err != nil {
- return ""
- }
- // 将随机字节转换为base64编码的URL安全字符串
- // 并去掉可能出现的等于号
- randomStr := strings.TrimRight(base64.URLEncoding.EncodeToString(randomBytes), "=")
- // 拼接UnionId和随机字符串
- username := fmt.Sprintf("%s_%s", openId, randomStr)
- return username
- }
- func rd() *cache.RedisCache {
- if redisCache == nil {
- redisCache = cache.GetInstance()
- }
- return redisCache
- }
|