前端如何进行单文件上传云服务存储( 二 )

直接调用 SDK 中提供的 put 等方法即可完成文件上传
临时 URL 上传(STS 临时授权)鉴于 SDK 上传方案中,会在代码中暴漏 AK (AccessKey ID),SK (AccessKey Secret)  等云服务数据,所以云服务厂家一般也会提供生成临时令牌的方式,可以由后端服务生成一个自定义时效以及权限的访问凭证提供给前端进行上传,有效期到期后,这个访问令牌就会失效,保证了前端上传的安全性 。
【前端如何进行单文件上传云服务存储】

前端如何进行单文件上传云服务存储

文章插图
1. 客户端向自己的后端应用发起请求,将文件类型,名称信息等传给后端,获取对应的上传信息以及授权签名信息 signature 等,
const UploadParams = {"accessid":"LTAI5tBDFVar1hoq****","host":"http://post-test.oss-cn-hangzhou.aliyuncs.com","policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDoyMzoyM1oiLCJjxb25kaXRpb25zIjpbWyJjcb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8i****","signature":"VsxOcOudx******z93CLaXPz+4s=","expire":1446727949,"dir":"user-dirs/"}2. 在获取到服务器返回的签名信息等内容后,客户端则可以通过 POST 或者 PUT 请求直接向云服务发送上传文件的请求(上传形式多种多样,并且有些云服务有要求上传数据类型为 form-data 格式)
// form-data 类型let params = {// key表示上传到 Bucket 内的 Object 的完整路径,例如 exampledir/exampleobject.txtObject,完整路径中不能包含 Bucket 名称 。// filename 表示待上传的本地文件名称 。'key' : key + '${filename}','policy': UploadParams.policy,'OSSAccessKeyId': UploadParams.accessid,// 设置服务端返回状态码为200,不设置则默认返回状态码204 。'success_action_status' : '200','signature': UploadParams.signature,}let requestData = new FormData();Object.keys(params).map(key => {requestData.Append(key, params[key]);});// 获取的上传 file 文件,file 必须为最后一个表单域,除 file 以外的其他表单域无顺序要求requestData.append('file', fileObj);// 非 form-data 类型(非阿里云云服务会遇到,以下代码仅举例,不代表真实使用场景)let requestData = fileObj;let headers = {'key' : key + '${filename}','policy': UploadParams.policy,'OSSAccessKeyId': UploadParams.accessid,'success_action_status' : '200','signature': UploadParams.signature,}// 进行接口请求,上传文件axIOS({method: 'post',url: params.host,data: requestData,headers: headers || {},});这里代码只是简单的示例,实际使用时需要对各个文件服务需要进行不同的适配 。
加密算法和解析对于获取 Signature 鉴权信息等内容时,后端服务在有文档或者 SDK 时,可以对接不同的云服务 JAVA SDK 直接进行生成临时授权的信息,在没有文档的情况下,则需要前端或者后端,针对各个不同的云服务,进行解析加密 Signature 的步骤(我司这里是前端进行了加密过程解析后,后续日常生成由后端服务完成) 。
加密算法
此处我以紫光云的 Signature 生成步骤给大家简单介绍下加密算法的流程,不同的云服务,加密过程都比较类似 。
前端如何进行单文件上传云服务存储

文章插图
图片来源:紫光云上传流程(https://www.unicloud.com/document/show-19262078.html)
以下是根据上述的加密流程写的测试生成 Signature 的代码部分,大家也可以自行测试试用 。
按流程主要分成3步即可
  1. 生成 CanonicalRequest 字段
  2. 生成前面的 StringToSign
  3. 根据 AK (AccessKey ID),SK (AccessKey Secret)  生成 Signature,最后组装 Authorization 。
const crypto = require('crypto');const CryptoJS = require('crypto-js')function zip() {const filename = 'uploadTest.png'// const date = new Date()// const timeStampISO8601Format = `${date.toISOString().replace(/-/g, '').replace(/:/g, '').split('.')[0]}Z` // ISO 8601 格式const timeStampISO8601Format = '20230101T000000Z' // ISO 8601 格式const dateString = timeStampISO8601Format.substr(0, 8) // YYYYMMDD 格式时间const uriFileName = uriEscapePath(filename)const content = 'UNSIGNED-PAYLOAD'// 生成 CanonicalRequest 字段let CanonicalRequest = `PUTn${uriFileName}nncontent-disposition:attachment;filename=uploadTest.pngncontent-type:image/pngnhost:oos-cn.ctyunapi.cnnx-amz-content-sha256:${content}nx-amz-date:${timeStampISO8601Format}nncontent-disposition;content-type;host;x-amz-content-sha256;x-amz-daten${content}`let hashedCanonicalRequest = crypto.createHash('sha256').update(CanonicalRequest).digest('hex');// 生成前面的 StringToSignconst signStr = `AWS4-Hmac-SHA256n${timeStampISO8601Format}n${dateString}/cn/s3/aws4_requestn${hashedCanonicalRequest}`//根据 AK (AccessKey ID),SK (AccessKey Secret) 生成 Signatureconst AWSAccessKeyId = 'AWSAccessKeyId';const AWSSecretAccessKey = 'AWSSecretAccessKey';var DateKey = CryptoJS.HmacSHA256(dateString, `AWS4${AWSSecretAccessKey}`);var DateRegionKey = CryptoJS.HmacSHA256('cn', DateKey);var DateRegionServiceKey = CryptoJS.HmacSHA256('s3', DateRegionKey);var SigningKey = CryptoJS.HmacSHA256('aws4_request', DateRegionServiceKey);var Signature = CryptoJS.HmacSHA256(signStr, SigningKey);console.log('


推荐阅读