feat:修复合并问题
This commit is contained in:
parent
b9527bee70
commit
6ff8743c72
@ -6,7 +6,7 @@ SERVER_PORT=8080
|
||||
|
||||
# ==================== JWT Configuration ====================
|
||||
# JWT密钥 - 生产环境请修改为安全的随机字符串
|
||||
JWT_SECRET=topfans-secret-key-please-change-in-production
|
||||
JWT_SECRET=
|
||||
|
||||
# ==================== Dubbo Service URLs ====================
|
||||
# 各微服务的Dubbo连接地址(直连模式)
|
||||
|
||||
@ -1408,23 +1408,15 @@ func (ctrl *AssetController) buildOSSPrefix(uploadType string, userID, starID in
|
||||
return fmt.Sprintf("%s%d/%d/", baseDir, userID, starID)
|
||||
}
|
||||
|
||||
// generatePresignedURL 使用STS临时凭证生成预签名URL
|
||||
// generatePresignedURL 生成预签名URL(优先 STS,失败降级到永久 AK/SK 直连)
|
||||
func (ctrl *AssetController) generatePresignedURL(
|
||||
ossConfig config.OSSConfig,
|
||||
filePath string,
|
||||
expiresInSeconds int64,
|
||||
) (string, error) {
|
||||
// 1. 获取STS临时凭证
|
||||
// 注意:STS 的 DurationSeconds 最小 15 分钟(900秒),最大 1 小时(3600秒)
|
||||
// 但预签名 URL 的过期时间可以更长,由 OSS SDK 的 SignURL 方法控制
|
||||
// 所以我们需要限制 STS token 的过期时间,但预签名 URL 可以使用更长的过期时间
|
||||
stsExpiration := expiresInSeconds
|
||||
if stsExpiration > 3600 {
|
||||
stsExpiration = 3600 // STS 最大支持 1 小时
|
||||
}
|
||||
if stsExpiration < 900 {
|
||||
stsExpiration = 900 // STS 最小支持 15 分钟
|
||||
}
|
||||
// 尝试 STS AssumeRole,失败则降级到永久 AccessKey 直连
|
||||
var accessKeyID, accessKeySecret, securityToken string
|
||||
useSTS := false
|
||||
|
||||
credConfig := new(credentials.Config).
|
||||
SetType("ram_role_arn").
|
||||
@ -1433,34 +1425,47 @@ func (ctrl *AssetController) generatePresignedURL(
|
||||
SetRoleArn(ossConfig.RoleArn).
|
||||
SetRoleSessionName("topfans-download-session").
|
||||
SetPolicy("").
|
||||
SetRoleSessionExpiration(int(stsExpiration))
|
||||
SetRoleSessionExpiration(3600)
|
||||
|
||||
provider, err := credentials.NewCredential(credConfig)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("创建凭证提供器失败: %w", err)
|
||||
if provider, err := credentials.NewCredential(credConfig); err == nil {
|
||||
if cred, err := provider.GetCredential(); err == nil {
|
||||
accessKeyID = *cred.AccessKeyId
|
||||
accessKeySecret = *cred.AccessKeySecret
|
||||
securityToken = *cred.SecurityToken
|
||||
useSTS = true
|
||||
} else {
|
||||
logger.Logger.Warn("STS AssumeRole failed for presigned URL, falling back to direct AK/SK", zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
logger.Logger.Warn("STS credential provider failed for presigned URL, falling back to direct AK/SK", zap.Error(err))
|
||||
}
|
||||
|
||||
cred, err := provider.GetCredential()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取临时凭证失败: %w", err)
|
||||
if !useSTS {
|
||||
accessKeyID = ossConfig.AccessKeyID
|
||||
accessKeySecret = ossConfig.AccessKeySecret
|
||||
}
|
||||
|
||||
// 2. 创建OSS客户端(使用临时凭证)
|
||||
// 创建OSS客户端
|
||||
endpoint := fmt.Sprintf("https://oss-%s.aliyuncs.com", ossConfig.Region)
|
||||
|
||||
client, err := oss.New(endpoint, *cred.AccessKeyId, *cred.AccessKeySecret,
|
||||
oss.SecurityToken(*cred.SecurityToken))
|
||||
var client *oss.Client
|
||||
var err error
|
||||
if useSTS && securityToken != "" {
|
||||
client, err = oss.New(endpoint, accessKeyID, accessKeySecret, oss.SecurityToken(securityToken))
|
||||
} else {
|
||||
client, err = oss.New(endpoint, accessKeyID, accessKeySecret)
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("创建OSS客户端失败: %w", err)
|
||||
}
|
||||
|
||||
// 3. 获取Bucket
|
||||
// 获取Bucket
|
||||
bucket, err := client.Bucket(ossConfig.BucketName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取Bucket失败: %w", err)
|
||||
}
|
||||
|
||||
// 4. 生成预签名URL
|
||||
// 生成预签名URL
|
||||
signedURL, err := bucket.SignURL(filePath, oss.HTTPGet, expiresInSeconds)
|
||||
if err != nil {
|
||||
logger.Logger.Error("OSS SignURL failed",
|
||||
@ -1471,7 +1476,7 @@ func (ctrl *AssetController) generatePresignedURL(
|
||||
return "", fmt.Errorf("生成预签名URL失败: %w", err)
|
||||
}
|
||||
|
||||
// 5. 修复 path 的 URL 编码:OSS SDK 的 buildURL 用 QueryEscape 把 / 编成 %2F,
|
||||
// 修复 path 的 URL 编码:OSS SDK 的 buildURL 用 QueryEscape 把 / 编成 %2F,
|
||||
// 导致 OSS 按字面 key "asset%2F18%2F88%2Fxxx" 查找失败(403)。只把 path 段(? 之前)的 %2F 改回 /。
|
||||
if idx := strings.Index(signedURL, "?"); idx >= 0 {
|
||||
signedURL = strings.ReplaceAll(signedURL[:idx], "%2F", "/") + signedURL[idx:]
|
||||
@ -1479,9 +1484,9 @@ func (ctrl *AssetController) generatePresignedURL(
|
||||
signedURL = strings.ReplaceAll(signedURL, "%2F", "/")
|
||||
}
|
||||
|
||||
// 6. 若 SDK 未把 STS 的 security-token 加入 URL,则手动追加(使用 STS 临时凭证时,预签名 URL 必须带此参数,否则 403)
|
||||
if !strings.Contains(signedURL, "security-token") && cred.SecurityToken != nil && *cred.SecurityToken != "" {
|
||||
signedURL = signedURL + "&security-token=" + url.QueryEscape(*cred.SecurityToken)
|
||||
// 若 SDK 未把 STS 的 security-token 加入 URL,则手动追加(使用 STS 临时凭证时,预签名 URL 必须带此参数,否则 403)
|
||||
if useSTS && securityToken != "" && !strings.Contains(signedURL, "security-token") {
|
||||
signedURL = signedURL + "&security-token=" + url.QueryEscape(securityToken)
|
||||
}
|
||||
|
||||
// 检查生成的预签名 URL 是否包含 security-token 参数
|
||||
@ -1493,8 +1498,8 @@ func (ctrl *AssetController) generatePresignedURL(
|
||||
}
|
||||
|
||||
tokenPreview := ""
|
||||
if cred.SecurityToken != nil && *cred.SecurityToken != "" {
|
||||
token := *cred.SecurityToken
|
||||
if securityToken != "" {
|
||||
token := securityToken
|
||||
if len(token) > 50 {
|
||||
tokenPreview = token[:50] + "..."
|
||||
} else {
|
||||
|
||||
@ -967,7 +967,7 @@ func syncAssetsIDSequence(tx *gorm.DB) error {
|
||||
return tx.Exec(`
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('assets', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM assets), 0)
|
||||
GREATEST(COALESCE((SELECT MAX(id) FROM assets), 1), 1)
|
||||
)
|
||||
`).Error
|
||||
}
|
||||
|
||||
@ -2,9 +2,8 @@
|
||||
// 自动检测后端环境:探测开发服务器是否可用,能连通则用开发地址,否则用生产地址
|
||||
|
||||
// 团队开发机(Gateway + 团队数据库;注册/登录/余额/铸造)
|
||||
const DEV_BASE = 'http://192.168.110.60:8080'
|
||||
// 本机 Gateway(所有接口走本地)
|
||||
// const DEV_BASE = 'http://localhost:8081'
|
||||
// const DEV_BASE = 'http://192.168.110.60:8080'
|
||||
const DEV_BASE = 'http://localhost:8081'
|
||||
const SEGMENT_BASE = 'http://localhost:8081'
|
||||
const LASER_BASE = 'http://localhost:8081' // 镭射 AI 生成 + compositor 走本地 Gateway
|
||||
const PROD_BASE = 'http://101.132.250.62:8080' // 生产环境
|
||||
|
||||
Loading…
Reference in New Issue
Block a user