package services import ( "encoding/json" "errors" "eta_gn/eta_api/models" "eta_gn/eta_api/models/system" "eta_gn/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 // 普通邮箱 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 } 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) { // 普通的第三方 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 } // UserLoginChange 切换用户 func UserLoginChange(adminName string) (resp *system.LoginResp, err error) { sysUser, e := system.GetSysUserByAdminName(adminName) if e != nil { if utils.IsErrNoRow(e) { err = fmt.Errorf("用户不存在: %s", adminName) return } err = fmt.Errorf("获取用户失败, %v", e) return } // 生成token account := utils.MD5(sysUser.AdminName) token := utils.GenToken(account) sysSession := new(system.SysSession) sysSession.UserName = sysUser.AdminName sysSession.SysUserId = sysUser.AdminId sysSession.ExpiredTime = time.Now().AddDate(0, 0, 90) sysSession.IsRemember = 0 // 均需要做过期校验 sysSession.CreatedTime = time.Now() sysSession.LastUpdatedTime = time.Now() sysSession.AccessToken = token if e := system.AddSysSession(sysSession); e != nil { err = fmt.Errorf("新增session失败, %v", e) return } // 修改最后登录时间 { sysUser.LastLoginTime = time.Now().Format(utils.FormatDateTime) sysUser.LastUpdatedTime = time.Now().Format(utils.FormatDateTime) _ = sysUser.Update([]string{"LastLoginTime", "LastUpdatedTime"}) } resp = new(system.LoginResp) resp.Authorization = token resp.Authorization = "authorization=" + token resp.RealName = sysUser.RealName resp.AdminName = sysUser.AdminName resp.RoleName = sysUser.RoleName resp.SysRoleTypeCode = sysUser.RoleTypeCode //系统角色编码 resp.RoleTypeCode = sysUser.RoleTypeCode if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_GROUP { resp.RoleTypeCode = utils.ROLE_TYPE_CODE_FICC_SELLER } if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_TEAM { resp.RoleTypeCode = utils.ROLE_TYPE_CODE_FICC_SELLER } if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_DEPARTMENT { resp.RoleTypeCode = utils.ROLE_TYPE_CODE_FICC_SELLER } if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_GROUP { resp.RoleTypeCode = utils.ROLE_TYPE_CODE_RAI_SELLER } if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_RAI_DEPARTMENT { resp.RoleTypeCode = utils.ROLE_TYPE_CODE_RAI_SELLER } if sysUser.RoleName == utils.ROLE_NAME_FICC_DIRECTOR { resp.RoleTypeCode = utils.ROLE_TYPE_CODE_FICC_SELLER } resp.AdminId = sysUser.AdminId var productName string productId := GetProductId(sysUser.RoleTypeCode) if productId == 1 { productName = utils.COMPANY_PRODUCT_FICC_NAME } else if productId == 2 { productName = utils.COMPANY_PRODUCT_RAI_NAME } else { productName = "admin" } resp.ProductName = productName resp.Authority = sysUser.Authority // 设置redis缓存 { // 获取不可信的登录态,并将该登录态重置掉,不允许多次登录 noTrustLoginKey := fmt.Sprint(utils.CACHE_ACCESS_TOKEN_LOGIN_NO_TRUST, sysUser.AdminId) noTrustLoginId, _ := utils.Rc.RedisString(noTrustLoginKey) if noTrustLoginId != `` { // 如果存在不可信设备,那么将其下架 oldNoTrustLoginKey := fmt.Sprint(utils.CACHE_ACCESS_TOKEN_LOGIN, noTrustLoginId) _ = utils.Rc.Put(oldNoTrustLoginKey, "0", utils.LoginCacheTime*time.Minute) } // 如果当前是不可信设备,那么将其加入到不可信名单 loginKey := fmt.Sprint(utils.CACHE_ACCESS_TOKEN_LOGIN, sysSession.Id) _ = utils.Rc.Put(loginKey, "1", utils.LoginCacheTime*time.Minute) _ = utils.Rc.Put(noTrustLoginKey, sysSession.Id, utils.LoginCacheTime*time.Minute) } // 新增登录记录 go func() { record := new(system.SysUserLoginRecord) record.Uid = sysUser.AdminId record.UserName = adminName //record.Ip = this.Ctx.Input.IP() record.Stage = "login" record.CreateTime = time.Now() _ = system.AddSysUserLoginRecord(record) }() return }