Java生成Azure SAS token出现Signature Fields Not Well Formed错误求助
Azure存储SAS生成报"signature fields not well formed"错误的常见原因与修复方案
核心前提
你需要生成的是Azure存储服务的SAS令牌,不能混用事件中心的SAS生成逻辑,两类服务的签名串拼接规则完全不同,混用是触发该报错的高频原因。
常见遗漏/错误点
- 签名串拼接顺序错误/缺空行
存储账户SAS的签名串必须严格按照固定顺序拼接,未用到的可选字段必须保留空行,不能直接省略。标准拼接顺序如下:存储账户名
授权服务类型(blob/file/queue/table对应首字母)
授权资源类型(服务/容器/对象对应s/c/o的组合)
授权权限(读/写/列等对应r/w/l等的组合)
授权起始时间(UTC时区ISO 8601格式,建议比当前时间早5分钟避免时钟偏移)
授权过期时间(UTC时区ISO 8601格式)
授权IP范围(无则留空行)
授权协议(https/https,http,无则留空行)
存储服务API版本号
5个连续空行(对应存储服务可选的专属扩展字段,无配置必须全部保留空行) - 密钥处理逻辑错误
存储账户的访问密钥本身是Base64编码的字符串,计算HMAC-SHA256签名前需要先做Base64解码,不能直接将密钥字符串转字节数组参与计算。 - 编码格式错误
签名计算完成后,签名值以及所有SAS参数都需要做URL编码,+、/、=等特殊字符必须转义,否则会触发签名校验失败。 - API版本不匹配
生成SAS时指定的存储服务API版本号,必须和实际发起文件请求时携带的API版本号一致,否则会校验失败。
正确Java代码示例
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public class StorageSasGenerator { public static String generateAccountSas(String accountName, String accountKey) throws Exception { // 按实际需求配置SAS参数 String signedService = "f"; // f对应File存储,用Blob则填b String signedResourceType = "sco"; // 授权服务、容器、对象级资源 String signedPermission = "rl"; // 授予读、列权限 String signedStart = OffsetDateTime.now(ZoneOffset.UTC).minusMinutes(5).format(DateTimeFormatter.ISO_INSTANT); String signedExpiry = OffsetDateTime.now(ZoneOffset.UTC).plusHours(2).format(DateTimeFormatter.ISO_INSTANT); String signedProtocol = "https"; String signedVersion = "2021-06-08"; // 建议用你实际调用的存储API版本 // 严格按规则拼接签名字符串 String stringToSign = String.join("\n", accountName, signedService, signedResourceType, signedPermission, signedStart, signedExpiry, "", // 无IP限制留空 signedProtocol, signedVersion, "", // 以下5个扩展字段无配置全部留空 "", "", "", "" ); // 计算HMAC-SHA256签名 Mac sha256Hmac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(accountKey), "HmacSHA256"); sha256Hmac.init(secretKey); String signature = Base64.getEncoder().encodeToString(sha256Hmac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8))); // 拼接最终SAS令牌,所有参数值做URL编码 return String.format("?sv=%s&ss=%s&srt=%s&sp=%s&st=%s&se=%s&spr=%s&sig=%s", URLEncoder.encode(signedVersion, StandardCharsets.UTF_8), URLEncoder.encode(signedService, StandardCharsets.UTF_8), URLEncoder.encode(signedResourceType, StandardCharsets.UTF_8), URLEncoder.encode(signedPermission, StandardCharsets.UTF_8), URLEncoder.encode(signedStart, StandardCharsets.UTF_8), URLEncoder.encode(signedExpiry, StandardCharsets.UTF_8), URLEncoder.encode(signedProtocol, StandardCharsets.UTF_8), URLEncoder.encode(signature, StandardCharsets.UTF_8) ); } }
内容的提问来源于stack exchange,提问作者whey_do_MSFT_docs_stink
相关产品推荐
相关产品推荐

