package services import ( "encoding/json" "errors" "eta/eta_api/models" "eta/eta_api/models/company" "eta/eta_api/models/system" "eta/eta_api/utils" "fmt" "github.com/go-ldap/ldap" "io" "net/http" "strconv" "strings" "time" ) // SendAdminMobileVerifyCode 发送用户手机验证码 func SendAdminMobileVerifyCode(source int, mobile, areaCode string) (ok bool, err error) { defer func() { if err != nil { tips := fmt.Sprintf("SendAdminMobileVerifyCode ErrMsg: %s", err.Error()) utils.FileLog.Info(tips) fmt.Println(tips) } }() smsClient, e := NewSmsClient() if e != nil { err = fmt.Errorf("NewSmsClient err: %s", e.Error()) return } verifyCode := utils.GetRandDigit(6) record := new(system.AdminVerifyCodeRecord) record.VerifyType = system.AdminVerifyCodeRecordTypeMobile record.Mobile = mobile record.Source = source record.Code = verifyCode record.ExpiredTime = time.Now().Add(utils.VerifyCodeExpireMinute * time.Minute) record.CreateTime = time.Now().Local() record.ModifyTime = time.Now().Local() if e := record.Create(); e != nil { err = fmt.Errorf("新增验证码记录失败, Err: %s", e.Error()) return } var smsReq UserLoginSmsCodeReq smsReq.Mobile = mobile smsReq.TelAreaCode = areaCode smsReq.VerifyCode = verifyCode smsResult, e := smsClient.SendUserLoginCode(smsReq) if e != nil { err = fmt.Errorf("SendUserLoginCode err: %s", e.Error()) return } ok = smsResult.Success record.SendStatus = system.AdminVerifyCodeRecordStatusSuccess if !ok { record.SendStatus = system.AdminVerifyCodeRecordStatusFail } record.RequestId = smsResult.RequestId cols := []string{"SendStatus", "RequestId"} if e := record.Update(cols); e != nil { err = fmt.Errorf("更新验证码记录失败, Err: %s", e.Error()) } return } // SendAdminEmailVerifyCode 发送用户邮箱验证码 func SendAdminEmailVerifyCode(source int, email string) (ok bool, err error) { defer func() { if err != nil { tips := fmt.Sprintf("SendAdminEmailVerifyCode ErrMsg: %s", err.Error()) utils.FileLog.Info(tips) fmt.Println(tips) } }() // 读取配置 confMap, e := models.GetBusinessConf() if e != nil { err = fmt.Errorf("GetBusinessConf err: %s", e.Error()) return } subjectConf := confMap[models.BusinessConfLoginEmailTemplateSubject] contentConf := confMap[models.BusinessConfLoginEmailTemplateContent] if subjectConf == "" { err = fmt.Errorf("请先配置邮件模版主题") return } if contentConf == "" { err = fmt.Errorf("请先配置邮件模版内容") return } verifyCode := utils.GetRandDigit(6) t := time.Now().Format("2006年01月02日") emailContent := contentConf emailContent = strings.Replace(emailContent, "{{VERIFY_CODE}}", verifyCode, 1) emailContent = strings.Replace(emailContent, "{{EXPIRED_MINUTE}}", strconv.Itoa(utils.VerifyCodeExpireMinute), 1) emailContent = strings.Replace(emailContent, "{{DATE_TIME}}", t, 1) // 验证码记录 record := new(system.AdminVerifyCodeRecord) record.VerifyType = system.AdminVerifyCodeRecordTypeEmail record.Email = email record.Source = source record.Code = verifyCode record.ExpiredTime = time.Now().Add(utils.VerifyCodeExpireMinute * time.Minute) record.CreateTime = time.Now().Local() record.ModifyTime = time.Now().Local() if e := record.Create(); e != nil { err = fmt.Errorf("新增验证码记录失败, Err: %s", e.Error()) return } var result string if confMap[models.BusinessConfEmailClient] == models.BusinessConfEmailClientSmtp { // 普通邮箱 var emailReq SendEmailReq emailReq.Title = subjectConf emailReq.Content = emailContent emailReq.ToUser = append(emailReq.ToUser, email) ok, e = SendEmail(emailReq) if e != nil { err = fmt.Errorf("邮箱推送失败, Err: %s", e.Error()) return } } else { // 默认阿里云邮箱 // 读取发信人昵称配置...后面可以优化一下 authKey := "english_report_email_conf" emailConf, e := company.GetConfigDetailByCode(authKey) if e != nil { err = fmt.Errorf("获取群发邮件权限失败, Err: %s", e.Error()) return } if emailConf.ConfigValue == "" { err = fmt.Errorf("邮件配置为空, 不可推送") return } conf := new(models.EnglishReportEmailConf) if e = json.Unmarshal([]byte(emailConf.ConfigValue), &conf); e != nil { err = fmt.Errorf("邮件配置有误, 不可推送") return } req := new(EnglishReportSendEmailRequest) req.Subject = subjectConf req.Email = email req.FromAlias = conf.FromAlias // 发信人昵称 req.HtmlBody = emailContent aliEmail := new(AliyunEmail) o, r, e := aliEmail.SendEmail(req) if e != nil { err = fmt.Errorf("阿里云邮箱推送失败, Err: %s", e.Error()) return } ok = o result = r } record.SendStatus = system.AdminVerifyCodeRecordStatusSuccess if !ok { record.SendStatus = system.AdminVerifyCodeRecordStatusFail } record.SendResult = result cols := []string{"SendStatus", "SendResult"} if e = record.Update(cols); e != nil { err = fmt.Errorf("更新验证码记录失败, Err: %s", e.Error()) } return } // LdapUserCheck AD域用户校验 func LdapUserCheck(userName, password string) (pass bool, err error) { defer func() { if err != nil { tips := fmt.Sprintf("LdapUserCheck ErrMsg: %s", err.Error()) utils.FileLog.Info(tips) fmt.Println(tips) } }() if userName == "" || password == "" { err = fmt.Errorf("账号密码有误") return } confMap, e := models.GetBusinessConf() if e != nil { err = fmt.Errorf("GetBusinessConf err: %s", e.Error()) return } if confMap[models.BusinessConfLdapHost] == "" || confMap[models.BusinessConfLdapBase] == "" { err = fmt.Errorf("AD域配置有误") return } ldapPort, _ := strconv.Atoi(confMap[models.BusinessConfLdapPort]) if ldapPort <= 0 { err = fmt.Errorf("AD域端口号有误, Port: %d", ldapPort) return } // 连接ldap addr := fmt.Sprintf("%s:%d", confMap[models.BusinessConfLdapHost], ldapPort) conn, e := ldap.Dial("tcp", addr) if e != nil { err = fmt.Errorf("ldap Dial err: %s", e.Error()) return } defer conn.Close() // 绑定用户 bindUserName := fmt.Sprintf("%s%s", userName, confMap[models.BusinessConfLdapBindUserSuffix]) if e = conn.Bind(bindUserName, password); e != nil { err = fmt.Errorf("ldap Bind err: %s", e.Error()) return } // 鉴权操作 searchRequest := ldap.NewSearchRequest( confMap[models.BusinessConfLdapBase], ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, fmt.Sprintf(confMap[models.BusinessConfLdapUserFilter], userName), []string{"dn"}, nil, ) //b, _ := json.Marshal(searchRequest) //fmt.Println("searchRequest: ", string(b)) sr, e := conn.Search(searchRequest) if e != nil { err = fmt.Errorf("ldap Search err: %s", e.Error()) return } // 验证结果 if len(sr.Entries) != 1 { utils.FileLog.Info("ldap check fail: user does not exist or too many entries returned") return } pass = true return } // ThirdLogin // @Description: 第三方登录(换取token) // @author: Roc // @datetime 2024-01-30 16:09:18 // @param req map[string]interface{} // @return data GetCrmTokenData // @return err error // @return errMsg string func ThirdLogin(req map[string]interface{}) (data GetCrmTokenData, err error, errMsg string) { if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox { authCode, ok := req["code"] if !ok { errMsg = "参数有误" err = errors.New("参数缺失, code") return } authCodeStr := fmt.Sprint(authCode) if authCodeStr == "" { errMsg = "参数有误" err = errors.New("参数缺失, AuthCode") return } data, err = CodeLoginFromMiddleServer(authCodeStr) return } data, err, errMsg = ThirdCodeLoginFromMiddleServer(req) // 普通的第三方 return } // ThirdCodeLoginFromMiddleServer // @Description: 第三方登录(向桥接服务换取token) // @author: Roc // @datetime 2024-01-30 16:09:35 // @param param map[string]interface{} // @return tokenResp GetCrmTokenData // @return err error func ThirdCodeLoginFromMiddleServer(param map[string]interface{}) (tokenResp GetCrmTokenData, err error, errMsg string) { if utils.EtaBridgeUrl == `` || utils.EtaBridgeLoginUrl == "" { errMsg = `未配置第三方登录的桥接服务地址` err = errors.New(errMsg) return } data, e := json.Marshal(param) if e != nil { err = fmt.Errorf("data json marshal err: %s", e.Error()) return } body := io.NopCloser(strings.NewReader(string(data))) client := &http.Client{} req, e := http.NewRequest("POST", utils.EtaBridgeUrl+utils.EtaBridgeLoginUrl, body) if e != nil { err = fmt.Errorf("http create request err: %s", e.Error()) return } contentType := "application/json;charset=utf-8" req.Header.Set("Content-Type", contentType) checkToken := utils.MD5(utils.EtaBridgeAppNameEn + utils.EtaBridgeMd5Key) req.Header.Set("Authorization", checkToken) resp, e := client.Do(req) if e != nil { err = fmt.Errorf("http client do err: %s", e.Error()) return } defer func() { _ = resp.Body.Close() }() b, e := io.ReadAll(resp.Body) if e != nil { err = fmt.Errorf("resp body read err: %s", e.Error()) return } if len(b) == 0 { err = fmt.Errorf("resp body is empty") return } // 生产环境解密, 注意有个坑前后的双引号 if utils.RunMode == "release" { str := string(b) str = strings.Trim(str, `"`) b = utils.DesBase64Decrypt([]byte(str), utils.EtaBridgeDesKey) } result := new(GetCrmTokenDataResp) if e = json.Unmarshal(b, &result); e != nil { err = fmt.Errorf("result unmarshal err: %s\nresult: %s", e.Error(), string(b)) utils.FileLog.Info("第三方登录(向桥接服务换取token):\n" + string(b)) return } if result.Code != 200 { errMsg = result.Msg err = fmt.Errorf("result: %s", string(b)) return } tokenResp = result.Data return } // ThirdLogout // @Description: 第三方登出 // @author: Roc // @datetime 2024-01-30 16:09:18 // @param req map[string]interface{} // @return data GetCrmTokenData // @return err error func ThirdLogout(accessToken string) (err error) { if utils.EtaBridgeUrl == "" || utils.EtaBridgeLogoutUrl == "" { // 未配置第三方登出的桥接服务地址 return } params := map[string]interface{}{ "access_token": accessToken, } data, e := json.Marshal(params) if e != nil { err = fmt.Errorf("data json marshal err: %s", e.Error()) return } body := io.NopCloser(strings.NewReader(string(data))) client := &http.Client{} req, e := http.NewRequest("POST", utils.EtaBridgeUrl+utils.EtaBridgeLogoutUrl, body) if e != nil { err = fmt.Errorf("http create request err: %s", e.Error()) return } contentType := "application/json;charset=utf-8" req.Header.Set("Content-Type", contentType) checkToken := utils.MD5(utils.EtaBridgeAppNameEn + utils.EtaBridgeMd5Key) req.Header.Set("Authorization", checkToken) resp, e := client.Do(req) if e != nil { err = fmt.Errorf("http client do err: %s", e.Error()) return } defer func() { _ = resp.Body.Close() }() b, e := io.ReadAll(resp.Body) if e != nil { err = fmt.Errorf("resp body read err: %s", e.Error()) return } if len(b) == 0 { err = fmt.Errorf("resp body is empty") return } // 生产环境解密, 注意有个坑前后的双引号 if utils.RunMode == "release" { str := string(b) str = strings.Trim(str, `"`) b = utils.DesBase64Decrypt([]byte(str), utils.EtaBridgeDesKey) } result := new(GetCrmTokenDataResp) if e = json.Unmarshal(b, &result); e != nil { err = fmt.Errorf("result unmarshal err: %s\nresult: %s", e.Error(), string(b)) return } if result.Code != 200 { err = fmt.Errorf("result: %s", string(b)) return } return }