package user import ( "bufio" "errors" "eta/eta_mini_ht_api/common/component/config" logger "eta/eta_mini_ht_api/common/component/log" "eta/eta_mini_ht_api/common/contants" "eta/eta_mini_ht_api/common/exception" authUtils "eta/eta_mini_ht_api/common/utils/auth" "eta/eta_mini_ht_api/controllers" "eta/eta_mini_ht_api/service/auth" "eta/eta_mini_ht_api/service/user" "os" "strings" ) type AuthController struct { controllers.BaseController } const ChinaAreaCode = "+86" // LoginReq 获取验证码请求 type LoginReq struct { VerifyCode string `json:"verifyCode"` Mobile string `json:"mobile"` AreaCode string `json:"areaCode"` } // Logout 小程序退出登录接口 // @Summary 小程序退出登录接口 // @Description 用户小程序退出登录 // @Param mobile body LoginReq true "登录请求体" // @Success 200 {object} controllers.BaseResponse // @router /logout [post] func (a *AuthController) Logout() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("退出登录失败") userInfo := a.Data["user"].(user.User) err = auth.Logout(userInfo.Id, userInfo.OpenId) if err != nil { a.FailedResult("退出登录失败", result) return } a.SuccessResult("退出登录成功", nil, result) return }) } // Login 小程序登录接口 // @Summary 小程序用户登录 // @Description 用户通过微信小程序登录 // @Param mobile body LoginReq true "登录请求体" // @Success 200 {object} controllers.BaseResponse // @router /login [post] func (a *AuthController) Login() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("登录失败") loginReq := new(LoginReq) a.GetPostParams(loginReq) userInfo := a.Data["user"].(user.User) if userInfo.Mobile != "" && userInfo.Mobile != loginReq.Mobile { a.FailedResult("登录失败,已绑定手机号:"+userInfo.Mobile, result) err = exception.New(exception.LoginFailed) return } mobileUser, err := user.GetUserByMobile(loginReq.Mobile) if err != nil { var etaErr *exception.EtaError errors.As(err, &etaErr) if etaErr.ErrorCode != exception.TemplateUserNotFound { a.FailedResult("登录失败:"+userInfo.Mobile, result) err = exception.New(exception.UnknownError) return } } if mobileUser.Id > 0 && (mobileUser.Id != userInfo.Id && mobileUser.Mobile == loginReq.Mobile) { a.FailedResult("登录失败,该手机号已绑定过微信", result) err = exception.New(exception.LoginFailed) return } if loginReq.AreaCode == "" || !checkValidAreaCode(loginReq.AreaCode) { a.FailedResult("非法的手机区号", result) err = exception.New(exception.IllegalAreaCode) return } if loginReq.AreaCode == ChinaAreaCode && !authUtils.IsValidMobile(loginReq.Mobile) { a.FailedResult("只支持86的区号", result) err = exception.New(exception.IllegalPhoneNumber) return } err = auth.CheckUser(loginReq.Mobile, loginReq.VerifyCode) if err != nil { a.FailedResult("验证码错误", result) logger.Warn("验证码校验失败:%v", err) return } //用户手机为空需要绑定手机 if userInfo.Mobile == "" { //注册用户或者登录 err = auth.BindMobile(userInfo.Id, loginReq.Mobile, loginReq.AreaCode) if err != nil { a.FailedResult("登录异常,绑定手机失败", result) return } } //生成一个正式的登录token,生成登录流水 token, err := auth.Login(userInfo.Id, userInfo.OpenId, loginReq.Mobile, loginReq.VerifyCode) if err != nil { a.FailedResult("登录异常,生成accessToken失败", result) return } //财人汇判断是否是存量客户 a.SuccessResult("登录成功", &LoginResp{ Token: token, }, result) return }) } type LoginResp struct { Token string } // SmsCodeReq 获取验证码请求 type SmsCodeReq struct { Mobile string `json:"mobile"` AreaCode string `json:"areaCode"` } // SMSCode 小程序手机验证码接口 // @Summary 获取手机验证码 // @Param mobile body SmsCodeReq true "小程序手机验证码接口" // @Success 200 {object} controllers.BaseResponse // @Description 用户发送手机验证码 // @router /sendCode [post] func (a *AuthController) SMSCode() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("发送短信失败") mobile := new(SmsCodeReq) a.GetPostParams(mobile) if mobile.AreaCode == "" || !checkValidAreaCode(mobile.AreaCode) { a.FailedResult("发送短信失败", result) err = exception.New(exception.IllegalAreaCode) return } phoneNum := mobile.Mobile if mobile.AreaCode == ChinaAreaCode && !authUtils.IsValidMobile(phoneNum) { return result, exception.New(exception.IllegalPhoneNumber) } //发送短息 err = auth.SendSMSCode(phoneNum) if err != nil { logger.Warn("发送短信失败:%v", err) return result, err } if err != nil { return result, err } result = &controllers.WrapData{Msg: "验证码发送成功"} return result, nil }) } type RefreshTokenRes struct { Token string `json:"token"` Status string `json:"status"` IsBindMobile int `json:"isBindMobile"` TokenType string `json:"tokenType"` } // RefreshToken 更新token // @Summary 更新token // @Success 200 {object} controllers.BaseResponse // @Description 更新token // @router /refreshToken [get] func (a *AuthController) RefreshToken(code string) { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("刷新token失败") if code == "" { logger.Error("code不能为空") return result, exception.New(exception.WeChatCodeEmpty) } //刷新token token, isBindMobile, status, tokenType, err := auth.RefreshToken(code) if err != nil { logger.Error("刷新token失败:%v", err) a.FailedResult("刷新token失败", result) return } a.SuccessResult("刷新token成功", RefreshTokenRes{ Token: token, IsBindMobile: isBindMobile, TokenType: tokenType, Status: status, }, result) return }) } // AreaCodes 小程序手机验证码接口 // @Summary 获取手机验证码 // @Param mobile body SmsCodeReq true "小程序手机验证码接口" // @Success 200 {object} controllers.BaseResponse // @Description 用户发送手机验证码 // @router /areaCodes [get] func (a *AuthController) AreaCodes() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("获取区号失败") list, err := auth.GetAreaCodes() if err != nil { a.FailedResult("获取区号失败", result) } a.SuccessResult("获取区号成功", list, result) return }) } type WXAppidResp struct { AppId string } // WXAppid 获取APPID // @Summary 获取APPID // @Success 200 {object} controllers.BaseResponse // @Description 获取APPID // @router /wxAppid [get] func (a *AuthController) WXAppid() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("获取AppId失败") appid := config.GetConfig(contants.WECHAT).(*config.WechatConfig).GetAppid() if err != nil { a.FailedResult("获取AppId失败", result) } a.SuccessResult("获取AppId成功", WXAppidResp{ AppId: appid, }, result) return }) } type FileResp struct { Content string } // Notice 获取注册须知 // @Summary 获取注册须知 // @Success 200 {object} controllers.BaseResponse // @Description 获取注册须知 // @router /notice [get] func (a *AuthController) Notice() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("获取注册须知失败") fileConfig := config.GetConfig(contants.FILE).(*config.FileConfig) //publicKey := config.GetConfig(contants.FILE).(*config.FileConfig).GetPublicKey() noticeFile := fileConfig.GetNotice() content, err := readTextConfig(noticeFile) if err != nil { err = exception.New(exception.GetNoticeFileError) a.FailedResult("获取注册须知失败", result) } a.SuccessResult("获取注册须知成功", FileResp{ Content: content, }, result) return }) } // Disclaimer 获取免责声明 // @Summary 获取免责声明 // @Success 200 {object} controllers.BaseResponse // @Description 获取免责声明 // @router /disclaimer [get] func (a *AuthController) Disclaimer() { controllers.Wrap(&a.BaseController, func() (result *controllers.WrapData, err error) { result = a.InitWrapData("获取免责声明失败") fileConfig := config.GetConfig(contants.FILE).(*config.FileConfig) //publicKey := config.GetConfig(contants.FILE).(*config.FileConfig).GetPublicKey() disclaimerFile := fileConfig.GetDisclaimer() content, err := readTextConfig(disclaimerFile) if err != nil { a.FailedResult("获取免责声明失败", result) } a.SuccessResult("获取免责声明成功", FileResp{ Content: content, }, result) return }) } // 读取纯文本文件 func readTextConfig(filename string) (content string, err error) { file, err := os.Open(filename) if err != nil { return "", err } defer file.Close() scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) var lines []string for scanner.Scan() { line := scanner.Text() lines = append(lines, line) } err = scanner.Err() return strings.Join(lines, "\n"), nil } func checkValidAreaCode(areaCode string) bool { list := auth.GetValidAreaCodes() if areaCode == "" || len(list) == 0 { return false } for _, code := range list { if areaCode == code { return true } } return false }