使用Postman生成Azure IoT Hub设备注册SAS令牌遇未授权问题
Azure IoT Hub设备注册SAS令牌未授权问题排查
我用Postman预请求脚本生成SAS令牌用于Azure IoT Hub设备注册,一直收到**Unauthorized(未授权)**错误。sr和se参数看起来正常,怀疑问题出在签名部分。
现有预请求脚本
var resourceUri = "scopeId/registrations/deviceId" // The resource uri var deviceId = "deviceId"; resourceUri = encodeURIComponent(resourceUri.toLowerCase()); // Encode the url var expires = Math.ceil((Date.now() / 1000) + 10 * 60); // Expire the token 60 minutes from now var toSign = resourceUri + "\n" + expires; // this is the string format to gen signature from var crypted = CryptoJS.HmacSHA256(deviceId, CryptoJS.enc.Base64.parse("symmetrickKeyOfEnrollmentGroup")); var signature = CryptoJS.HmacSHA256(toSign, crypted); // The signature generated from the decodedKey var encodedUri = encodeURIComponent(CryptoJS.enc.Base64.stringify(signature)); // The url encoded version of the Base64 signature // Construct authorization string (shared access signature) var iotHubSasToken = "SharedAccessSignature sr=" + resourceUri + "&sig=" + encodedUri + "&se=" + expires +"&skn=registration"; console.log(iotHubSasToken); postman.setGlobalVariable("token", iotHubSasToken);
生成的令牌
SharedAccessSignature sr=0ne002ee24e%2Fregistrations%2Fcxdlx3f3zv9xx3f3zq&sig=Ukz%2FPyyLaweLYmFq4gHUP%2BhiO7X%2FyQAE9noAaw4nuLU%3D&se=1659940252&skn=registration
错误截图

问题分析与修正方案
1. 签名生成逻辑错误
注册组场景下,需要先从注册组对称密钥派生设备专属密钥,再用派生密钥签名待签内容。你当前的代码错误地使用了派生密钥的哈希结果去签名,导致签名无效。
2. 待签名字符串格式错误
待签名的resourceUri应该使用原始小写值,而非已经encodeURIComponent后的版本,编码只用于最终令牌的sr参数。
3. 多余的skn参数
DPS注册组的SAS令牌不需要skn(共享访问策略名称)参数,该参数仅适用于IoT Hub服务级别的共享访问策略,需要移除。
修正后的预请求脚本
var scopeId = "你的Scope ID"; var deviceId = "你的设备ID"; var enrollmentGroupKey = "注册组对称密钥"; // 构造原始resourceUri并转小写(不编码) var resourceUri = `${scopeId}/registrations/${deviceId}`.toLowerCase(); // 生成设备派生密钥:HMAC-SHA256(设备ID, 解码后的注册组密钥),再转Base64 var decodedGroupKey = CryptoJS.enc.Base64.parse(enrollmentGroupKey); var derivedDeviceKey = CryptoJS.HmacSHA256(deviceId, decodedGroupKey); var derivedDeviceKeyBase64 = CryptoJS.enc.Base64.stringify(derivedDeviceKey); // 设置令牌过期时间(10分钟后) var expires = Math.ceil((Date.now() / 1000) + 10 * 60); // 构造待签名内容:原始resourceUri + 换行符 + 过期时间 var toSign = `${resourceUri}\n${expires}`; // 用派生密钥签名待签内容 var signature = CryptoJS.HmacSHA256(toSign, CryptoJS.enc.Base64.parse(derivedDeviceKeyBase64)); var encodedSignature = encodeURIComponent(CryptoJS.enc.Base64.stringify(signature)); // 构造最终SAS令牌(移除skn参数) var encodedResourceUri = encodeURIComponent(resourceUri); var sasToken = `SharedAccessSignature sr=${encodedResourceUri}&sig=${encodedSignature}&se=${expires}`; console.log(sasToken); postman.setGlobalVariable("token", sasToken);
额外验证点
- 确认注册组配置中允许设备注册,且设备ID格式符合要求
- 检查本地时间与Azure服务器时间偏差不超过5分钟(避免过期时间校验失败)
- 确保注册组对称密钥未被篡改,且正确解码使用
内容的提问来源于stack exchange,提问作者Liverpool
相关产品推荐
相关产品推荐

