更新登录

This commit is contained in:
2026-04-02 17:53:50 +08:00
parent d62872cc6c
commit d5d6c9fb4c
7 changed files with 450 additions and 18 deletions
+136 -16
View File
@@ -1,9 +1,13 @@
package services
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"net/http"
"strings"
"sync"
"time"
@@ -98,24 +102,48 @@ func SendBackendLoginCode(tenantName, account, channel string) error {
if err := models.Orm.QueryTable(new(models.Tenant)).Filter("tenant_name", tenantName).One(&tenant); err != nil {
return errors.New("租户不存在")
}
var user models.TenantUser
if err := models.Orm.QueryTable(new(models.TenantUser)).
Filter("tid", tenant.ID).
Filter("account", account).
One(&user); err != nil {
return errors.New("用户不存在")
}
if user.Status == 0 {
return errors.New("账号已禁用")
}
if channel == "sms" && (user.Phone == nil || strings.TrimSpace(*user.Phone) == "") {
return errors.New("该账号未绑定手机号")
}
if channel == "email" && (user.Email == nil || strings.TrimSpace(*user.Email) == "") {
return errors.New("该账号未绑定邮箱")
}
rand.Seed(time.Now().UnixNano())
code := fmt.Sprintf("%06d", rand.Intn(1000000))
// 规则:先校验租户,再校验“输入的手机号/邮箱”是否为该租户已绑定的记录
switch channel {
case "sms":
phone := account
var user models.TenantUser
if err := models.Orm.QueryTable(new(models.TenantUser)).
Filter("tid", tenant.ID).
Filter("phone", phone).
One(&user); err != nil {
return errors.New("该手机号非当前企业绑定号码,请重试")
}
if user.Status == 0 {
return errors.New("账号已禁用")
}
if user.Phone == nil || strings.TrimSpace(*user.Phone) == "" {
return errors.New("该手机号非当前企业绑定号码,请重试")
}
content := "短信验证码:" + code
if err := enqueueSMSTaskForLogin(tenant.ID, phone, content, code); err != nil {
return errors.New("短信发送失败,请重试")
}
case "email":
email := account
var user models.TenantUser
if err := models.Orm.QueryTable(new(models.TenantUser)).
Filter("tid", tenant.ID).
Filter("email", email).
One(&user); err != nil {
return errors.New("该账号未绑定邮箱")
}
if user.Status == 0 {
return errors.New("账号已禁用")
}
if user.Email == nil || strings.TrimSpace(*user.Email) == "" {
return errors.New("该账号未绑定邮箱")
}
}
loginCodeStore.Store(codeKey(tenantName+"#"+account, channel), loginCodeItem{
Code: code,
Channel: channel,
@@ -128,3 +156,95 @@ func VerifyBackendLoginCode(tenantName, account, channel, code string) error {
return VerifyPlatformLoginCode(tenantName+"#"+account, channel, code)
}
func getDefaultSystemSMSConfig() (backendURL string, apiKey string, err error) {
var row models.SystemSMS
err = models.Orm.QueryTable(new(models.SystemSMS)).
Filter("is_default", 1).
Filter("status", 1).
OrderBy("-weight", "-id").
Limit(1).
One(&row)
if err != nil {
// fallback:自定义网关
err2 := models.Orm.QueryTable(new(models.SystemSMS)).
Filter("config_code", "custom").
OrderBy("-id").
Limit(1).
One(&row)
if err2 != nil {
return "", "", err2
}
}
backendURL = strings.TrimSpace(row.ApiURL)
apiKey = strings.TrimSpace(row.ApiKey)
return backendURL, apiKey, nil
}
// enqueueSMSTaskForLogin 入队短信任务到网关,并写入 yz_system_sms_tasks
func enqueueSMSTaskForLogin(tid uint64, phone, content, code string) error {
backendURL, apiKey, err := getDefaultSystemSMSConfig()
if err != nil {
return err
}
if backendURL == "" || apiKey == "" {
return errors.New("短信网关未配置")
}
enqueueURL := strings.TrimRight(backendURL, "/") + "/api/v1/business/outbound-tasks"
payload := map[string]interface{}{
"phone": phone,
"content": content,
}
bs, _ := json.Marshal(payload)
client := &http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest("POST", enqueueURL, bytes.NewReader(bs))
if err != nil {
return err
}
req.Header.Set("X-Api-Key", apiKey)
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.Header.Set("Accept", "application/json")
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
bodyBytes, _ := io.ReadAll(resp.Body)
bodyStr := strings.TrimSpace(string(bodyBytes))
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("gateway http status: %d, body: %s", resp.StatusCode, bodyStr)
}
// 2xx:认为已成功提交
now := time.Now()
tidCopy := tid
contentPtr := content
var reportPtr *string
if bodyStr != "" {
reportPtr = &bodyStr
}
task := &models.SystemSMSTask{
Tid: &tidCopy,
ApiKey: apiKey,
Phone: phone,
Content: &contentPtr,
Status: 3,
Code: code,
ReportRaw: reportPtr,
CreateTime: &now,
UpdateTime: &now,
}
_, insertErr := models.Orm.Insert(task)
// 入队成功但写任务表失败:不影响用户侧体验
if insertErr != nil {
return nil
}
return nil
}