feat(upload): 支持阿里云 OSS 直传凭证 + 营销图管理后台静态路由
- 新增 internal/common/oss: OSS PostPolicy/UploadHost,CDN 为 aliyuncs 时返回 OSS 凭证 - upload_handler: QINIU_CDN_DOMAIN 为 OSS 域名时返回 oss_access_key_id/policy/signature,upload_url 为 bucket 域名 - routes: 增加 /admin/marketing 静态页面路由 Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
package oss
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IsOSSDomain 判断 CDN 域名是否为阿里云 OSS(据此决定返回 OSS 还是七牛凭证)
|
||||
func IsOSSDomain(cdnDomain string) bool {
|
||||
return strings.Contains(strings.ToLower(cdnDomain), "aliyuncs.com")
|
||||
}
|
||||
|
||||
// ParseOSSEndpoint 从 CDN 域名解析 OSS endpoint,如 oss-cn-beijing.aliyuncs.com -> oss-cn-beijing
|
||||
func ParseOSSEndpoint(cdnDomain string) string {
|
||||
// oss-cn-beijing.aliyuncs.com -> oss-cn-beijing
|
||||
re := regexp.MustCompile(`^([a-z0-9-]+)\.aliyuncs\.com$`)
|
||||
m := re.FindStringSubmatch(strings.TrimSpace(strings.ToLower(cdnDomain)))
|
||||
if len(m) >= 2 {
|
||||
return m[1]
|
||||
}
|
||||
return "oss-cn-beijing"
|
||||
}
|
||||
|
||||
// PostPolicy 生成 OSS PostObject 所需的 policy 和 signature
|
||||
// bucket: 桶名, endpoint: 如 oss-cn-beijing, key: 对象 key, accessKeySecret: 密钥, expireSeconds: 有效期
|
||||
func PostPolicy(bucket, endpoint, key, accessKeySecret string, expireSeconds int) (policyBase64, signature string, err error) {
|
||||
if expireSeconds <= 0 {
|
||||
expireSeconds = 300
|
||||
}
|
||||
expiration := time.Now().Add(time.Duration(expireSeconds) * time.Second).UTC()
|
||||
expirationStr := expiration.Format("2006-01-02T15:04:05.000Z")
|
||||
|
||||
keyPrefix := key
|
||||
if idx := strings.LastIndex(key, "/"); idx >= 0 {
|
||||
keyPrefix = key[:idx+1]
|
||||
}
|
||||
if keyPrefix == "" {
|
||||
keyPrefix = "uploads/"
|
||||
}
|
||||
|
||||
policy := map[string]interface{}{
|
||||
"expiration": expirationStr,
|
||||
"conditions": []interface{}{
|
||||
[]interface{}{"content-length-range", 0, 10 * 1024 * 1024}, // 10MB
|
||||
[]interface{}{"starts-with", "$key", keyPrefix},
|
||||
},
|
||||
}
|
||||
policyJSON, err := json.Marshal(policy)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
policyBase64 = base64.StdEncoding.EncodeToString(policyJSON)
|
||||
|
||||
mac := hmac.New(sha1.New, []byte(accessKeySecret))
|
||||
mac.Write([]byte(policyBase64))
|
||||
signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
||||
return policyBase64, signature, nil
|
||||
}
|
||||
|
||||
// UploadHost 返回 OSS PostObject 的完整上传地址
|
||||
func UploadHost(bucket, endpoint string) string {
|
||||
return fmt.Sprintf("https://%s.%s.aliyuncs.com", bucket, endpoint)
|
||||
}
|
||||
Reference in New Issue
Block a user