Apex类上传文件至Azure Blob报MAC签名不匹配错误如何解决
签名不匹配的具体问题定位
- 文件名编码使用错误
构造签名用的blobName参数使用了URL编码后的文件名,Azure计算签名时要求使用原始未编码的文件路径,仅请求端点的文件名需要做URL编码,二者混用直接导致签名校验失败。
- 文件名编码使用错误
- 签名字符串换行符数量不匹配
按照2015-12-11版本的Azure Blob签名规则,PUT请求的签名字符串中Content-Type字段后应跟随6个换行符(对应6个未使用的请求头空位),你的代码中多写了1个换行符,导致签名结构不符合要求。
- 签名字符串换行符数量不匹配
- 日期格式化未指定英文Locale
Apex的formatGMT方法默认使用当前用户的Locale,如果用户Locale为非英文,生成的星期缩写、月份缩写会是本地语言,Azure无法识别该日期格式,最终导致签名校验失败。
- 日期格式化未指定英文Locale
修正代码片段
1. 修改uploadBlob方法内的文件名处理逻辑
public Boolean uploadBlob( Blob fileBody, Integer intFileLength, String strFileType, String strFileName) { Boolean isUploaded= false; // 新增:单独存储原始文件名用于签名,编码后的文件名仅用于请求端点 String rawFileName = strFileName; String encodedFileName = EncodingUtil.urlEncode(strFileName, 'UTF-8'); this.fileType = strFileType; this.storageName = 'STORAGE_ACCOUNT'; this.storageContainer = 'CONTAINER_NAME'; this.storageKey = 'ACCESS_KEY'; this.storageUrl ='https://STORAGE_ACCOUNT.blob.core.windows.net'; // 签名用的blobName使用原始未编码文件名 this.blobName = '/'+storageName+'/'+storageContainer+'/'+rawFileName; System.debug('blobName--->'+blobName); // 请求端点使用编码后的文件名 this.requestURL = storageUrl+'/'+storageContainer+'/'+encodedFileName; System.debug('requestURL--->'+requestURL); this.fileLength = String.valueof(intFileLength); String strSharedKey = getBlobSharedKey(); try { this.uploadBlob(fileBody, strSharedKey); isUploaded = true; }catch(Exception exp) { System.debug('Exception occur while uploading the Blob--->'+exp.getMessage()); isUploaded = false; } return isUploaded; }
2. 修改getBlobSharedKey方法内的日期格式化和签名字符串构造逻辑
public String getBlobSharedKey() { System.debug('getBlobSharedKey--->Start'); String sharedKey; String signature; Datetime dt = Datetime.now(); // 新增:指定Locale为en_US,确保日期格式为英文缩写 this.formattedDate = dt.formatGMT(DATEFORMAT, 'en_US'); // 调整:Content-Type后由7个换行改为6个换行,匹配Azure签名规则 String stringToSign = 'PUT\n\n\n'+fileLength+'\n\n'+fileType+'\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:'+formattedDate+'\nx-ms-version:2015-12-11\n'+blobName; System.debug('stringToSign--->'+stringToSign); Blob unicodeKey = EncodingUtil.base64Decode(storageKey); Blob data = Crypto.generateMac('hmacSHA256', Blob.valueOf(stringToSign), unicodeKey); signature = EncodingUtil.base64Encode(data); sharedKey = 'SharedKey '+storageName+':' + signature; return sharedKey; }
校验提示
如果修改后仍存在签名错误,可直接提取Azure错误响应中给出的String to sign参考值,和你本地生成的stringToSign逐字符对比,即可快速定位剩余差异。
内容的提问来源于stack exchange,提问作者hansaliyad
相关产品推荐
相关产品推荐

