package svc import ( "applet/app/db" "applet/app/db/model" "applet/app/e" "applet/app/lib/mob" "applet/app/lib/sms" "applet/app/lib/zhimeng" "applet/app/md" "applet/app/svc" "applet/app/utils" "applet/app/utils/cache" "applet/app/utils/logx" sms2 "code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git/sms" "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/syyongx/php2go" "github.com/tidwall/gjson" "math/rand" "time" "xorm.io/xorm" ) func Login(c *gin.Context) { r := new(md.LoginResponse) requestBody := new(md.FastLoginRequestBody) if err := c.ShouldBindJSON(&requestBody); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } user, _ := db.UserFindByMobileAll(svc.MasterDb(c), requestBody.Mobile) if user == nil { e.OutErr(c, 400, e.NewErr(400, "账号不存在")) return } if user.Password != utils.Md5(requestBody.Password) { e.OutErr(c, 400, e.NewErr(400, "密码不正确")) return } if err := svc.FastLoginUserExist(c, r, requestBody); err != nil { if e.ErrorIsAccountBan(err) { e.OutErr(c, e.ERR_USER_IS_BAN, err) return } e.OutErr(c, 400, err) return } e.OutSuc(c, r, nil) return } func LoginFastIn(c *gin.Context) { var req map[string]string if err := c.ShouldBindJSON(&req); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } if req["phone"] == "" { e.OutErr(c, 400, e.NewErr(400, "手机号不能为空")) return } if req["captcha"] == "" { e.OutErr(c, 400, e.NewErr(400, "验证码不能为空")) return } mob1, errr := mob.GetMobSDK(c.GetString("mid")) if errr != nil { e.OutErr(c, e.ERR_MOB_CONFIG, errr) return } if req["zone"] == "" { req["zone"] = "86" } send := map[string]interface{}{ "phone": req["phone"], "zone": req["zone"], "code": req["captcha"], } var ok bool var err error // h5(wap) 登录 smsPlatform := sms.GetSmsPlatform(c) key := fmt.Sprintf("%s_SMS_FastLogin_%s", db.SysCfgGet(c, "app_name"), req["phone"]) if smsPlatform == "ljioe" { b, err := cache.GetBytes(key) if err != nil { e.OutErr(c, e.ERR_MOB_SMS_NO_EXISTS, err) return } if req["captcha"] != gjson.GetBytes(b, "data.captcha").String() { e.OutErr(c, e.ERR_MOB_SMS_NO_SAME, err) return } ok = true } else { c.Set("not_deduction_doing", "1") ok, err = mob1.MobSMS(c, send) if err != nil { e.OutErr(c, 400, err.Error()) return } } r := new(md.LoginResponse) requestBody := &md.FastLoginRequestBody{ Mobile: req["phone"], } if ok { // 短信验证通过 user, isExist, err := db.UserGetByMobileIgnoreDelete(db.DBs[c.GetString("mid")], req["phone"], req["zone"]) if err != nil { e.OutErr(c, e.ERR, err) return } //用户已注册过,获取用户信息并返回 if isExist { if user.DeleteAt != 0 { e.OutErr(c, e.ERR_USER_IS_BAN) return } if err := svc.FastLoginUserExist(c, r, requestBody); err != nil { if e.ErrorIsAccountBan(err) { e.OutErr(c, e.ERR_USER_IS_BAN, err) return } e.OutErr(c, 400, err) return } e.OutSuc(c, r, nil) return } if err := FastLoginUserNoExist(c, r, requestBody); err != nil { // 创建失败时清空用户 if r.UserID != "" { UserDeleteOne(c, r.UserID) } e.OutErr(c, e.ERR, err) return } cache.Del(key) // 返回登陆响应 e.OutSuc(c, r, nil) return } // 验证码无效或者过期,验证码错误 e.OutErr(c, e.ERR_SMS_AUTH, err) return } func FastLoginUserNoExist(c *gin.Context, r *md.LoginResponse, requestBody *md.FastLoginRequestBody) error { user := new(model.User) user.Username = requestBody.Mobile user.Password = utils.Md5(requestBody.Mobile) if requestBody.Password != "" { user.Password = utils.Md5(requestBody.Password) } user.Platform = c.GetHeader("platform") user.Phone = requestBody.Mobile appNameCn := db.SysCfgGet(c, "app_name_cn") user.Nickname = appNameCn + requestBody.Mobile[len(requestBody.Mobile)-4:len(requestBody.Mobile)] user.Zone = "86" lvs, err := db.UserLevlAll(c, db.DBs[c.GetString("mid")]) if err != nil || len(lvs) == 0 { return errors.New("会员等级不存在") } user.Level = lvs[0].Id user.State = 1 user.CreateAt = time.Now() user.UpdateAt = time.Now() // ---- 插入用户-----! exist, err := userCheck(c, user, db.UserInsert) if err != nil { return err } if exist { return errors.New("Register user is exist") } r.UserID = utils.IntToStr(user.Uid) // 生成jwt appName := db.SysCfgGet(c, "app_name") token, err := utils.GenToken(user.Uid, user.Username, user.Phone, appName, "", "") if err != nil { return logx.Warn(err) } // Insert user profile userProfile := new(model.UserProfile) userProfile.ArkidToken = token userProfile.Uid = user.Uid if userProfile.AvatarUrl == "" { userProfile.AvatarUrl = db.SysCfgGet(c, "app_user_default_avatar") } userProfile.IsNew = 1 exist, err = userProfileCheck(c, userProfile, db.UserProfileInsert) if err != nil { return err } if exist { return errors.New("user Profile is exist") } //debug //生成邀请码 防止卡死 GetInviteCode(c, user, userProfile) // 异步处理 有效会员和新会员 // 写入缓存 key := fmt.Sprintf("%s:token:%s", c.GetString("mid"), user.Username) _, err = cache.SetEx(key, token, 39528000) // 半年 if err != nil { return logx.Warn(err) } r.Token = token r.UserID = utils.IntToStr(user.Uid) return nil } func GetInviteCode(c *gin.Context, user *model.User, userProfile *model.UserProfile) { if userProfile.InviteCode != "" { return } cc := c.Copy() // 传递上下文给 goroutine 的话 一定要使用副本,这样才能保证上下文的输出安全 //生成邀请码的线程 直接访问怕慢 go UserInviteCode(cc, &md.User{ Info: user, Profile: userProfile, }) return } func userCheck(c *gin.Context, user *model.User, f func(*xorm.Engine, *model.User) (int64, error)) (bool, error) { fmt.Println("user in userCheck is ", utils.SerializeStr(user)) isExist, err := db.UserIsExistByMobile(db.DBs[c.GetString("mid")], user.Username) if isExist { return isExist, nil } _, err = f(db.DBs[c.GetString("mid")], user) return false, err } func userProfileCheck(c *gin.Context, userProfile *model.UserProfile, f func(*xorm.Engine, *model.UserProfile) (int64, error)) (bool, error) { isExist, err := db.UserProfileIsExistByUserID(db.DBs[c.GetString("mid")], userProfile.Uid) if isExist { return isExist, nil } _, err = f(db.DBs[c.GetString("mid")], userProfile) return false, err } func UserDeleteOne(c *gin.Context, id interface{}) (int64, error) { _, err := db.UserDelete(db.DBs[c.GetString("mid")], id) if err != nil { return 0, err } // 删除用户 _, err = db.UserProfileDelete(db.DBs[c.GetString("mid")], id) if err != nil { return 0, err } // 删除用户关系 _, err = db.UserRelateDelete(db.DBs[c.GetString("mid")], id) if err != nil { return 0, err } // 将他的下级pid清零 us, err := db.UserProfileByPuid(db.DBs[c.GetString("mid")], id) if err != nil { return 0, err } for _, item := range *us { item.ParentUid = 0 _, err = db.UserProfileUpdate(db.DBs[c.GetString("mid")], item.Uid, &item, "parent_uid") if err != nil { continue } } return 1, nil } func LoginSendSms(c *gin.Context) { var req map[string]string if err := c.ShouldBindJSON(&req); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } if req["phone"] == "" { e.OutErr(c, 400, e.NewErr(400, "手机号不能为空")) return } isExist, err := db.UserisExistByMobile(db.DBs[c.GetString("mid")], req["phone"]) if err != nil { e.OutErr(c, e.ERR, err) return } userdata, _ := db.UserFindByPhoneOrNickname(db.DBs[c.GetString("mid")], req["phone"]) if userdata != nil && userdata.State == 2 { e.OutErr(c, 400, e.NewErr(400, "账号已冻结")) return } types := "" if !isExist { types = "register" } else if isExist { types = "login" } smsType := svc.SysCfgGet(c, "sms_type") c.Set("sms_type", smsType) if c.GetString("sms_type") == "1" { count := sms2.SmsNumGetSmsNum(db.Db, "putong", c.GetString("mid")) if count-1 < 0 { e.OutErr(c, e.ERR_MOB_SMS_NO_AVA, err) return } } else { count, _ := zhimeng.SmsNum(db.Db, c.GetString("mid"), c.GetString("sms_type"), db.SysCfgGet(c, "third_zm_sms_key"), db.SysCfgGet(c, "third_zm_sms_secret")) if count-1 < 0 { e.OutErr(c, e.ERR_MOB_SMS_NO_AVA, err) return } } appName := db.SysCfgGet(c, "sms_push_sign") captcha := createCaptcha() content := fmt.Sprintf("【%s】验证码:%s", appName, captcha) key := fmt.Sprintf("%s_SMS_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode := "" switch types { case "login": content = fmt.Sprintf("【%s】快捷登录验证码:%s", appName, captcha) key = fmt.Sprintf("%s_SMS_FastLogin_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode = "login" case "register": content = fmt.Sprintf("【%s】注册验证码:%s", appName, captcha) key = fmt.Sprintf("%s_SMS_FastLogin_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode = "register" } marshal, _ := json.Marshal(c.Request.Header) waykeys := "app_" + c.ClientIP() + "_" + utils.IntToStr(utils.GetApiVersion(c)) + "_" + c.Request.RequestURI + "_" + string(marshal) postData := map[string]interface{}{ "content": content, "mobile": req["phone"], "templateCode": templateCode, "way": php2go.Base64Encode(waykeys), } requestBody := new(md.Register) requestBody.Mobile = req["phone"] requestBody.Captcha = captcha if requestBody.Zone == "" { requestBody.Zone = "86" } err = sms.GetSmsConfig(c, requestBody.Zone, postData) if err != nil { e.OutErr(c, 400, err) return } tmp := struct { Data md.Register `json:"data"` CacheTime int64 `json:"cache_time"` }{ Data: *requestBody, CacheTime: time.Now().Unix(), } if _, err := cache.SetEx(key, utils.Serialize(tmp), 180); err != nil { e.OutErr(c, e.ERR, err) return } //存入一个缓存 用于邀请码注册时候判断 keys := fmt.Sprintf("%s_SMSCHECK_%s", c.GetString("mid"), requestBody.Mobile) tmps := struct { Check int `json:"check"` CacheTime int64 `json:"cache_time"` }{ Check: 1, CacheTime: time.Now().Unix(), } if _, err := cache.SetEx(keys, utils.Serialize(tmps), 3600); err != nil { e.OutErr(c, e.ERR, err) return } e.OutSuc(c, "验证码已发送,3分钟内有效", nil) return } func Sms(c *gin.Context) { var req map[string]string if err := c.ShouldBindJSON(&req); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } user := svc.GetUser(c) req["phone"] = user.Info.Phone types := req["type"] var err error smsType := svc.SysCfgGet(c, "sms_type") c.Set("sms_type", smsType) if c.GetString("sms_type") == "1" { count := sms2.SmsNumGetSmsNum(db.Db, "putong", c.GetString("mid")) if count-1 < 0 { e.OutErr(c, e.ERR_MOB_SMS_NO_AVA, err) return } } else { count, _ := zhimeng.SmsNum(db.Db, c.GetString("mid"), c.GetString("sms_type"), db.SysCfgGet(c, "third_zm_sms_key"), db.SysCfgGet(c, "third_zm_sms_secret")) if count-1 < 0 { e.OutErr(c, e.ERR_MOB_SMS_NO_AVA, err) return } } appName := db.SysCfgGet(c, "sms_push_sign") captcha := createCaptcha() content := fmt.Sprintf("【%s】验证码:%s", appName, captcha) key := fmt.Sprintf("%s_SMS_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode := "" switch types { case "login": content = fmt.Sprintf("【%s】快捷登录验证码:%s", appName, captcha) key = fmt.Sprintf("%s_SMS_FastLogin_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode = "login" case "bind_alipay": content = fmt.Sprintf("【%s】绑定支付宝验证码:%s", appName, captcha) key = fmt.Sprintf("%s_SMS_FastLogin_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode = "bind_alipay" case "register": content = fmt.Sprintf("【%s】注册验证码:%s", appName, captcha) key = fmt.Sprintf("%s_SMS_FastLogin_%s", db.SysCfgGet(c, "app_name"), req["phone"]) templateCode = "register" } marshal, _ := json.Marshal(c.Request.Header) waykeys := "app_" + c.ClientIP() + "_" + utils.IntToStr(utils.GetApiVersion(c)) + "_" + c.Request.RequestURI + "_" + string(marshal) postData := map[string]interface{}{ "content": content, "mobile": req["phone"], "templateCode": templateCode, "way": php2go.Base64Encode(waykeys), } requestBody := new(md.Register) requestBody.Mobile = req["phone"] requestBody.Captcha = captcha if requestBody.Zone == "" { requestBody.Zone = "86" } err = sms.GetSmsConfig(c, requestBody.Zone, postData) if err != nil { e.OutErr(c, 400, err) return } tmp := struct { Data md.Register `json:"data"` CacheTime int64 `json:"cache_time"` }{ Data: *requestBody, CacheTime: time.Now().Unix(), } if _, err := cache.SetEx(key, utils.Serialize(tmp), 180); err != nil { e.OutErr(c, e.ERR, err) return } //存入一个缓存 用于邀请码注册时候判断 keys := fmt.Sprintf("%s_SMSCHECK_%s", c.GetString("mid"), requestBody.Mobile) tmps := struct { Check int `json:"check"` CacheTime int64 `json:"cache_time"` }{ Check: 1, CacheTime: time.Now().Unix(), } if _, err := cache.SetEx(keys, utils.Serialize(tmps), 3600); err != nil { e.OutErr(c, e.ERR, err) return } e.OutSuc(c, "验证码已发送,3分钟内有效", nil) return } func createCaptcha() string { return fmt.Sprintf("%05v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000)) }