OSS前端直傳+后端簽名

OSS前端直傳+后端簽名

一重父、服務(wù)端簽名后前端直傳

首先安裝阿里云SDK Aliyun.OSS.SDK.NetCore

        public static string accessKeyId = "你的accessKeyId";
        public static string accessKeySecret = "你的accessKeySecret";
        public static string bucketName = "你的桶名稱";
        public static string endpoint = "oss-cn-beijing.aliyuncs.com";
        public static int expireTime = 30;
        public Dictionary<string, string> GetPolicy(string fileName)
        {
            var dir = DateTime.Now.ToString("yyyyMMdd") + "/";
            // 構(gòu)造OssClient實例。 endpoint 格式:https://oss-cn-beijing.aliyuncs.com
            var ossClient = new OssClient("https://" + endpoint, accessKeyId, accessKeySecret);
            var config = new PolicyConditions();
            config.AddConditionItem(PolicyConditions.CondContentLengthRange, 1, 1024L * 1024 * 1024 * 5);// 文件大小范圍:單位byte
            config.AddConditionItem(MatchMode.StartWith, PolicyConditions.CondKey, dir);
            var expire = DateTimeOffset.Now.AddMinutes(30);// 過期時間
            // 生成 Policy,并進行 Base64 編碼
            var policy = ossClient.GeneratePostPolicy(expire.LocalDateTime, config);
            var policyBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy));

            // 計算簽名
            var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(accessKeySecret));
            var bytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(policyBase64));
            var sign = Convert.ToBase64String(bytes);
            // 將簽名和回調(diào)的內(nèi)容,返回給前端
            var host = $"https://{bucketName}.{endpoint}";
            var key = $"{dir}{Guid.NewGuid()}/{fileName}";
            var fullUrl = $"https://{bucketName}.{endpoint}/{key}";
            var rt = new Dictionary<string, string>
            {
                { "OSSAccessKeyId",accessKeyId},
                { "Host",host },
                { "key",key},
                { "policy",policyBase64},
                { "Signature",sign},
                { "success_action_status","200"},
                { "fullUrl",fullUrl },
                {"expire",expire.ToString() }
            };

            return rt;
        }

前端首先訪問后端獲取簽名,獲取簽名后使用FromData的形式上傳文件

async startUpload() {
      // 獲取后端簽名和上傳地址
      const res = await axios.get("http://localhost:5152/api/OSS/GetPolicy", {
        params: {
          name: this.file.name
        }
      });
      var formData = new FormData();
      formData.append("name", this.file.name);
      formData.append("OSSAccessKeyId", res.data.OSSAccessKeyId);
      formData.append("key", res.data.key);
      formData.append("policy", res.data.policy);
      formData.append("signature", res.data.Signature);
      formData.append("success_action_status", res.data.success_action_status);
      formData.append("file", this.file);
      axios
        .post(res.data.Host, formData, {
          headers: {
            "Content-Type": "multipart/form-data"
          },
          withCredentials: false
        })
        .then(res => {
          console.log(res);
        });
    }

二靴拱、服務(wù)端STS簽名前端分片上傳+斷點續(xù)傳

當(dāng)文件過大時野崇,考慮使用分片上傳和斷點續(xù)傳的方式來上傳文件到oss,這時我們就不能直接使用accesskeyId和accessKeySecret的方式來在前端上傳八毯,以免暴露我們的密鑰,當(dāng)然也不能直接使用第一種的方式進行簽名(或許可以瞄桨,沒有找到示例话速,也沒有研究出來),所以我們采用STStoken的方式簽名芯侥,然后在前端使用阿里云提供的SDK進行文件上傳泊交。

斷點續(xù)傳的思路是在每個分片上傳的時候存儲當(dāng)前文件的上傳進度,如果中間因為各種原因無法繼續(xù)上傳時柱查,當(dāng)用戶重新上傳同一個文件的時候廓俭,獲取文件的上傳進度,繼續(xù)上傳沒有上傳完的部分唉工,而不是重新上傳整個文件研乒。為了確保斷點續(xù)傳前后上傳的是同一個文件,我們使用md5作為存儲進度的key值淋硝,如果是同一個文件雹熬,則續(xù)傳,如果不是同一個文件谣膳,則從0開始上傳竿报。

首先登錄阿里云開通sts賬戶和權(quán)限。

安裝 aliyun-net-sdk-core和aliyun-net-sdk-sts sdk

public Dictionary<string, string> GetSTSToken()
        {
            //此處使用sts賬戶的id和secret
            var AccessKeyID = "***";
            var AccessKeySecret = "***";
            string bucketName = "***";
            // ststoken
            IClientProfile profile = DefaultProfile.GetProfile("oss-cn-beijing", AccessKeyID, AccessKeySecret);
            DefaultAcsClient client = new DefaultAcsClient(profile);
            var request = new AssumeRoleRequest();
            request.RoleArn = "***";
            request.RoleSessionName = "xxx";//這里的名字隨便寫
            request.DurationSeconds = 3600;//過期時間
            var response = client.GetAcsResponse(request);

            var result = new Dictionary<string, string>
            {
                {"AccessKeyId", response.Credentials.AccessKeyId},
                {"AccessKeySecret",response.Credentials.AccessKeySecret },
                {"SecurityToken",response.Credentials.SecurityToken },
                {"Expiration",response.Credentials.Expiration },
                {"BucketName",bucketName }
            };

            return result;
        }

簽名完成后继谚,安裝阿里云oss sdk

npm install ali-oss;
npm install spark-md5;
<template>
  <div class="hello">
    <div>
      <input type="file" @change="fileChange" />
      <div>{{ progress }}</div>
    </div>
  </div>
</template>
#自行導(dǎo)入包烈菌,自行定義變量
async fileChange(e) {
      this.file = e.target.files[0];
      this.uploadFile(this.file);
    },
async uploadFile(file) {
      const objectKey = "xxx" + "/file/" + this.file.name;
      // 初始化 OSS 客戶端 SDK
      await this.initOSSClient();
      this.resumeUpload(objectKey, file);
    }
# 首先初始化oss 對象
    async initOSSClient() {
      const res = await axios.get("http://localhost:5152/api/OSS/GetSTSToken");
      console.log(res);
      const {
        AccessKeyId,
        AccessKeySecret,
        SecurityToken,
        BucketName
      } = res.data;
      this.bucketName = BucketName;

      this.client = new OSS({
        region: "oss-cn-beijing",
        accessKeyId: AccessKeyId,
        accessKeySecret: AccessKeySecret,
        stsToken: SecurityToken,
        bucket: BucketName
      });
    },
    # 斷點上傳
    async resumeUpload(objectKey, file) {
      //使用SparkMd5計算文件的md5值
      let md5 =await this.calculateFileMD5(file);

      let checkpoint = JSON.parse(
        window.localStorage.getItem("checkpoint_" + md5)
      );
      var _this = this;
      // 重試五次。
      for (let i = 0; i < 5; i++) {
        try {
          const result = await this.client.multipartUpload(objectKey, file, {
            checkpoint,
            async progress(percentage, cpt) {
              checkpoint = cpt;
              _this.progress = parseInt(percentage * 100);
              // 將 checkpoint 保存到瀏覽器localstorage 中。
              window.localStorage.setItem(
                "checkpoint_" + md5,
                JSON.stringify(checkpoint)
              );
            }
          });
          // 刪除本地保存的 checkpoint僧界,如果此處不刪除的話侨嘀,上傳成功后,用戶無法再次上傳同名文件
          window.localStorage.removeItem("checkpoint_" + md5);

          break; // 跳出當(dāng)前循環(huán)捂襟。
        } catch (e) {
          console.log(e);
        }
      }
    },
    // 使用sparkMD5 計算文件md5
     calculateFileMD5(file, chunkSize = 2097152) {
      // chunkSize為分塊大小咬腕,默認(rèn)為2MB
      return new Promise((resolve, reject) => {
        const fileReader = new FileReader();
        let currentPosition = 0;
        const spark = new SparkMD5.ArrayBuffer();

        fileReader.onerror = function() {
          reject("文件讀取失敗葬荷!");
        };

        fileReader.onload = function() {
          spark.append(fileReader.result); // 將讀取到的數(shù)據(jù)添加到MD5計算器中

          currentPosition += chunkSize;
          if (currentPosition < file.size) {
            // 文件還沒讀完涨共,繼續(xù)讀取下一塊
            loadNext();
          } else {
            // 文件讀取完畢,計算MD5值并返回結(jié)果
            const hash = spark.end();
            resolve(hash);
          }
        };

        function loadNext() {
          const blob = file.slice(currentPosition, currentPosition + chunkSize);
          fileReader.readAsArrayBuffer(blob);
        }

        // 開始讀取第一塊
        loadNext();
      });
    }

如果想自己控制上傳的各步驟可以使用initiateMultipartUpload uploadPart completeMultipartUpload 等方法自行實現(xiàn)各步驟宠漩,大致思路就是先initiateMultipartUpload初始化一個分片上傳举反,返回uploadid,然后將文件按一定的大小分片扒吁,之后循環(huán)上傳每個分片火鼻,完成分片之后調(diào)用completeMultipartUpload方法合并文件,這種方式比較復(fù)雜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雕崩,一起剝皮案震驚了整個濱河市魁索,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盼铁,老刑警劉巖粗蔚,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異饶火,居然都是意外死亡鹏控,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門肤寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來当辐,“玉大人,你說我怎么就攤上這事鲤看≡稻荆” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵刨摩,是天一觀的道長寺晌。 經(jīng)常有香客問我世吨,道長澡刹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任耘婚,我火速辦了婚禮罢浇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己嚷闭,他們只是感情好攒岛,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胞锰,像睡著了一般灾锯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嗅榕,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天顺饮,我揣著相機與錄音,去河邊找鬼凌那。 笑死兼雄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帽蝶。 我是一名探鬼主播赦肋,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼励稳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了麦锯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鹅巍,失蹤者是張志新(化名)和其女友劉穎料祠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體髓绽,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡顺呕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了来涨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹦掐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出藤滥,到底是詐尸還是另有隱情,我是刑警寧澤拙绊,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布泳秀,位于F島的核電站,受9級特大地震影響晶默,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜磺陡,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一币他、第九天 我趴在偏房一處隱蔽的房頂上張望坞靶。 院中可真熱鬧蝴悉,春花似錦、人聲如沸拍冠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晃财。三九已至,卻和暖如春断盛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伙菜。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工厢洞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躺翻。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像踊淳,于是被迫代替她去往敵國和親陕靠。 傳聞我的和親對象是個殘疾皇子迂尝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容