Quellcode durchsuchen

refactor(ssl): 重构 SSL 证书处理逻辑

- 新增 SslCertService 接口和 sslCertService 实现类
- 解析证书、添加证书、编辑证书等功能移至 SslCertService 中
- 优化 SSL策略创建和编辑逻辑
- 调整 WebForwardingService 中的 SSL 相关调用
- 更新数据库模型和仓库接口,支持新的 SSL 证书处理方式
fusu vor 1 Monat
Ursprung
Commit
ea79e0cb64

+ 3 - 3
api/v1/cdn.go

@@ -44,8 +44,8 @@ type Website struct {
 	Name             string  `json:"name" form:"name"`                                   // 网站名称
 	Description      string  `json:"description" form:"description"`                     // 可选项,网站描述
 	ServerNamesJSON  []byte  `json:"serverNamesJSON,omitempty" form:"serverNamesJSON"`   // 域名列表 json:server_names
-	HttpJSON         []byte  `json:"httpJSON,omitempty" form:"httpJSON"`                 // HTTP协议设置,当type为httpProxy或者httpWeb时填写 json:http_protocol
-	HttpsJSON        []byte  `json:"httpsJSON,omitempty" form:"httpsJSON"`               // HTTPS协议设置,当type为httpProxy或者httpWeb时填写 json:https_protocol
+	HttpJSON         TypeJSON `json:"httpJSON,omitempty" form:"httpJSON"`                 // HTTP协议设置,当type为httpProxy或者httpWeb时填写 json:http_protocol
+	HttpsJSON        TypeJSON  `json:"httpsJSON,omitempty" form:"httpsJSON"`               // HTTPS协议设置,当type为httpProxy或者httpWeb时填写 json:https_protocol
 	TcpJSON          []byte  `json:"tcpJSON,omitempty" form:"tcpJSON"`                   // TCP协议设置,当type为tcpProxy时填写 json:tcp_protocol
 	TlsJSON          []byte  `json:"tlsJSON,omitempty" form:"tlsJSON"`                   // TLS协议设置,当type为tcpProxy时填写 json:tls_protocol
 	UdpJSON          []byte  `json:"udpJSON,omitempty" form:"udpJSON"`                   // UDP协议设置,当type为udpProxy时填写 json:udp_protocol
@@ -145,7 +145,7 @@ type SSLPolicy struct {
 	Http2Enabled     bool           `json:"http2Enabled" form:"http2Enabled"`         //是否支持HTTP/2
 	Http3Enabled     bool           `json:"http3Enabled" form:"http3Enabled"`         //是否支持Http3Enabled
 	MinVersion       string         `json:"minVersion" form:"minVersion"`             //最小TLS版本
-	SslCertsJSON     []SslCertsJSON `json:"sslCertsJSON" form:"sslCertsJSON"`         //SslCertsJSON
+	SslCertsJSON     []byte `json:"sslCertsJSON" form:"sslCertsJSON"`         //SslCertsJSON
 	HstsJSON         []byte         `json:"hstsJSON" form:"hstsJSON"`                 //HstsJSON
 	ClientAuthType   int32          `json:"clientAuthType" form:"clientAuthType"`     //可选项,客户端校验类型:0 无需证书,1 需要客户端证书,2 需要任一客户端证书,3 如果客户端上传了证书才校验,4 需要客户端证书而且需要校验
 	CipherSuites     []string       `json:"cipherSuites" form:"cipherSuites"`         //可选项,支持的TLS加密套件

+ 1 - 2
api/v1/wafformatter.go

@@ -21,8 +21,7 @@ type WebJson struct {
 }
 
 type SSL struct {
-	WebId       int64  `form:"WebId" json:"WebId" `
-	SSLPolicyId int    `form:"SSLPolicyId" json:"SSLPolicyId" `
+	CertId      int    `form:"certId" json:"certId" `
 	CdnUserId   int    `form:"UserId" json:"UserId" `
 	Domain      string `form:"Domain" json:"Domain" `
 	Name        string `form:"Name" json:"Name" `

+ 1 - 0
api/v1/webForwarding.go

@@ -11,6 +11,7 @@ type WebForwardingDataRequest struct {
 	Comment            string `form:"comment" json:"comment" validate:"max=50"`
 	HttpsCert          string `form:"httpsCert" json:"httpsCert"`
 	HttpsKey           string `form:"httpsKey" json:"httpsKey"`
+	SslPolicyId        int64    `form:"sslPolicyId" json:"sslPolicyId"`
 	SslCertId          int64    `form:"sslCertId" json:"sslCertId"`
 	Proxy 				bool `form:"proxy" json:"proxy" default:"false"`
 	CcConfig           CcConfigRequest `form:"ccConfig" json:"ccConfig"`

+ 1 - 0
cmd/server/wire/wire.go

@@ -82,6 +82,7 @@ var serviceSet = wire.NewSet(
 	service.NewCdnService,
 	service.NewAllowAndDenyIpService,
 	service.NewProxyService,
+	service.NewSslCertService,
 )
 
 var handlerSet = wire.NewSet(

+ 3 - 2
cmd/server/wire/wire_gen.go

@@ -73,7 +73,8 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	aoDunService := service.NewAoDunService(serviceService, viperViper)
 	proxyRepository := repository.NewProxyRepository(repositoryRepository)
 	proxyService := service.NewProxyService(serviceService, proxyRepository, cdnService)
-	webForwardingService := service.NewWebForwardingService(serviceService, requiredService, webForwardingRepository, crawlerService, parserService, wafFormatterService, aoDunService, rabbitMQ, gateWayGroupIpRepository, gatewayGroupRepository, globalLimitRepository, cdnService, proxyService)
+	sslCertService := service.NewSslCertService(serviceService, webForwardingRepository, cdnService)
+	webForwardingService := service.NewWebForwardingService(serviceService, requiredService, webForwardingRepository, crawlerService, parserService, wafFormatterService, aoDunService, rabbitMQ, gateWayGroupIpRepository, gatewayGroupRepository, globalLimitRepository, cdnService, proxyService, sslCertService)
 	webForwardingHandler := handler.NewWebForwardingHandler(handlerHandler, webForwardingService)
 	webLimitRepository := repository.NewWebLimitRepository(repositoryRepository)
 	webLimitService := service.NewWebLimitService(serviceService, webLimitRepository, requiredService, parserService, crawlerService, hostService)
@@ -111,7 +112,7 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 
 var repositorySet = wire.NewSet(repository.NewDB, repository.NewRedis, repository.NewCasbinEnforcer, repository.NewMongoClient, repository.NewMongoDB, repository.NewRabbitMQ, repository.NewRepository, repository.NewTransaction, repository.NewAdminRepository, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository, repository.NewGameShieldUserIpRepository, repository.NewWebLimitRepository, repository.NewTcpLimitRepository, repository.NewUdpLimitRepository, repository.NewGameShieldBackendRepository, repository.NewGameShieldSdkIpRepository, repository.NewHostRepository, repository.NewGlobalLimitRepository, repository.NewGatewayGroupRepository, repository.NewGateWayGroupIpRepository, repository.NewCdnRepository, repository.NewAllowAndDenyIpRepository, repository.NewProxyRepository)
 
-var serviceSet = wire.NewSet(service.NewService, service.NewAoDunService, service.NewUserService, service.NewAdminService, service.NewGameShieldService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewCrawlerService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService, service.NewUdpLimitService, service.NewGameShieldBackendService, service.NewGameShieldSdkIpService, service.NewHostService, service.NewGlobalLimitService, service.NewGatewayGroupService, service.NewWafFormatterService, service.NewGateWayGroupIpService, service.NewRequestService, service.NewCdnService, service.NewAllowAndDenyIpService, service.NewProxyService)
+var serviceSet = wire.NewSet(service.NewService, service.NewAoDunService, service.NewUserService, service.NewAdminService, service.NewGameShieldService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewCrawlerService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService, service.NewUdpLimitService, service.NewGameShieldBackendService, service.NewGameShieldSdkIpService, service.NewHostService, service.NewGlobalLimitService, service.NewGatewayGroupService, service.NewWafFormatterService, service.NewGateWayGroupIpService, service.NewRequestService, service.NewCdnService, service.NewAllowAndDenyIpService, service.NewProxyService, service.NewSslCertService)
 
 var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewAdminHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler, handler.NewGameShieldUserIpHandler, handler.NewWebLimitHandler, handler.NewTcpLimitHandler, handler.NewUdpLimitHandler, handler.NewGameShieldBackendHandler, handler.NewGameShieldSdkIpHandler, handler.NewHostHandler, handler.NewGlobalLimitHandler, handler.NewGatewayGroupHandler, handler.NewGateWayGroupIpHandler, handler.NewAllowAndDenyIpHandler)
 

+ 2 - 1
internal/model/webforwarding.go

@@ -16,7 +16,8 @@ type WebForwarding struct {
 	Comment              string `gorm:"null"`
 	HttpsCert             string `gorm:"null"`
 	HttpsKey             string `gorm:"null"`
-	SslCertId 		int `gorm:"null"`
+	SslCertId 			int `gorm:"null"`
+	SslPolicyId               int
 	Proxy 				bool `gorm:"null"`
 	Cc                   bool
 	ThresholdMethod      string

+ 3 - 3
internal/repository/webforwarding.go

@@ -31,7 +31,7 @@ type WebForwardingRepository interface {
 	GetDomainCount(ctx context.Context, hostId int, domain string) (int, error)
 	// 获取IP数量等于1的IP
 	GetIpCountByIp(ctx context.Context, ips []string) ([]v1.IpCountResult, error)
-	GetSslCertId (ctx context.Context, sslPocyID int) ([]v1.SslCertsJSON, error)
+	GetSslCertId (ctx context.Context, sslPocyID int64) ([]v1.SslCertsJSON, error)
 	// 获取CDN的web配置的id
 	GetWebConfigId(ctx context.Context, id int64) (int64, error)
 	// 获取域名
@@ -269,7 +269,7 @@ func (r *webForwardingRepository) GetIpCountByIp(ctx context.Context, ips []stri
 	return results, nil
 }
 
-func (r *webForwardingRepository) GetSslCertId (ctx context.Context, sslPolicyID int) ([]v1.SslCertsJSON, error) {
+func (r *webForwardingRepository) GetSslCertId (ctx context.Context, sslPolicyID int64) ([]v1.SslCertsJSON, error) {
 	var certsJSON string
 
 	// 2. 查询数据库,只获取 `certs` 字段的字符串内容
@@ -324,4 +324,4 @@ func (r *webForwardingRepository) GetDomainByHostIdPort(ctx context.Context, hos
 	}
 	return domains, nil
 
-}
+}

+ 18 - 2
internal/service/cdn.go

@@ -310,14 +310,30 @@ func (s *cdnService) RenewPlan(ctx context.Context, req v1.RenewalPlan) error {
 
 // 创建网站
 func (s *cdnService) CreateWebsite(ctx context.Context, req v1.Website) (int64, error) {
+	var httpJSON, httpsJSON []byte
+	var err error
+	if &req.HttpJSON != nil {
+		httpJSON, err = json.Marshal(req.HttpJSON)
+		if err != nil {
+			return 0, err
+		}
+	}
+	if &req.HttpsJSON != nil {
+		httpsJSON, err = json.Marshal(req.HttpsJSON)
+		if err != nil {
+			return 0, err
+		}
+	}
+
+
 	formData := map[string]interface{}{
 		"userId":           req.UserId,
 		"type":             req.Type,
 		"name":             req.Name,
 		"description":      req.Description,
 		"serverNamesJSON":  req.ServerNamesJSON,
-		"httpJSON":         req.HttpJSON,
-		"httpsJSON":        req.HttpsJSON,
+		"httpJSON":         httpJSON,
+		"httpsJSON":        httpsJSON,
 		"tcpJSON":          req.TcpJSON,
 		"tlsJSON":          req.TlsJSON,
 		"udpJSON":          req.UdpJSON,

+ 236 - 0
internal/service/sslcert.go

@@ -0,0 +1,236 @@
+package service
+
+import (
+	"context"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/json"
+	"fmt"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+)
+
+type SslCertService interface {
+	ParseCert(ctx context.Context, httpsCert string, httpKey string) (serverName string, commonName []string, DNSNames []string, before int64, after int64, isSelfSigned bool, err error)
+	AddSSLCert(ctx context.Context, req v1.SSL) (int64, error)
+	EditSSLCert(ctx context.Context, req v1.SSL) error
+	AddSslPolicy(ctx context.Context, CertIds []int64) (sslPolicyId int64, err error)
+	EditSslPolicy(ctx context.Context, sslPolicyId int64, CertIds []int64, action string) error
+}
+func NewSslCertService(
+    service *Service,
+   	webForwardingRep repository.WebForwardingRepository,
+	cdn CdnService,
+) SslCertService {
+	return &sslCertService{
+		Service:        service,
+		webForwardingRep: webForwardingRep,
+		cdn: cdn,
+	}
+}
+
+type sslCertService struct {
+	*Service
+	webForwardingRep repository.WebForwardingRepository
+	cdn CdnService
+}
+
+func (s *sslCertService) ParseCert(ctx context.Context, httpsCert string, httpKey string) (serverName string, commonName []string, DNSNames []string, before int64, after int64, isSelfSigned bool, err error) {
+	cert, err := tls.X509KeyPair([]byte(httpsCert), []byte(httpKey))
+	if err != nil {
+		return "", nil, nil, 0, 0, false, fmt.Errorf("无法从字符串加载密钥对: %v", err)
+	}
+
+	if len(cert.Certificate) == 0 {
+		return "", nil, nil, 0, 0, false, fmt.Errorf("提供的证书数据中没有找到证书。")
+	}
+
+	// 解析第一个证书(通常是叶子证书)
+	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+	if err != nil {
+		return "", nil, nil, 0, 0, false, fmt.Errorf("无法解析证书: %v", err)
+	}
+
+	// 1. 获取 Common Name (通用名称)
+	// Common Name 位于 Subject 字段内. [1]
+	serverName = x509Cert.Subject.CommonName
+
+	// 2. 获取 DNS Names (备用主题名称中的DNS条目)
+	// DNS Names 直接是证书结构体的一个字段. [1]
+	DNSNames = x509Cert.DNSNames
+
+	// 检查证书是否为自签名
+	// 判断条件:颁发者(Issuer)和主题(Subject)相同,并且证书的签名可以由其自身的公钥验证
+	if err := x509Cert.CheckSignatureFrom(x509Cert); err == nil {
+		isSelfSigned = true
+	}
+
+	// 将CommonName放入一个切片,以匹配[]string的类型要求
+	var commonNames []string
+	if x509Cert.Subject.CommonName != "" {
+		commonNames = []string{x509Cert.Subject.CommonName}
+	}
+
+	return serverName, commonNames, DNSNames, x509Cert.NotBefore.Unix(), x509Cert.NotAfter.Unix(), isSelfSigned, nil
+
+}
+
+func (s *sslCertService) AddSslPolicy(ctx context.Context, CertIds []int64) (sslPolicyId int64, err error) {
+	// 构造策略中引用的证书列表
+	type sslCerts struct {
+		IsOn   bool  `json:"isOn" form:"isOn"`
+		CertId int64 `json:"certId" form:"certId"`
+	}
+	var sslCertsSlice []sslCerts
+	for _, certId := range CertIds {
+		sslCertsSlice = append(sslCertsSlice, sslCerts{
+			IsOn:   true,
+			CertId: certId,
+		})
+	}
+
+	sslCertsJson, err := json.Marshal(sslCertsSlice)
+	if err != nil {
+		return 0, fmt.Errorf("序列化SSL证书引用失败: %w", err)
+	}
+
+	// 调用CDN服务创建策略
+	newSslPolicyId, err := s.cdn.AddSSLPolicy(ctx, v1.AddSSLPolicy{
+		Http2Enabled: true,
+		SslCertsJSON: sslCertsJson,
+		MinVersion:   "TLS 1.1", // 可根据安全要求调整
+	})
+	if err != nil {
+		// 如果策略创建失败,需要考虑回滚或记录错误,这里直接返回错误
+		return 0, fmt.Errorf("通过CDN添加SSL策略失败: %w", err)
+	}
+	return newSslPolicyId, nil
+}
+
+func (s *sslCertService) EditSslPolicy(ctx context.Context, sslPolicyId int64, CertIds []int64, action string) error {
+	type sslCerts struct {
+		IsOn   bool  `json:"isOn" form:"isOn"`
+		CertId int64 `json:"certId" form:"certId"`
+	}
+	oldCertIds, err := s.webForwardingRep.GetSslCertId(ctx, sslPolicyId)
+	if err != nil {
+		return fmt.Errorf("获取SSL证书失败: %w", err)
+	}
+
+	var sslCertsSlice []sslCerts
+
+	switch action {
+	case "add":
+		for _, certId := range CertIds {
+			exist := false
+			for _, oldCertId := range oldCertIds {
+				if oldCertId.CertId == certId {
+					exist = true
+					break
+				}
+			}
+			if !exist {
+				sslCertsSlice = append(sslCertsSlice, sslCerts{
+					IsOn:   true,
+					CertId: certId,
+				})
+			}
+		}
+	case "del":
+		for _, oldCertId := range oldCertIds {
+			exist := false
+			for _, certId := range CertIds {
+				if oldCertId.CertId == certId {
+					exist = true
+					break
+				}
+			}
+			if !exist {
+				sslCertsSlice = append(sslCertsSlice, sslCerts{
+					IsOn:   false,
+					CertId: oldCertId.CertId,
+				})
+			}
+		}
+
+	}
+
+
+	sslCertsJson, err := json.Marshal(sslCertsSlice)
+	if err != nil {
+		return  fmt.Errorf("序列化SSL证书引用失败: %w", err)
+	}
+
+	// 调用CDN服务创建策略
+	 err = s.cdn.EditSSLPolicy(ctx, v1.SSLPolicy{
+		SslPolicyId: sslPolicyId,
+		Http2Enabled: true,
+		SslCertsJSON: sslCertsJson,
+		MinVersion:   "TLS 1.1", // 可根据安全要求调整
+	})
+	if err != nil {
+		// 如果策略创建失败,需要考虑回滚或记录错误,这里直接返回错误
+		return fmt.Errorf("通过CDN添加SSL策略失败: %w", err)
+	}
+	return nil
+}
+
+
+func (s *sslCertService) AddSSLCert(ctx context.Context, req v1.SSL) (int64, error) {
+	// 1. 解析证书文件,提取元数据
+	serverName, commonNames, DNSNames, before, after, isSelfSigned, err := s.ParseCert(ctx, req.CertData, req.KeyData)
+	if err != nil {
+		return  0, fmt.Errorf("解析证书失败: %w", err)
+	}
+
+	// 2. 将证书添加到CDN提供商
+	// 这是获取可以在策略中引用的 `sslCertId` 的前提
+	newSslCertId, err := s.cdn.AddSSLCert(ctx, v1.SSlCert{
+		IsOn:         true,
+		UserId:       int64(req.CdnUserId),
+		Name:         req.Domain, // 使用域名作为证书名称
+		ServerName:   serverName,
+		Description:  req.Description,
+		CertData:     []byte(req.CertData),
+		KeyData:      []byte(req.KeyData),
+		TimeBeginAt:  before,
+		TimeEndAt:    after,
+		DnsNames:     DNSNames,
+		CommonNames:  commonNames,
+		IsSelfSigned: isSelfSigned,
+	})
+	if err != nil {
+		return  0, fmt.Errorf("添加SSL证书到CDN失败: %w", err)
+	}
+	return newSslCertId, nil
+}
+
+
+func (s *sslCertService) EditSSLCert(ctx context.Context, req v1.SSL) error {
+	serverName, commonNames, DNSNames, before, after, isSelfSigned, err := s.ParseCert(ctx, req.CertData, req.KeyData)
+	if err != nil {
+		return fmt.Errorf("解析证书失败: %w", err)
+	}
+
+	// 2. 将证书添加到CDN提供商
+	// 这是获取可以在策略中引用的 `sslCertId` 的前提
+	err = s.cdn.EditSSLCert(ctx, v1.SSlCert{
+		IsOn:         true,
+		UserId:       int64(req.CdnUserId),
+		Name:         req.Domain, // 使用域名作为证书名称
+		ServerName:   serverName,
+		Description:  req.Description,
+		CertData:     []byte(req.CertData),
+		KeyData:      []byte(req.KeyData),
+		TimeBeginAt:  before,
+		TimeEndAt:    after,
+		DnsNames:     DNSNames,
+		CommonNames:  commonNames,
+		IsSelfSigned: isSelfSigned,
+	})
+	if err != nil {
+		return fmt.Errorf("添加SSL证书到CDN失败: %w", err)
+	}
+	return nil
+}
+

+ 0 - 149
internal/service/wafformatter.go

@@ -2,8 +2,6 @@ package service
 
 import (
 	"context"
-	"crypto/tls"
-	"crypto/x509"
 	"encoding/json"
 	"fmt"
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
@@ -39,10 +37,6 @@ type WafFormatterService interface {
 	WashDelIps(ctx context.Context, ips []string) ([]string, error)
 	// 判断域名是否是IDN,如果是,转换为 Punycode
 	ConvertToPunycodeIfIDN(ctx context.Context, domain string) (isIDN bool, punycodeDomain string, err error)
-	// 解析证书
-	ParseCert(ctx context.Context, httpsCert string, httpKey string) (serverName string, commonName []string, DNSNames []string, before int64, after int64, isSelfSigned bool, err error)
-	AddSSLPolicy(ctx context.Context, req v1.SSL) (sslPolicyId int64, sslCertId int64, err error)
-	EditSSL(ctx context.Context, req v1.SSL) error
 	// 验证端口重复
 	VerifyPort(ctx context.Context,protocol string, port string,hostId int64,domain string) error
 }
@@ -99,7 +93,6 @@ type RequireResponse struct {
 	model.GlobalLimit `json:"globalLimit" form:"globalLimit"`
 	GatewayIps        []string `json:"ips" form:"ips"`
 	Tag               string   `json:"tag" form:"tag"`
-	SslPolicyId       int64    `json:"sslPolicyId" form:"sslPolicyId"`
 }
 
 func (s *wafFormatterService) Require(ctx context.Context, req v1.GlobalRequire) (RequireResponse, error) {
@@ -498,148 +491,6 @@ func (s *wafFormatterService) ConvertToPunycodeIfIDN(ctx context.Context, domain
 	return isIDN, punycodeDomain, nil
 }
 
-func (s *wafFormatterService) ParseCert(ctx context.Context, httpsCert string, httpKey string) (serverName string, commonName []string, DNSNames []string, before int64, after int64, isSelfSigned bool, err error) {
-	cert, err := tls.X509KeyPair([]byte(httpsCert), []byte(httpKey))
-	if err != nil {
-		return "", nil, nil, 0, 0, false, fmt.Errorf("无法从字符串加载密钥对: %v", err)
-	}
-
-	if len(cert.Certificate) == 0 {
-		return "", nil, nil, 0, 0, false, fmt.Errorf("提供的证书数据中没有找到证书。")
-	}
-
-	// 解析第一个证书(通常是叶子证书)
-	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
-	if err != nil {
-		return "", nil, nil, 0, 0, false, fmt.Errorf("无法解析证书: %v", err)
-	}
-
-	// 1. 获取 Common Name (通用名称)
-	// Common Name 位于 Subject 字段内. [1]
-	serverName = x509Cert.Subject.CommonName
-
-	// 2. 获取 DNS Names (备用主题名称中的DNS条目)
-	// DNS Names 直接是证书结构体的一个字段. [1]
-	DNSNames = x509Cert.DNSNames
-
-	// 检查证书是否为自签名
-	// 判断条件:颁发者(Issuer)和主题(Subject)相同,并且证书的签名可以由其自身的公钥验证
-	if err := x509Cert.CheckSignatureFrom(x509Cert); err == nil {
-		isSelfSigned = true
-	}
-
-	// 将CommonName放入一个切片,以匹配[]string的类型要求
-	var commonNames []string
-	if x509Cert.Subject.CommonName != "" {
-		commonNames = []string{x509Cert.Subject.CommonName}
-	}
-
-	return serverName, commonNames, DNSNames, x509Cert.NotBefore.Unix(), x509Cert.NotAfter.Unix(), isSelfSigned, nil
-
-}
-
-// HandleSSLPolicy 负责处理SSL证书的完整生命周期:解析、上传到CDN并创建或更新SSL策略。
-// 它封装了与CDN服务交互的复杂性,并返回一个可用的SSL策略ID。
-func (s *wafFormatterService) AddSSLPolicy(ctx context.Context, req v1.SSL) (sslPolicyId int64, sslCertId int64, err error) {
-	// 1. 解析证书文件,提取元数据
-	serverName, commonNames, DNSNames, before, after, isSelfSigned, err := s.ParseCert(ctx, req.CertData, req.KeyData)
-	if err != nil {
-		return 0, 0, fmt.Errorf("解析证书失败: %w", err)
-	}
-
-	// 2. 将证书添加到CDN提供商
-	// 这是获取可以在策略中引用的 `sslCertId` 的前提
-	newSslCertId, err := s.cdn.AddSSLCert(ctx, v1.SSlCert{
-		IsOn:         true,
-		UserId:       int64(req.CdnUserId),
-		Name:         req.Domain, // 使用域名作为证书名称
-		ServerName:   serverName,
-		Description:  req.Description,
-		CertData:     []byte(req.CertData),
-		KeyData:      []byte(req.KeyData),
-		TimeBeginAt:  before,
-		TimeEndAt:    after,
-		DnsNames:     DNSNames,
-		CommonNames:  commonNames,
-		IsSelfSigned: isSelfSigned,
-	})
-	if err != nil {
-		return 0, 0, fmt.Errorf("添加SSL证书到CDN失败: %w", err)
-	}
-
-	// 3. 基于获取到的证书ID,创建SSL策略
-	if newSslCertId != 0 {
-		// 构造策略中引用的证书列表
-		type sslCerts struct {
-			IsOn   bool  `json:"isOn" form:"isOn"`
-			CertId int64 `json:"certId" form:"certId"`
-		}
-		var sslCertsSlice []sslCerts
-		sslCertsSlice = append(sslCertsSlice, sslCerts{
-			IsOn:   true,
-			CertId: newSslCertId,
-		})
-		sslCertsJson, err := json.Marshal(sslCertsSlice)
-		if err != nil {
-			return 0, 0, fmt.Errorf("序列化SSL证书引用失败: %w", err)
-		}
-
-		// 调用CDN服务创建策略
-		newSslPolicyId, err := s.cdn.AddSSLPolicy(ctx, v1.AddSSLPolicy{
-			Http2Enabled: true,
-			SslCertsJSON: sslCertsJson,
-			MinVersion:   "TLS 1.1", // 可根据安全要求调整
-		})
-		if err != nil {
-			// 如果策略创建失败,需要考虑回滚或记录错误,这里直接返回错误
-			return 0, 0, fmt.Errorf("通过CDN添加SSL策略失败: %w", err)
-		}
-		return newSslPolicyId, newSslCertId, nil
-	}
-
-	return 0, 0, fmt.Errorf("未能创建有效的SSL证书ID,无法继续创建策略")
-}
-
-func (s *wafFormatterService) EditSSL(ctx context.Context, req v1.SSL) error {
-	oldData, err := s.webForwardingRep.GetWebForwarding(ctx, req.WebId)
-	if err != nil {
-		return err
-	}
-	if oldData.HttpsKey != req.KeyData || oldData.HttpsCert != req.CertData {
-		serverName, commonNames, DNSNames, before, after, isSelfSigned, err := s.ParseCert(ctx, req.CertData, req.KeyData)
-		if err != nil {
-			return fmt.Errorf("解析证书失败: %w", err)
-		}
-		sslCert, err := s.webForwardingRep.GetSslCertId(ctx, oldData.SslCertId)
-		if err != nil {
-			return fmt.Errorf("获取SSL证书失败: %w", err)
-		}
-
-		for _, v := range sslCert {
-			err = s.cdn.EditSSLCert(ctx, v1.SSlCert{
-				SslCertId:    v.CertId,
-				IsOn:         v.IsOn,
-				UserId:       int64(req.CdnUserId),
-				Name:         req.Domain, // 使用域名作为证书名称
-				ServerName:   serverName,
-				Description:  req.Description,
-				CertData:     []byte(req.CertData),
-				KeyData:      []byte(req.KeyData),
-				TimeBeginAt:  before,
-				TimeEndAt:    after,
-				DnsNames:     DNSNames,
-				CommonNames:  commonNames,
-				IsSelfSigned: isSelfSigned,
-			})
-			if err != nil {
-				return fmt.Errorf("更新SSL证书失败: %w", err)
-			}
-		}
-		return nil
-
-	}
-	return nil
-}
 
 // 验证端口重复
 func (s *wafFormatterService) VerifyPort(ctx context.Context,protocol string, port string,hostId int64,domain string) error {

+ 91 - 70
internal/service/webforwarding.go

@@ -36,6 +36,7 @@ func NewWebForwardingService(
 	globalLimitRep repository.GlobalLimitRepository,
 	cdn CdnService,
 	proxy ProxyService,
+	sslCert SslCertService,
 ) WebForwardingService {
 	return &webForwardingService{
 		Service:                 service,
@@ -51,6 +52,7 @@ func NewWebForwardingService(
 		cdn:                     cdn,
 		globalLimitRep:          globalLimitRep,
 		proxy:                   proxy,
+		sslCert:               	 sslCert,
 	}
 }
 
@@ -75,6 +77,7 @@ type webForwardingService struct {
 	cdn                     CdnService
 	globalLimitRep          repository.GlobalLimitRepository
 	proxy                   ProxyService
+	sslCert                 SslCertService
 }
 
 func (s *webForwardingService) require(ctx context.Context, req v1.GlobalRequire) (v1.GlobalRequire, error) {
@@ -160,22 +163,23 @@ func (s *webForwardingService) GetWebForwarding(ctx context.Context, req v1.GetF
 // ruleId 是从 WAF 系统获取的 ID
 func (s *webForwardingService) buildWebForwardingModel(req *v1.WebForwardingDataRequest, ruleId int, require RequireResponse) *model.WebForwarding {
 	return &model.WebForwarding{
-		HostId:    require.HostId,
-		CdnWebId:  ruleId,
-		Port:      req.Port,
-		Domain:    req.Domain,
-		IsHttps:   req.IsHttps,
-		Comment:   req.Comment,
-		HttpsCert: req.HttpsCert,
-		HttpsKey:  req.HttpsKey,
-		SslCertId: int(require.SslPolicyId),
-			Cc:        req.CcConfig.IsOn,
+		HostId:          require.HostId,
+		CdnWebId:        ruleId,
+		Port:            req.Port,
+		Domain:          req.Domain,
+		IsHttps:         req.IsHttps,
+		Comment:         req.Comment,
+		HttpsCert:       req.HttpsCert,
+		HttpsKey:        req.HttpsKey,
+		SslCertId:       int(req.SslCertId),
+		SslPolicyId: int(req.SslPolicyId),
+		Cc:              req.CcConfig.IsOn,
 		ThresholdMethod: req.CcConfig.ThresholdMethod,
 		Level:           req.CcConfig.Level,
 		Limit5s:         req.CcConfig.Limit5s,
 		Limit60s:        req.CcConfig.Limit60s,
 		Limit300s:       req.CcConfig.Limit300s,
-		Proxy:     req.Proxy,
+		Proxy:           req.Proxy,
 	}
 }
 
@@ -208,11 +212,10 @@ func (s *webForwardingService) prepareWafData(ctx context.Context, req *v1.WebFo
 	}
 
 	// 2. 调用辅助函数,构建核心的代理配置 (将复杂逻辑封装起来)
-	byteData, sslPolicyId, err := s.buildProxyJSONConfig(ctx, req, require)
+	byteData,  err := s.buildProxyConfig(ctx, req, require)
 	if err != nil {
 		return RequireResponse{}, v1.Website{}, err // 错误信息在辅助函数中已经包装好了
 	}
-	require.SslPolicyId = sslPolicyId
 	type serverNames struct {
 		ServerNames string `json:"name" form:"name"`
 		Type        string `json:"type" form:"type"`
@@ -242,15 +245,14 @@ func (s *webForwardingService) prepareWafData(ctx context.Context, req *v1.WebFo
 		NodeClusterId:   defaultNodeClusterId,
 	}
 
-	var noSslByteData, _ = json.Marshal(v1.TypeJSON{IsOn: false})
 
 	// 4. 根据协议类型,填充 HttpJSON 和 HttpsJSON 字段
 	if req.WebForwardingData.IsHttps == isHttps {
-		formData.HttpJSON = noSslByteData
+		formData.HttpJSON = v1.TypeJSON{IsOn: false}
 		formData.HttpsJSON = byteData
 	} else {
 		formData.HttpJSON = byteData
-		formData.HttpsJSON = noSslByteData
+		formData.HttpsJSON = v1.TypeJSON{IsOn: false}
 	}
 
 	return require, formData, nil
@@ -260,46 +262,25 @@ func (s *webForwardingService) prepareWafData(ctx context.Context, req *v1.WebFo
 // 辅助函数:buildProxyJSONConfig
 // 职责:专门负责处理 HTTP/HTTPS 的差异,并生成对应的 JSON 配置。
 // =================================================================
-func (s *webForwardingService) buildProxyJSONConfig(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) ([]byte, int64, error) {
+func (s *webForwardingService) buildProxyConfig(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) (v1.TypeJSON, error) {
 	var (
 		jsonData v1.TypeJSON
 		apiType  string
-		err      error
+
 	)
 
-	var sslPolicyId int64
+
 	jsonData.IsOn = true
 	apiType = protocolHttps
 	// 判断协议类型,并处理 HTTPS 的特殊逻辑(证书)
 	if req.WebForwardingData.IsHttps == isHttps {
 		// 处理证书信息
-		if req.WebForwardingData.SslCertId == 0 {
-			sslPolicyId, _, err = s.wafformatter.AddSSLPolicy(ctx, v1.SSL{
-				CdnUserId:   require.CdnUid,
-				Domain:      req.WebForwardingData.Domain,
-				Name:        req.WebForwardingData.Domain,
-				Description: req.WebForwardingData.Comment,
-				CertData:    req.WebForwardingData.HttpsCert,
-				KeyData:     req.WebForwardingData.HttpsKey,
-			})
+		if req.WebForwardingData.SslPolicyId == 0 {
+			sslPolicyId, err := s.sslCert.AddSslPolicy(ctx, nil)
 			if err != nil {
-				return nil, 0, fmt.Errorf("处理证书失败: %w", err)
+				return v1.TypeJSON{}, err
 			}
 			jsonData.SslPolicyRef.SslPolicyId = sslPolicyId
-		} else {
-			err = s.wafformatter.EditSSL(ctx, v1.SSL{
-				WebId:       int64(req.WebForwardingData.Id),
-				SSLPolicyId: int(req.WebForwardingData.SslCertId),
-				CdnUserId:   require.CdnUid,
-				Name:        req.WebForwardingData.Domain,
-				Description: req.WebForwardingData.Comment,
-				CertData:    req.WebForwardingData.HttpsCert,
-				KeyData:     req.WebForwardingData.HttpsKey,
-			})
-			if err != nil {
-				return nil, 0, fmt.Errorf("处理证书失败: %w", err)
-			}
-			jsonData.SslPolicyRef.SslPolicyId = req.WebForwardingData.SslCertId
 		}
 		jsonData.SslPolicyRef.IsOn = true
 	} else {
@@ -319,13 +300,8 @@ func (s *webForwardingService) buildProxyJSONConfig(ctx context.Context, req *v1
 		})
 	}
 
-	// 序列化为 JSON
-	byteData, err := json.Marshal(jsonData)
-	if err != nil {
-		return nil, 0, fmt.Errorf("序列化WAF配置失败: %w", err)
-	}
 
-	return byteData, sslPolicyId, nil
+	return jsonData, nil
 }
 
 // 查找两个列表的差异
@@ -373,6 +349,29 @@ func (s *webForwardingService) AddWebForwarding(ctx context.Context, req *v1.Web
 		return err
 	}
 
+	// 添加证书
+	if req.WebForwardingData.IsHttps == isHttps {
+		sslCertId, err := s.sslCert.AddSSLCert(ctx, v1.SSL{
+			Name:         req.WebForwardingData.Domain,
+			Domain:       req.WebForwardingData.Domain,
+			CertData:     req.WebForwardingData.HttpsCert,
+			KeyData:      req.WebForwardingData.HttpsKey,
+			CdnUserId:    require.CdnUid,
+			Description:  req.WebForwardingData.Comment,
+		})
+		if err != nil {
+			return err
+		}
+		req.WebForwardingData.SslCertId = sslCertId
+		req.WebForwardingData.SslPolicyId = formData.HttpsJSON.SslPolicyRef.SslPolicyId
+		err = s.sslCert.EditSslPolicy(ctx, formData.HttpsJSON.SslPolicyRef.SslPolicyId, []int64{sslCertId}, "add")
+		if err != nil {
+			return err
+		}
+	}
+
+
+	// 添加网站
 	webId, err := s.cdn.CreateWebsite(ctx, formData)
 	if err != nil {
 		return err
@@ -520,21 +519,51 @@ func (s *webForwardingService) EditWebForwarding(ctx context.Context, req *v1.We
 
 	//修改网站端口
 	if oldData.Port != req.WebForwardingData.Port || oldData.IsHttps != req.WebForwardingData.IsHttps || oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
-		var typeJson []byte
-		var closeJson []byte
 		var apiType string
 		var closeType string
+
+		// 修改证书
+		if oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
+			err = s.sslCert.EditSSLCert(ctx, v1.SSL{
+				Name:        req.WebForwardingData.Domain,
+				CertId:      oldData.SslCertId,
+				CertData:    req.WebForwardingData.HttpsCert,
+				KeyData:     req.WebForwardingData.HttpsKey,
+				CdnUserId:   require.CdnUid,
+				Domain:      req.WebForwardingData.Domain,
+				Description: req.WebForwardingData.Comment,
+			})
+			if err != nil {
+				return err
+			}
+		}
+
+		// 切换协议
+		var typeConfig v1.TypeJSON
+		var closeConfig v1.TypeJSON
 		if req.WebForwardingData.IsHttps == isHttps {
-			typeJson = formData.HttpsJSON
-			closeJson = formData.HttpJSON
+			typeConfig = formData.HttpsJSON
+			closeConfig = formData.HttpJSON
 			apiType = protocolHttps
 			closeType = protocolHttp
 		} else {
-			typeJson = formData.HttpJSON
-			closeJson = formData.HttpsJSON
+			typeConfig = formData.HttpJSON
+			closeConfig = formData.HttpsJSON
 			apiType = protocolHttp
 			closeType = protocolHttps
 		}
+
+
+
+		typeJson,err := json.Marshal(typeConfig)
+		if err != nil {
+			return err
+		}
+		closeJson,err := json.Marshal(closeConfig)
+		if err != nil {
+			return err
+		}
+		// 切换协议
 		err = s.cdn.EditServerType(ctx, v1.EditWebsite{
 			Id:       int64(oldData.CdnWebId),
 			TypeJSON: typeJson,
@@ -796,25 +825,17 @@ func (s *webForwardingService) DeleteWebForwarding(ctx context.Context, Ids []in
 		}
 
 		// 删除ssl
-		data, err := s.webForwardingRepository.GetWebForwarding(ctx, int64(Id))
+		err = s.cdn.DelSSLCert(ctx, int64(oldData.SslCertId))
 		if err != nil {
 			return err
 		}
-		if data.SslCertId != 0 {
-			sslPolicyData, err := s.webForwardingRepository.GetSslCertId(ctx, data.SslCertId)
-			if err != nil {
-				return err
-			}
-			if sslPolicyData != nil {
-				for _, v := range sslPolicyData {
-					err := s.cdn.DelSSLCert(ctx, v.CertId)
-					if err != nil {
-						return err
-					}
-				}
-			}
+		err = s.sslCert.EditSslPolicy(ctx, int64(oldData.SslPolicyId), []int64{int64(oldData.SslCertId)}, "del")
+		if err != nil {
+			return err
 		}
 
+
+
 		if err = s.webForwardingRepository.DeleteWebForwarding(ctx, int64(Id)); err != nil {
 			return err
 		}
@@ -1048,4 +1069,4 @@ func (s *webForwardingService) EditCcConfig(ctx context.Context,webId int64, req
 		return err
 	}
 	return nil
-}
+}