package logic import ( "context" "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "hash" "io" "strings" "time" "lone-services/pkg/utils" chore "lone-services/rpc/chore/pb" "lone-services/services/chore/internal/svc" "github.com/alibabacloud-go/tea/tea" "github.com/zeromicro/go-zero/core/logx" ) type OssSignatureLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger } type MiniOssSignature struct { Policy string `json:"policy"` SecurityToken string `json:"security_token"` XOssSignatureVersion string `json:"x_oss_signature_version"` XOssCredential string `json:"x_oss_credential"` XOssDate string `json:"x_oss_date"` Signature string `json:"signature"` Host string `json:"host"` Dir string `json:"dir"` Bucket string `json:"bucket"` CdnHost string `json:"cdn_host"` Expire int64 `json:"expire"` } func NewOssSignatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OssSignatureLogic { return &OssSignatureLogic{ ctx: ctx, svcCtx: svcCtx, Logger: logx.WithContext(ctx), } } func (l *OssSignatureLogic) OssSignature(in *chore.OssSignatureReq) (*chore.Response, error) { accessKeyId := utils.GetConfigString("oss.accessKeyId") accessKeySecret := utils.GetConfigString("oss.accessKeySecret") roleArn := utils.GetConfigString("oss.roleArn") roleSessionName := utils.GetConfigString("oss.roleSessionName") region := utils.GetConfigString("oss.region") bucket := utils.GetConfigString("oss.bucketName") dir := utils.GetConfigString("oss.dir") endpoint := utils.GetConfigString("oss.endpoint") cdnHost := utils.GetConfigString("oss.host") expireSec := int64(utils.GetConfigInt("oss.expireSeconds")) signRegion := strings.TrimPrefix(region, "oss-") stsEndpoint := "sts." + signRegion + ".aliyuncs.com" client, err := CreateClient(tea.String(accessKeyId), tea.String(accessKeySecret), tea.String(stsEndpoint)) if err != nil { l.Errorf("create STS client: %v", err) return failResponse(utils.Fail), nil } resp, err := AssumeRole(client, roleArn, roleSessionName, expireSec) if err != nil { l.Errorf("AssumeRole: %v", err) return failResponse(utils.Fail), nil } if resp == nil || resp.Body == nil || resp.Body.Credentials == nil { l.Errorf("AssumeRole empty credentials") return failResponse(utils.Fail), nil } cred := resp.Body.Credentials stsAccessKeyId := tea.StringValue(cred.AccessKeyId) stsAccessKeySecret := tea.StringValue(cred.AccessKeySecret) securityToken := tea.StringValue(cred.SecurityToken) utcNow := time.Now().UTC() date := utcNow.Format("20060102") xOssDate := utcNow.Format("20060102T150405Z") expiration := utcNow.Add(time.Duration(expireSec) * time.Second) credential := fmt.Sprintf("%s/%s/%s/oss/aliyun_v4_request", stsAccessKeyId, date, signRegion) policyMap := map[string]any{ "expiration": expiration.Format("2006-01-02T15:04:05.000Z"), "conditions": []any{ map[string]string{"bucket": bucket}, map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"}, map[string]string{"x-oss-credential": credential}, map[string]string{"x-oss-date": xOssDate}, map[string]string{"x-oss-security-token": securityToken}, []any{"starts-with", "$key", dir}, }, } policyJSON, err := json.Marshal(policyMap) if err != nil { l.Errorf("marshal policy: %v", err) return failResponse(utils.Fail), nil } stringToSign := base64.StdEncoding.EncodeToString(policyJSON) signature := ossV4Sign(stsAccessKeySecret, date, signRegion, stringToSign) out := MiniOssSignature{ Policy: stringToSign, SecurityToken: securityToken, XOssSignatureVersion: "OSS4-HMAC-SHA256", XOssCredential: credential, XOssDate: xOssDate, Signature: signature, Host: strings.TrimRight(endpoint, "/"), Dir: dir, Bucket: bucket, CdnHost: strings.TrimRight(cdnHost, "/"), Expire: expiration.Unix(), } return okResponse(out), nil } func ossV4Sign(accessKeySecret, date, region, stringToSign string) string { hmacHash := func() hash.Hash { return sha256.New() } h1 := hmac.New(hmacHash, []byte("aliyun_v4"+accessKeySecret)) _, _ = io.WriteString(h1, date) h1Key := h1.Sum(nil) h2 := hmac.New(hmacHash, h1Key) _, _ = io.WriteString(h2, region) h2Key := h2.Sum(nil) h3 := hmac.New(hmacHash, h2Key) _, _ = io.WriteString(h3, "oss") h3Key := h3.Sum(nil) h4 := hmac.New(hmacHash, h3Key) _, _ = io.WriteString(h4, "aliyun_v4_request") h4Key := h4.Sum(nil) h := hmac.New(hmacHash, h4Key) _, _ = io.WriteString(h, stringToSign) return hex.EncodeToString(h.Sum(nil)) }