From 97ee6fd5f2654ea94485e490c2cc6d9e5d6ed115 Mon Sep 17 00:00:00 2001 From: tian <“184391138@qq.com”> Date: Sun, 10 Mar 2024 18:40:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20:zany=5Fface:=20cdn=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/api/v1/system/sys_captcha.go | 6 +- server/config.yaml | 15 +++- server/config/cdn.go | 7 ++ server/config/config.go | 1 + server/initialize/gorm.go | 6 +- server/model/goods/goods_show.go | 6 +- server/model/system/sys_user.go | 17 ---- server/plugin/upyun/token.go | 129 +++++++++++++--------------- 8 files changed, 88 insertions(+), 99 deletions(-) create mode 100644 server/config/cdn.go diff --git a/server/api/v1/system/sys_captcha.go b/server/api/v1/system/sys_captcha.go index 89df951..f209dd5 100644 --- a/server/api/v1/system/sys_captcha.go +++ b/server/api/v1/system/sys_captcha.go @@ -62,7 +62,7 @@ func (b *BaseApi) Captcha(c *gin.Context) { type GetCDNTokenQuery struct { Method string `form:"method"` - SaveKey string `form:"save_key"` + SaveKey string `form:"saveKey"` } type GetCDNTokenData struct { @@ -95,7 +95,7 @@ func (b *BaseApi) GetCDNToken(c *gin.Context) { return } - token, err = upyun.GetUpYunFormAPIToken(q.Method, q.SaveKey) + token, err = upyun.GetUpyunToken(q.Method, q.SaveKey) if err != nil { global.GVA_LOG.Error("获取失败!", zap.Error(err)) response.FailWithMessage("获取失败", c) @@ -106,7 +106,7 @@ func (b *BaseApi) GetCDNToken(c *gin.Context) { data.Method = token.Method data.Policy = token.Policy data.Expiration = token.XUpYunExpire - response.OkWithData(gin.H{"data": data}, c) + response.OkWithData(data, c) } } diff --git a/server/config.yaml b/server/config.yaml index 56224ea..abd9a2b 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -67,12 +67,15 @@ db-list: log-zap: false disable: true email: - to: xxx@qq.com - from: xxx@163.com - host: smtp.163.com + to: 184391138@qq.com + from: m13160998425@163.com +# host: smtp.gmail.com # 587 +# host: smtp.163.com # 25 + host: smtp.mxhichina.com # 25 secret: xxx nickname: test - port: 465 +# port: 587 + port: 25 is-ssl: true excel: dir: ./resource/excel/ @@ -212,3 +215,7 @@ zap: max-age: 0 show-line: true log-in-console: true +cdn: + bucket: pychr + op: pychr + password: 9Vk9Mdxkh8zFQ24c6rysPxv3Sjm1IF3L \ No newline at end of file diff --git a/server/config/cdn.go b/server/config/cdn.go new file mode 100644 index 0000000..87e0b60 --- /dev/null +++ b/server/config/cdn.go @@ -0,0 +1,7 @@ +package config + +type CDN struct { + Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` + Op string `mapstructure:"op" json:"op" yaml:"op"` + Password string `mapstructure:"password" json:"password" yaml:"password"` +} diff --git a/server/config/config.go b/server/config/config.go index edb7486..7fcb59f 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -29,4 +29,5 @@ type Server struct { // 跨域配置 Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"` + CDN CDN `mapstructure:"cdn" json:"cdn" yaml:"cdn"` } diff --git a/server/initialize/gorm.go b/server/initialize/gorm.go index 3bf9034..90c5b28 100644 --- a/server/initialize/gorm.go +++ b/server/initialize/gorm.go @@ -2,6 +2,7 @@ package initialize import ( "os" + "pychr/model/goods" "pychr/global" "pychr/model/example" @@ -9,7 +10,6 @@ import ( "go.uber.org/zap" "gorm.io/gorm" - "pychr/model/goods" ) func Gorm() *gorm.DB { @@ -47,12 +47,12 @@ func RegisterTables() { system.SysAuthorityBtn{}, system.SysAutoCode{}, system.SysExportTemplate{}, - system.GoodsShow{}, example.ExaFile{}, example.ExaCustomer{}, example.ExaFileChunk{}, - example.ExaFileUploadAndDownload{}, goods.GoodsShow{}, + example.ExaFileUploadAndDownload{}, + goods.GoodsShow{}, ) if err != nil { global.GVA_LOG.Error("register table failed", zap.Error(err)) diff --git a/server/model/goods/goods_show.go b/server/model/goods/goods_show.go index 1afa791..b57a91c 100644 --- a/server/model/goods/goods_show.go +++ b/server/model/goods/goods_show.go @@ -11,15 +11,15 @@ type GoodsShow struct { global.GVA_MODEL LangType common.LangType `json:"langType" form:"langType" gorm:"column:lang_type;comment:语言类型 1中文 2英文;size:10;" binding:"required"` // 语言类型 1中文 2英文 LangTypeName string `json:"langTypeName" form:"langTypeName"` // 语言类型名称 - GoodsMainPic string `json:"goodsMainPic" form:"goodsMainPic" gorm:"column:goods_main_pic;comment:商品主图;size:191;"` // 商品主图 + GoodsMainPic string `json:"goodsMainPic" form:"goodsMainPic" gorm:"column:goods_main_pic;comment:商品主图;type:longtext;"` // 商品主图 Name string `json:"name" form:"name" gorm:"column:name;comment:商品名称;size:191;" binding:"required"` // 商品名称 BriefIntroduction string `json:"briefIntroduction" form:"briefIntroduction" gorm:"column:brief_introduction;comment:简介;size:191;"` // 简介 Type int `json:"type" form:"type" gorm:"column:type;comment:类型;size:10;" binding:"required"` // 类型 TypeName string `json:"typeName"` // 类型名称 MainIntroduction string `json:"mainIntroduction" form:"mainIntroduction" gorm:"column:main_introduction;comment:主介绍;size:191;"` // 主介绍 - GoodsAssistantPic string `json:"goodsAssistantPic" form:"goodsAssistantPic" gorm:"column:goods_assistantPic;comment:商品副图;size:191;"` // 商品副图 + GoodsAssistantPic string `json:"goodsAssistantPic" form:"goodsAssistantPic" gorm:"column:goods_assistantPic;comment:商品副图;type:longtext;"` // 商品副图 SecondIntroductionTitle string `json:"secondIntroductionTitle" form:"secondIntroductionTitle" gorm:"column:second_introduction_title;comment:副介绍标题;size:191;"` // 副介绍标题 - SecondIntroduction string `json:"secondIntroduction" form:"secondIntroduction" gorm:"column:second_introduction;comment:副介绍,逗号拼接;size:191;"` // 副介绍,逗号拼接 + SecondIntroduction string `json:"secondIntroduction" form:"secondIntroduction" gorm:"column:second_introduction;comment:副介绍,逗号拼接;type:longtext;"` // 副介绍,逗号拼接 } // TableName 商品 GoodsShow自定义表名 goods_show diff --git a/server/model/system/sys_user.go b/server/model/system/sys_user.go index 050a566..77ca8ac 100644 --- a/server/model/system/sys_user.go +++ b/server/model/system/sys_user.go @@ -26,20 +26,3 @@ type SysUser struct { func (SysUser) TableName() string { return "sys_users" } - -type GoodsShow struct { - global.GVA_MODEL - LangType int `json:"langType" gorm:"default:1;comment:语言类型 1中文 2英文"` // 语言类型 1中文 2英文 - GoodsMainPic string `json:"goodsMainPic" gorm:"comment:商品主图"` // 商品主图 - Name string `json:"name" gorm:"index;comment:商品名称"` // 商品名称 - BriefIntroduction string `json:"briefIntroduction" gorm:"comment:简介"` // 简介 - Type int `json:"type" gorm:"default:1;comment:类型"` // 类型 - MainIntroduction string `json:"mainIntroduction" gorm:"default:dark;comment:主介绍"` // 主介绍 - GoodsAssistantPic string `json:"goodsAssistantPic" gorm:"default:'';comment:商品副图"` // 商品副图 - SecondIntroductionTitle string `json:"secondIntroductionTitle" gorm:"default:'';comment:副介绍标题"` // 副介绍标题 - SecondIntroduction string `json:"secondIntroduction" gorm:"comment:副介绍"` // 副介绍,逗号拼接 -} - -func (GoodsShow) TableName() string { - return "goods_show" -} diff --git a/server/plugin/upyun/token.go b/server/plugin/upyun/token.go index f9ef1cc..77778bf 100644 --- a/server/plugin/upyun/token.go +++ b/server/plugin/upyun/token.go @@ -5,100 +5,91 @@ import ( "crypto/md5" "crypto/sha1" "encoding/base64" - "encoding/hex" + "encoding/json" "fmt" - "strconv" + "pychr/global" "strings" "time" ) -var ( - bucket = "pychr" - op = "root" - password = "MRnhPT4VlGXAuDEWe4l7JTxrdxbXjZFE" - token = "2cb96a90-b787-43a4-91ec-54d796c069da" -) - const ( - effectiveDuration = time.Minute * 60 + effectiveDuration = time.Minute * 30 ) -type RestAPIToken struct { - Authorization string - XUpYunUriPrefix string - XUpYunExpire int64 -} - -func GetUpYunRestAPIUploadToken(method string) (r RestAPIToken) { - now := time.Now() - expire := now.Add(effectiveDuration).Unix() - - elem := FilterNoneString([]string{"PUT", "/" + bucket, strconv.FormatInt(expire, 10)}) - p := strings.Join(elem, "&") - key := []byte(StringMD5(password)) - mac := hmac.New(sha1.New, key) - mac.Write([]byte(p)) - hash := mac.Sum(nil) - sign := base64.StdEncoding.EncodeToString(hash) - authorization := "UPYUN " + op + ":" + sign - - r.XUpYunExpire = expire - r.Authorization = authorization - r.XUpYunUriPrefix = "/" + bucket - return -} - type FormAPIToken struct { Bucket string Method string Authorization string XUpYunExpire int64 Policy string + Date string } -func GetUpYunFormAPIToken(method, saveKey string) (r FormAPIToken, err error) { - method = strings.ToUpper(method) - now := time.Now() - expiration := now.Add(effectiveDuration).Unix() +type Policy struct { + Bucket string `json:"bucket"` + SaveKey string `json:"save-key"` + Expiration int64 `json:"expiration"` + // ContentMD5 string `json:"content-md5"` +} - paramsFormat := `{"bucket": "%v", "expiration": %v, "save-key": "%v"}` - params := fmt.Sprintf(paramsFormat, bucket, expiration, saveKey) +func makeSaveKey() string { + return "/{year}/{mon}/{day}/upload_{random32}{.suffix}" +} - policy := StringBase64(params) +func makePolicy(bucket, saveKey string) (string, int64) { + expiration := time.Now().Add(effectiveDuration).Unix() + obj := Policy{ + Bucket: bucket, + SaveKey: saveKey, + Expiration: expiration, + // ContentMD5: content-md5, + } - elem := FilterNoneString([]string{method, "/" + bucket, policy}) - p := strings.Join(elem, "&") - key := []byte(StringMD5(password)) - mac := hmac.New(sha1.New, key) - mac.Write([]byte(p)) - hash := mac.Sum(nil) - sign := base64.StdEncoding.EncodeToString(hash) - authorization := "UPYUN " + op + ":" + sign + str, err := json.Marshal(&obj) + if err != nil { + return "", 0 + } - r.Bucket = bucket - r.Method = method - r.XUpYunExpire = expiration - r.Authorization = authorization - r.Policy = policy - return + sEnc := base64.StdEncoding.EncodeToString([]byte(str)) + return sEnc, expiration } -func FilterNoneString(list []string) (r []string) { - for _, t := range list { - if t != "" { - r = append(r, t) +func md5Str(s string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(s))) +} +func makeRFC1123Date(d time.Time) string { + utc := d.UTC().Format(time.RFC1123) + return strings.Replace(utc, "UTC", "GMT", -1) +} +func base64ToStr(b []byte) string { + return base64.StdEncoding.EncodeToString(b) +} +func sign(key, secret, method, uri, date, policy, md5 string) string { + mac := hmac.New(sha1.New, []byte(secret)) + elems := []string{} + for _, v := range []string{method, uri, date, policy, md5} { + if v != "" { + elems = append(elems, v) } } - return + value := strings.Join(elems, "&") + mac.Write([]byte(value)) + signStr := base64ToStr(mac.Sum(nil)) + return "UPYUN " + key + ":" + signStr } -// 生成字符串MD5 -func StringMD5(s string) string { - h := md5.New() - h.Write([]byte(s)) - return hex.EncodeToString(h.Sum(nil)) -} +func GetUpyunToken(method, saveKey string) (r FormAPIToken, err error) { + method = strings.ToUpper(method) + date := makeRFC1123Date(time.Now()) + policy, expiration := makePolicy(global.GVA_CONFIG.CDN.Bucket, saveKey) + authorization := sign(global.GVA_CONFIG.CDN.Bucket, md5Str(global.GVA_CONFIG.CDN.Password), method, "/"+global.GVA_CONFIG.CDN.Bucket, "", policy, "") + + r.Bucket = global.GVA_CONFIG.CDN.Bucket + r.Method = method + r.XUpYunExpire = expiration + r.Authorization = authorization + r.Policy = policy + r.Date = date -func StringBase64(s string) (r string) { - return base64.StdEncoding.EncodeToString([]byte(s)) + return }