package v1 import ( "context" "encoding/json" "errors" "net/url" "regexp" "strings" "gitea.drugeyes.vip/pharnexbase/utils/pkg/set" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/transport" ) type Signer struct { client *oss.Client bucketsWl []string expiredInSec int64 // 默认 7 天有效期 } func NewSigner(client *oss.Client) *Signer { return &Signer{ client: client, expiredInSec: 604800, } } type UrlInfo struct { Bucket string Endpoint string Object string FileName string } func (s *Signer) SetBucketsWhiteList(bucketsWl []string) *Signer { s.bucketsWl = bucketsWl return s } func (s *Signer) SetExpiredInSec(expiredInSec int64) *Signer { s.expiredInSec = expiredInSec return s } func (s *Signer) SignUrl() middleware.Middleware { return func(handler middleware.Handler) middleware.Handler { return func(ctx context.Context, req interface{}) (reply interface{}, err error) { reply, err = handler(ctx, req) if err != nil { return } if _, ok := transport.FromServerContext(ctx); ok { // 后置匹配 oss 地址,签名 url,替换输出 var marshal []byte marshal, err = json.Marshal(reply) if err != nil { return } jsonStr := string(marshal) r := regexp.MustCompile("\"(https?://[-.a-z0-9]+\\.aliyuncs\\.com/[^\"\\\\]+)\\\\*\"") res := r.FindAllStringSubmatch(jsonStr, -1) for _, mu := range res { urlInfo, ue := GetUrlInfo(mu[1]) // url错误则不处理,用户中心不处理 if ue == nil && !set.NewSetWithItems(s.bucketsWl...).Has(urlInfo.Bucket){ var bucket *oss.Bucket bucket, err = s.client.Bucket(urlInfo.Bucket) if err != nil { return } // 生成用于下载的签名URL,并指定签名URL的有效时间。 var surl string surl, err = bucket.SignURL(urlInfo.Object, oss.HTTPGet, s.expiredInSec) if err != nil { return } // 使用签名url替换原始url jsonStr = strings.Replace(jsonStr, mu[1], surl, -1) } } // 覆盖原始输出 err = json.Unmarshal([]byte(jsonStr), reply) if err != nil { return } } return } } } func GetUrlInfo(ossUrl string) (*UrlInfo, error) { parse, err := url.Parse(ossUrl) if err != nil { return nil, err } hostInfo := strings.SplitN(parse.Host, ".", 2) if len(hostInfo) != 2 { return nil, errors.New("oss url error") } object := strings.TrimLeft(parse.Path, "/") if object == "" { return nil, errors.New("oss url error") } objectInfo := strings.Split(object, "/") if len(object) == 0 { return nil, errors.New("oss url error") } fileName := objectInfo[len(objectInfo)-1] return &UrlInfo{ Bucket: hostInfo[0], Endpoint: hostInfo[1], Object: object, FileName: fileName, }, err }