You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular调用Azure Blob存储PUT接口遇403认证错误求助

解决Angular向Azure Blob存储PUT请求返回403认证失败的问题

我之前也踩过Azure Blob存储认证的坑,结合你的代码来看,几个关键细节没处理对,这才导致了403错误。咱们一步步来梳理和修正:

核心问题分析

你收到的错误提示是签名验证失败,这几乎都是因为Authorization头的签名生成不符合Azure规则,再加上几个请求头的细节错误共同导致的。

1. SharedKey签名不能直接填原始密钥

你当前的Authorization头写的是SharedKey myaccount:<access key>,这是完全错误的。Azure的SharedKey签名需要按照特定规则生成:

  • 把请求的方法(PUT)、请求头(尤其是x-ms开头的头)、资源路径等组合成一个签名字符串
  • 用存储账户的access key对这个字符串进行HMAC-SHA256加密,再转成Base64编码
  • 最后把编码后的结果放到Authorization头里,格式是SharedKey <账户名>:<生成的签名>

2. x-ms-date必须是当前UTC时间

你写的是固定值2019-04-09,Azure要求这个时间必须是当前UTC标准时间,且和服务器时间差不能超过15分钟,否则会直接拒绝请求。必须动态生成这个值。

3. Content-Length设置错误

你手动指定了1024,但实际请求体"{hel:ds}"的字节数远小于这个值。Content-Length是签名计算的一部分,数值不匹配会导致签名验证失败。要么让HttpClient自动处理这个头,要么准确计算请求体的字节数。

4. 不必要的请求头干扰

Vary是服务器响应头,你作为请求头设置它完全没必要,建议去掉,避免影响签名计算。

修正后的代码示例

我给你整理了可运行的修正代码,这里用crypto-js库来处理签名计算(先通过npm install crypto-js安装):

import { HttpClient, HttpHeaders } from '@angular/common/http';
import * as CryptoJS from 'crypto-js';

// 配置你的存储账户信息
const accountName = 'matasisrael';
const containerName = 'matas';
const accessKey = '你的存储账户access key'; // 注意是存储账户的key,不是SAS
const blobUrl = `https://${accountName}.blob.core.windows.net/${containerName}/routes.json`;

// 准备请求体
const requestBody = JSON.stringify({ hel: 'ds' });

// 生成当前UTC时间(必须符合格式要求)
const currentUtcDate = new Date().toUTCString();

// 计算请求体的字节长度(如果要手动设置Content-Length的话)
const contentLength = new TextEncoder().encode(requestBody).length;

// 构建签名字符串:注意x-ms开头的头要按字母排序,顺序不能错
const stringToSign = `PUT\n\napplication/json; charset=UTF-8\n${currentUtcDate}\nx-ms-blob-type:BlockBlob\nx-ms-version:2015-02-21\n/${accountName}/${containerName}/routes.json`;

// 生成签名:用Base64解析access key,再做HMAC-SHA256加密,最后转Base64
const signature = CryptoJS.HmacSHA256(stringToSign, CryptoJS.enc.Base64.parse(accessKey)).toString(CryptoJS.enc.Base64);

// 构建正确的请求头
const httpOptions = {
  headers: new HttpHeaders({
    'x-ms-version': '2015-02-21',
    'x-ms-date': currentUtcDate,
    'Content-Type': 'application/json; charset=UTF-8',
    'x-ms-blob-type': 'BlockBlob',
    'Authorization': `SharedKey ${accountName}:${signature}`,
    // Content-Length可以省略,HttpClient会自动计算,这里如果加就要准确
    'Content-Length': contentLength.toString()
  })
};

// 发起请求
this.http.put(blobUrl, requestBody, httpOptions).subscribe(
  data => console.log('Blob上传成功:', data),
  error => console.error('上传失败:', error)
);

更简单的替代方案:使用SAS URL

如果你觉得SharedKey签名太繁琐,强烈推荐用SAS(共享访问签名)。生成带写入权限的SAS token后,直接拼在Blob URL后面,请求时不需要处理Authorization头,代码会简洁很多:

const sasBlobUrl = 'https://matasisrael.blob.core.windows.net/matas/routes.json?<你的SAS Token>';
const httpOptions = {
  headers: new HttpHeaders({
    'x-ms-version': '2015-02-21',
    'x-ms-date': new Date().toUTCString(),
    'x-ms-blob-type': 'BlockBlob',
    'Content-Type': 'application/json; charset=UTF-8'
  })
};

this.http.put(sasBlobUrl, requestBody, httpOptions).subscribe(
  data => console.log('上传成功'),
  error => console.error('上传失败')
);

额外注意事项

  • 确保你的存储账户access key或SAS token拥有Blob写入权限(比如SAS要包含w权限)
  • 检查容器是否已经存在,私有容器必须通过密钥/SAS才能写入
  • 如果使用SAS,注意SAS的有效期,过期后也会返回403

内容的提问来源于stack exchange,提问作者Sagiv Melamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:15:00