@@ -0,0 +1,142 @@
package logic
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
"io"
"time"
"lone-services/pkg/utils"
chore "lone-services/rpc/chore/pb"
"lone-services/services/chore/internal/svc"
"github.com/aliyun/credentials-go/credentials"
"github.com/zeromicro/go-zero/core/logx"
)
type PolicyLogic struct {
ctx context . Context
svcCtx * svc . ServiceContext
logx . Logger
}
type PolicyToken struct {
Policy string ` json:"policy" `
SecurityToken string ` json:"security_token" `
SignatureVersion string ` json:"x_oss_signature_version" `
Credential string ` json:"x_oss_credential" `
Date string ` json:"x_oss_date" `
Signature string ` json:"signature" `
Host string ` json:"host" `
Dir string ` json:"dir" `
}
func NewPolicyLogic ( ctx context . Context , svcCtx * svc . ServiceContext ) * PolicyLogic {
return & PolicyLogic {
ctx : ctx ,
svcCtx : svcCtx ,
Logger : logx . WithContext ( ctx ) ,
}
}
var (
region string
bucketName string
product = "oss"
)
func ( l * PolicyLogic ) Policy ( in * chore . PolicyReq ) ( * chore . Response , error ) {
// 设置bucket所处地域
region = utils . GetConfigString ( "oss.region" )
// 替换为您的bucket名称
bucketName = utils . GetConfigString ( "oss.bucketName" )
// 设置 OSS 上传地址
// lone-images.oss-accelerate.aliyuncs.com
host := fmt . Sprintf ( "https://%s.oss-%s.aliyuncs.com" , bucketName , region )
// 设置上传目录
dir := utils . GetConfigString ( "oss.dir" )
config := new ( credentials . Config ) .
SetType ( "ram_role_arn" ) .
SetAccessKeyId ( utils . GetConfigString ( "oss.accessKeyId" ) ) .
SetAccessKeySecret ( utils . GetConfigString ( "oss.accessKeySecret" ) ) .
SetRoleArn ( utils . GetConfigString ( "oss.roleArn" ) ) .
SetRoleSessionName ( utils . GetConfigString ( "oss.roleSessionName" ) ) .
SetPolicy ( "" ) .
SetRoleSessionExpiration ( 3600 )
// 根据配置创建凭证提供器
provider , err := credentials . NewCredential ( config )
if err != nil {
l . Errorf ( "NewCredential fail, err:%v" , err )
}
// 从凭证提供器获取凭证
cred , err := provider . GetCredential ( )
if err != nil {
l . Errorf ( "GetCredential fail, err:%v" , err )
}
// 构建policy
utcTime := time . Now ( ) . UTC ( )
date := utcTime . Format ( "20060102" )
expiration := utcTime . Add ( 1 * time . Hour )
policyMap := map [ string ] any {
"expiration" : expiration . Format ( "2006-01-02T15:04:05.000Z" ) ,
"conditions" : [ ] any {
map [ string ] string { "bucket" : bucketName } ,
map [ string ] string { "x-oss-signature-version" : "OSS4-HMAC-SHA256" } ,
map [ string ] string { "x-oss-credential" : fmt . Sprintf ( "%v/%v/%v/%v/aliyun_v4_request" , * cred . AccessKeyId , date , region , product ) } ,
map [ string ] string { "x-oss-date" : utcTime . Format ( "20060102T150405Z" ) } ,
map [ string ] string { "x-oss-security-token" : * cred . SecurityToken } ,
} ,
}
// 将policy转换为 JSON 格式
policy , err := json . Marshal ( policyMap )
if err != nil {
l . Errorf ( "json.Marshal fail, err:%v" , err )
}
// 构造待签名字符串(StringToSign)
stringToSign := base64 . StdEncoding . EncodeToString ( [ ] byte ( policy ) )
hmacHash := func ( ) hash . Hash { return sha256 . New ( ) }
// 构建signing key
signingKey := "aliyun_v4" + * cred . AccessKeySecret
h1 := hmac . New ( hmacHash , [ ] byte ( signingKey ) )
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 , product )
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 )
signature := hex . EncodeToString ( h . Sum ( nil ) )
// 构建返回给前端的表单
policyToken := PolicyToken {
Policy : stringToSign ,
SecurityToken : * cred . SecurityToken ,
SignatureVersion : "OSS4-HMAC-SHA256" ,
Credential : fmt . Sprintf ( "%v/%v/%v/%v/aliyun_v4_request" , * cred . AccessKeyId , date , region , product ) ,
Date : utcTime . UTC ( ) . Format ( "20060102T150405Z" ) ,
Signature : signature ,
Host : host , // 返回 OSS 上传地址
Dir : dir , // 返回上传目录
}
response , err := json . Marshal ( policyToken )
if err != nil {
fmt . Println ( "json err:" , err )
}
return & chore . Response {
Code : 0 ,
Data : string ( response ) ,
} , nil
}