增加自定义绑定域名
This commit is contained in:
@@ -323,20 +323,31 @@ func (c *BackendTenantDomainController) Index() {
|
||||
|
||||
tid, _ := c.GetUint64("tid")
|
||||
statusStr := strings.TrimSpace(c.GetString("status"))
|
||||
subDomain := strings.TrimSpace(c.GetString("sub_domain"))
|
||||
keyword := strings.TrimSpace(c.GetString("sub_domain"))
|
||||
domainTypeStr := strings.TrimSpace(c.GetString("domain_type"))
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.SystemTenantDomain)).Filter("delete_time__isnull", true)
|
||||
// 条件一次性拼好:SetCond 会覆盖 Filter 累积的条件,不能混用
|
||||
cond := orm.NewCondition().And("delete_time__isnull", true)
|
||||
if tid > 0 {
|
||||
qs = qs.Filter("tid", tid)
|
||||
cond = cond.And("tid", tid)
|
||||
}
|
||||
if statusStr != "" {
|
||||
if st, err := strconv.Atoi(statusStr); err == nil {
|
||||
qs = qs.Filter("status", st)
|
||||
cond = cond.And("status", st)
|
||||
}
|
||||
}
|
||||
if subDomain != "" {
|
||||
qs = qs.Filter("sub_domain__icontains", subDomain)
|
||||
if domainTypeStr != "" {
|
||||
if dt, err := strconv.Atoi(domainTypeStr); err == nil {
|
||||
cond = cond.And("domain_type", dt)
|
||||
}
|
||||
}
|
||||
// 关键字同时匹配二级前缀与完整域名:自有域名没有 sub_domain,只能靠 full_domain 命中
|
||||
if keyword != "" {
|
||||
cond = cond.AndCond(orm.NewCondition().
|
||||
Or("sub_domain__icontains", keyword).
|
||||
Or("full_domain__icontains", keyword))
|
||||
}
|
||||
qs := models.Orm.QueryTable(new(models.SystemTenantDomain)).SetCond(cond)
|
||||
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
@@ -349,8 +360,7 @@ func (c *BackendTenantDomainController) Index() {
|
||||
jsonErr(&c.Controller, 500, 500, "获取租户域名失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
list := make([]models.SystemTenantDomain, 0, len(rows))
|
||||
list = append(list, rows...)
|
||||
list := tenantDomainList(rows)
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
@@ -359,20 +369,21 @@ func (c *BackendTenantDomainController) Index() {
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// MyDomains GET /backend/domain/tenant/myDomains?tid=1
|
||||
// MyDomains GET /backend/domain/tenant/myDomains
|
||||
// 租户 ID 取登录态,忽略请求参数里的 tid,避免越权查看其他租户域名。
|
||||
func (c *BackendTenantDomainController) MyDomains() {
|
||||
if _, err := requireBackend(&c.Controller); err != nil {
|
||||
claims, err := requireBackend(&c.Controller)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
tid, _ := c.GetUint64("tid")
|
||||
if tid == 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "租户ID不能为空")
|
||||
if claims.TenantId <= 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "当前登录账号未归属租户")
|
||||
return
|
||||
}
|
||||
var rows []models.SystemTenantDomain
|
||||
_, err := models.Orm.QueryTable(new(models.SystemTenantDomain)).
|
||||
Filter("tid", tid).
|
||||
_, err = models.Orm.QueryTable(new(models.SystemTenantDomain)).
|
||||
Filter("tid", claims.TenantId).
|
||||
Filter("delete_time__isnull", true).
|
||||
OrderBy("-id").
|
||||
All(&rows)
|
||||
@@ -380,23 +391,101 @@ func (c *BackendTenantDomainController) MyDomains() {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": rows}
|
||||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": tenantDomainList(rows)}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// Apply POST /backend/domain/tenant/apply body:{tid,sub_domain,main_domain}
|
||||
func (c *BackendTenantDomainController) Apply() {
|
||||
// BindCustom POST /backend/domain/tenant/bindCustom body:{domain}
|
||||
// 绑定租户自有域名。租户 ID 取登录态。
|
||||
func (c *BackendTenantDomainController) BindCustom() {
|
||||
claims, err := requireBackend(&c.Controller)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
if claims.TenantId <= 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "当前登录账号未归属租户")
|
||||
return
|
||||
}
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
var p customDomainPayload
|
||||
if err := json.Unmarshal(raw, &p); err != nil {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
id, status, errMsg := bindCustomDomain(uint64(claims.TenantId), p.Domain)
|
||||
if errMsg != "" {
|
||||
jsonErr(&c.Controller, status, status, errMsg)
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "绑定成功,请按提示配置解析后点击「检测解析」",
|
||||
"data": map[string]interface{}{"id": id},
|
||||
}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// CheckCustomDns POST /backend/domain/tenant/checkCustomDns body:{id}
|
||||
// 检测自有域名解析,通过后异步申请 HTTPS 证书。
|
||||
func (c *BackendTenantDomainController) CheckCustomDns() {
|
||||
claims, err := requireBackend(&c.Controller)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
if claims.TenantId <= 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "当前登录账号未归属租户")
|
||||
return
|
||||
}
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
var p domainIDPayload
|
||||
if err := json.Unmarshal(raw, &p); err != nil {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
data, status, errMsg := checkCustomDomainDNS(p.ID, uint64(claims.TenantId))
|
||||
if errMsg != "" {
|
||||
jsonErr(&c.Controller, status, status, errMsg)
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// CustomDomainGuide GET /backend/domain/tenant/customDomainGuide
|
||||
// 返回租户该怎么配解析(CNAME 目标 / A 记录 IP),前端不硬编码。
|
||||
func (c *BackendTenantDomainController) CustomDomainGuide() {
|
||||
if _, err := requireBackend(&c.Controller); err != nil {
|
||||
jsonErr(&c.Controller, 401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": customDomainGuideData()}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// Apply POST /backend/domain/tenant/apply body:{sub_domain,main_domain}
|
||||
// 租户 ID 取登录态,不信请求体,避免替其他租户申请。
|
||||
func (c *BackendTenantDomainController) Apply() {
|
||||
claims, err := requireBackend(&c.Controller)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
raw, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
var p struct {
|
||||
Tid uint64 `json:"tid"`
|
||||
SubDomain string `json:"sub_domain"`
|
||||
MainDomain string `json:"main_domain"`
|
||||
}
|
||||
@@ -404,10 +493,11 @@ func (c *BackendTenantDomainController) Apply() {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
if p.Tid == 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "租户ID不能为空")
|
||||
if claims.TenantId <= 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "当前登录账号未归属租户")
|
||||
return
|
||||
}
|
||||
tenantID := uint64(claims.TenantId)
|
||||
sub := strings.TrimSpace(p.SubDomain)
|
||||
main := strings.TrimSpace(p.MainDomain)
|
||||
if sub == "" {
|
||||
@@ -423,13 +513,14 @@ func (c *BackendTenantDomainController) Apply() {
|
||||
return
|
||||
}
|
||||
|
||||
// 该租户是否已有域名
|
||||
// 该租户是否已申请过平台二级域名(自有域名单独计数,两者可以共存)
|
||||
cnt, _ := models.Orm.QueryTable(new(models.SystemTenantDomain)).
|
||||
Filter("tid", p.Tid).
|
||||
Filter("tid", tenantID).
|
||||
Filter("domain_type", models.DomainTypePlatformSub).
|
||||
Filter("delete_time__isnull", true).
|
||||
Count()
|
||||
if cnt > 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "该租户已有域名,请删除后再次申请")
|
||||
jsonErr(&c.Controller, 400, 400, "该租户已有二级域名,请删除后再次申请")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -457,9 +548,10 @@ func (c *BackendTenantDomainController) Apply() {
|
||||
|
||||
full := sub + "." + main
|
||||
now := time.Now()
|
||||
tid := p.Tid
|
||||
tid := tenantID
|
||||
row := &models.SystemTenantDomain{
|
||||
Tid: &tid,
|
||||
DomainType: models.DomainTypePlatformSub,
|
||||
SubDomain: &sub,
|
||||
MainDomain: &main,
|
||||
FullDomain: &full,
|
||||
@@ -500,6 +592,10 @@ func (c *BackendTenantDomainController) Audit() {
|
||||
jsonErr(&c.Controller, 404, 404, "域名不存在")
|
||||
return
|
||||
}
|
||||
if row.DomainType == models.DomainTypeCustom {
|
||||
jsonErr(&c.Controller, 400, 400, "自有域名无需人工审核,解析检测与证书签发通过后自动生效")
|
||||
return
|
||||
}
|
||||
if row.Status != 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "该域名已审核过了")
|
||||
return
|
||||
@@ -547,11 +643,20 @@ func (c *BackendTenantDomainController) ToggleStatus() {
|
||||
return
|
||||
}
|
||||
if row.Status == 0 {
|
||||
jsonErr(&c.Controller, 400, 400, "审核中不可操作")
|
||||
if row.DomainType == models.DomainTypeCustom {
|
||||
jsonErr(&c.Controller, 400, 400, "该域名尚未生效(解析或证书未就绪),无需禁用")
|
||||
} else {
|
||||
jsonErr(&c.Controller, 400, 400, "审核中不可操作")
|
||||
}
|
||||
return
|
||||
}
|
||||
newStatus := 2
|
||||
if row.Status == 2 {
|
||||
// 自有域名重新启用要求证书还在,否则启用后访问会报证书错误
|
||||
if row.DomainType == models.DomainTypeCustom && row.SSLStatus != models.SSLStatusIssued {
|
||||
jsonErr(&c.Controller, 400, 400, "该域名的 HTTPS 证书未就绪,请先检测解析并等待证书签发")
|
||||
return
|
||||
}
|
||||
newStatus = 1
|
||||
}
|
||||
now := time.Now()
|
||||
@@ -568,8 +673,10 @@ func (c *BackendTenantDomainController) ToggleStatus() {
|
||||
}
|
||||
|
||||
// Delete DELETE /backend/domain/tenant/delete/:id
|
||||
// 只能删除本租户的域名记录。
|
||||
func (c *BackendTenantDomainController) Delete() {
|
||||
if _, err := requireBackend(&c.Controller); err != nil {
|
||||
claims, err := requireBackend(&c.Controller)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 401, 401, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -579,11 +686,14 @@ func (c *BackendTenantDomainController) Delete() {
|
||||
jsonErr(&c.Controller, 400, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
n, err := models.Orm.QueryTable(new(models.SystemTenantDomain)).
|
||||
qs := models.Orm.QueryTable(new(models.SystemTenantDomain)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{"delete_time": now, "update_time": now})
|
||||
Filter("delete_time__isnull", true)
|
||||
if claims.TenantId > 0 {
|
||||
qs = qs.Filter("tid", claims.TenantId)
|
||||
}
|
||||
now := time.Now()
|
||||
n, err := qs.Update(map[string]interface{}{"delete_time": now, "update_time": now})
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error())
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user