oss.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package controllers
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "encoding/base64"
  6. "encoding/hex"
  7. "encoding/json"
  8. "fmt"
  9. "shudao-chat-go/utils"
  10. "strconv"
  11. "time"
  12. "github.com/beego/beego/v2/server/web"
  13. )
  14. type OssController struct {
  15. web.Controller
  16. }
  17. // S3配置信息
  18. var accessKeyId string = "fnyfi2f368pbic74d8ll"
  19. var accessKeySecret string = "jgqwk7sirqlz2602x2k7yx2eor0vii19wah6ywlv"
  20. var bucket string = "gdsc-ai-aqzs"
  21. var endpoint string = "172.16.17.52:8060"
  22. var region string = "raoxi" // S3区域,可根据实际情况调整
  23. // S3服务地址 - 标准S3格式
  24. var host string = "http://" + endpoint + "/" + bucket
  25. // 用户上传文件时指定的前缀
  26. var upload_dir string = "uploads/"
  27. var expire_time int64 = 1800 // 30分钟
  28. // S3策略文档结构
  29. type S3PolicyDocument struct {
  30. Expiration string `json:"expiration"`
  31. Conditions []interface{} `json:"conditions"`
  32. }
  33. // S3响应结构
  34. type S3PolicyToken struct {
  35. URL string `json:"url"`
  36. Fields map[string]string `json:"fields"`
  37. Expire int64 `json:"expire"`
  38. StatusCode int `json:"statusCode"`
  39. }
  40. // 生成AWS4签名
  41. func generateAWS4Signature(secretKey, dateStamp, region, stringToSign string) string {
  42. kDate := hmacSHA256([]byte("AWS4"+secretKey), dateStamp)
  43. kRegion := hmacSHA256(kDate, region)
  44. kService := hmacSHA256(kRegion, "s3")
  45. kSigning := hmacSHA256(kService, "aws4_request")
  46. signature := hmacSHA256(kSigning, stringToSign)
  47. return hex.EncodeToString(signature)
  48. }
  49. // HMAC-SHA256计算
  50. func hmacSHA256(key []byte, data string) []byte {
  51. mac := hmac.New(sha256.New, key)
  52. mac.Write([]byte(data))
  53. return mac.Sum(nil)
  54. }
  55. func (c *OssController) Upload() {
  56. // 设置CORS头
  57. c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*")
  58. c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
  59. c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Content-Type")
  60. // 处理OPTIONS预检请求
  61. if c.Ctx.Request.Method == "OPTIONS" {
  62. c.Ctx.ResponseWriter.WriteHeader(200)
  63. return
  64. }
  65. // 从token中获取用户信息
  66. userInfo, err := utils.GetUserInfoFromContext(c.Ctx.Input.GetData("userInfo"))
  67. if err != nil {
  68. c.Data["json"] = map[string]interface{}{
  69. "statusCode": 401,
  70. "error": "获取用户信息失败: " + err.Error(),
  71. }
  72. c.ServeJSON()
  73. return
  74. }
  75. user_id := int(userInfo.ID)
  76. if user_id == 0 {
  77. user_id = 1
  78. }
  79. // 生成时间相关字符串
  80. now := time.Now().UTC()
  81. expire_end := now.Unix() + expire_time
  82. dateStamp := now.Format("20060102")
  83. amzDate := now.Format("20060102T150405Z")
  84. expiration := now.Add(time.Duration(expire_time) * time.Second).Format("2006-01-02T15:04:05.000Z")
  85. // 生成credential
  86. credential := fmt.Sprintf("%s/%s/%s/s3/aws4_request", accessKeyId, dateStamp, region)
  87. // 生成上传目录
  88. uploadDir := upload_dir + now.Format("01") + now.Format("02") + "/" + strconv.Itoa(user_id) + "/"
  89. // 创建S3策略文档
  90. policy := S3PolicyDocument{
  91. Expiration: expiration,
  92. Conditions: []interface{}{
  93. map[string]string{"bucket": bucket},
  94. []interface{}{"starts-with", "$key", uploadDir},
  95. map[string]string{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
  96. map[string]string{"x-amz-credential": credential},
  97. map[string]string{"x-amz-date": amzDate},
  98. []interface{}{"content-length-range", "0", "104857600"}, // 最大100MB
  99. },
  100. }
  101. // 将策略文档转换为JSON并进行Base64编码
  102. policyJSON, err := json.Marshal(policy)
  103. if err != nil {
  104. c.Data["json"] = map[string]interface{}{
  105. "statusCode": 500,
  106. "error": "Failed to create policy",
  107. }
  108. c.ServeJSON()
  109. return
  110. }
  111. policyBase64 := base64.StdEncoding.EncodeToString(policyJSON)
  112. // 生成AWS4签名
  113. signature := generateAWS4Signature(accessKeySecret, dateStamp, region, policyBase64)
  114. // 构建表单字段
  115. fields := map[string]string{
  116. "key": uploadDir + "${filename}",
  117. "policy": policyBase64,
  118. "x-amz-algorithm": "AWS4-HMAC-SHA256",
  119. "x-amz-credential": credential,
  120. "x-amz-date": amzDate,
  121. "x-amz-signature": signature,
  122. }
  123. // 构建响应
  124. var policyToken S3PolicyToken
  125. policyToken.StatusCode = 200
  126. policyToken.URL = host
  127. policyToken.Fields = fields
  128. policyToken.Expire = expire_end
  129. c.Data["json"] = policyToken
  130. c.ServeJSON()
  131. }