关于七牛JS-SDK依赖的上传凭证算法小记

926 阅读2分钟

上传凭证生成算法

  1. 构造上传策略
// 例如用户要向空间my-bucket上传一个文件,并且希望得到文件资源名,则相应的上传策略各字段分别为:
putPolicy = {
    scope: 'my-bucket',
    returnBody: '{"key": $(key)}'
};
  1. 将上传策略序列化成JSON
putPolicy = JSON.stringify(putPolicy);
  1. 对JSON编码的上传策略进行URL安全的Base64编码,得到待签名字符串

URL安全的Base64编码:第一步先将内容以Base64格式编码为字符串,第二步检查该结果字符串,将字符串中的加号+换成中划线-,并且将斜杠/换成下划线_。

encodedPutPolicy = urlsafe_base64_encode(putPolicy)
// qiniu/js-sdk 有提供 urlSafeBase64Encode 方法
// import qiniu from "qiniu-js/dist/qiniu.min.js";
// qiniu.urlSafeBase64Encod(putPolicy);
  1. 使用访问密钥(AK/SK)对上一步生成的待签名字符串计算HMAC-SHA1签名
sign = hmac_sha1(encodedPutPolicy, "<SecretKey>")
// 借助 crypto-es 实现
// import CryptoES from 'crypto-es';
// function hmacSha1(encodedFlags, secretKey) {
//   return CryptoES.HmacSHA1(encodedFlags, secretKey).toString(CryptoES.enc.Base64);
// }
// hmacSha1(encodedPutPolicy, "<SecretKey>");
  1. 对签名进行URL安全的Base64编码
encodedSign = urlsafe_base64_encode(sign)
// 正则,将字符串中的加号+换成中划线-,并且将斜杠/换成下划线_
// function base64ToUrlSafe(v) {
//   return v.replace(/\//g, '_').replace(/\+/g, '-');
// }
// base64ToUrlSafe(sign);
  1. 将访问密钥(Ak/SK)、encodedSign和encodedPutPolicy用英文符号:连接起来
uploadToken = AccessKey + ':' + encodedSign + ':' + encodedPutPolicy

看了下qiniu/nodejs-sdk生成上传凭证的源码,有一点存疑,文档中提到第三步和第五步都涉及到了URL安全的Base64编码,该编码方式的基本过程上面提到分成一二两步,但是源码中显示,第三步用到了一二两步,但是第五步只用到了第二步:

PutPolicy.prototype.uploadToken = function (mac) {
    mac = mac || new digest.Mac();
    var flags = this.getFlags();
    // urlsafeBase64Encode
    var encodedFlags = util.urlsafeBase64Encode(JSON.stringify(flags));
    var encoded = util.hmacSha1(encodedFlags, mac.secretKey);
    // base64ToUrlSafe
    var encodedSign = util.base64ToUrlSafe(encoded);
    var uploadToken = mac.accessKey + ':' + encodedSign + ':' + encodedFlags;
    return uploadToken;
};
exports.base64ToUrlSafe = function (v) {
    return v.replace(/\//g, '_').replace(/\+/g, '-');
};

// UrlSafe Base64 Decode
exports.urlsafeBase64Encode = function (jsonFlags) {
    var encoded = Buffer.from(jsonFlags).toString('base64');
    return exports.base64ToUrlSafe(encoded);
};