SAS 令牌 - 签名字段格式不正确

Mat*_*icz 6 java azure

我想生成一个 SAS 令牌来访问我的 Blob 容器,其中包含我的一些媒体文件。

\n\n

所以我使用以下代码创建了一个 SharedAccessSignature.java 类:

\n\n
public class SharedAccessSignature\n{\n    private final String signature;\n\n    private final String signedPermission;\n    private final String signedStart;\n    private final String signedExpiry;\n    private final String signedIdentifier;\n    private final String signedIp;\n    private final String signedProtocol;\n    private final String signedVersion;\n    private final String signedResource;\n\n    private SharedAccessSignature(SasBuilder builder)\n    {\n        signedPermission = formatAsUrlParameter("sp", builder.signedPermission);\n        signedStart = formatAsUrlParameter("st", builder.signedStart);\n        signedExpiry = formatAsUrlParameter("se", builder.signedExpiry);\n        signedIdentifier = formatAsUrlParameter("si", builder.signedIdentifier);\n        signedIp = formatAsUrlParameter("sip", builder.signedIp);\n        signedProtocol = formatAsUrlParameter("spr", builder.signedProtocol);\n        signedVersion = formatAsUrlParameter("sv", builder.signedVersion);\n        signedResource = formatAsUrlParameter("sr", builder.signedResource);\n\n        signature = "sig=" + new SasBuilder().encodeUtf8(builder.signature);\n    }\n\n    private String formatAsUrlParameter(String parameterKey, String parameterValue)\n    {\n        if (StringUtils.isNotBlank(parameterValue))\n        {\n            return parameterKey + "=" + parameterValue + "&";\n        }\n        return "";\n    }\n\n    @Override\n    public String toString()\n    {\n        return new StringBuilder()\n            .append(signedVersion)\n            .append(signedResource)\n            .append(signedStart)\n            .append(signedExpiry)\n            .append(signedPermission)\n            .append(signedIp)\n            .append(signedProtocol)\n            .append(signedIdentifier)\n            .append(signature)\n            .toString();\n    }\n\n    public static class SasBuilder\n    {\n        private String signature = "";\n\n        private String signedPermission = "";\n        private String signedStart = "";\n        private String signedExpiry = "";\n        private String canonicalizedResource = "";\n        private String signedIdentifier = "";\n        private String signedIp = "";\n        private String signedProtocol = "";\n        private String signedVersion = "";\n        private String signedResource = "";\n\n        public SasBuilder signedVersion(String signedVersion)\n        {\n            this.signedVersion = signedVersion;\n            return this;\n        }\n\n        public SasBuilder signedPermission(String signedPermission)\n        {\n            this.signedPermission = signedPermission;\n            return this;\n        }\n\n        public SasBuilder canonicalizedResource(String canonicalizedResource)\n        {\n            this.canonicalizedResource = canonicalizedResource;\n            return this;\n        }\n\n        public SasBuilder signedIp(String signedIp)\n        {\n            this.signedIp = signedIp;\n            return this;\n        }\n\n        public SasBuilder signedProtocol(String signedProtocol)\n        {\n            this.signedProtocol = signedProtocol;\n            return this;\n        }\n\n        public SasBuilder signedIdentifier(String signedIdentifier)\n        {\n            this.signedIdentifier = signedIdentifier;\n            return this;\n        }\n\n        public SasBuilder signedExpiry(String signedExpiry)\n        {\n            this.signedExpiry = signedExpiry;\n            return this;\n        }\n\n        public SasBuilder signedStart(String signedStart)\n        {\n            this.signedStart = signedStart;\n            return this;\n        }\n\n        public SasBuilder signedResource(String signedResource)\n        {\n            this.signedResource = signedResource;\n            return this;\n        }\n\n        public SharedAccessSignature build()\n        {\n            String toBeAsEnvironmentVariable_securityKey = "....";\n            signature = generateSasSignature(toBeAsEnvironmentVariable_securityKey, stringToSign());\n            checkPreconditions();\n            return new SharedAccessSignature(this);\n        }\n\n        private String generateSasSignature(String key, String input)\n        {\n            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");\n            Encoder encoder = Base64.getEncoder();\n            Mac sha256_HMAC = null;\n            String hash = null;\n\n            try\n            {\n                sha256_HMAC = Mac.getInstance("HmacSHA256");\n                sha256_HMAC.init(secret_key);\n                hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));\n            }\n            catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e)\n            {\n                e.printStackTrace();\n            }\n            return hash;\n        }\n\n        private String stringToSign()\n        {\n            StringBuilder strToSign = new StringBuilder();\n            strToSign.append(signedPermission).append("\\n");\n            strToSign.append(signedStart).append("\\n");\n            strToSign.append(signedExpiry).append("\\n");\n            strToSign.append(canonicalizedResource).append("\\n");\n            strToSign.append(signedIdentifier).append("\\n");\n            strToSign.append(signedIp).append("\\n");\n            strToSign.append(signedProtocol).append("\\n");\n            strToSign.append(signedVersion).append("\\n");\n            strToSign.append("").append("\\n");\n            strToSign.append("").append("\\n");\n            strToSign.append("").append("\\n");\n            strToSign.append("").append("\\n");\n            strToSign.append("");\n            return strToSign.toString();\n        }\n\n        private void checkPreconditions()\n        {\n            if (StringUtils.isBlank(signedVersion) || StringUtils.isBlank(signedResource) || StringUtils.isBlank(signedPermission) || StringUtils.isBlank(signedExpiry) || StringUtils.isBlank(signature))\n            {\n                throw new IllegalStateException("SAS Builder: SignedVersion, signedResource, SignedPermission, SignedExpiry, Signature must be set.");\n            }\n        }\n\n        private String encodeUtf8(String textToBeEncoded)\n        {\n            try\n            {\n                return URLEncoder.encode(textToBeEncoded, "UTF-8");\n            }\n            catch (UnsupportedEncodingException e)\n            {\n                e.printStackTrace();\n            }\n            return textToBeEncoded;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我尝试生成一个 SAS 令牌,如下所示:

\n\n
SharedAccessSignature s = new SharedAccessSignature.SasBuilder()\n        .signedPermission("rwd")\n        .signedStart("2018-01-31T10:48:41Z")\n        .signedExpiry("2018-04-06T18:48:41Z")\n        .signedVersion("2015-04-05")\n        .signedResource("b")\n        .canonicalizedResource("/blob/myaccount")\n        .signedProtocol("https")\n        .build();\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n
sv=2015-04-05&sr=b&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D\n
Run Code Online (Sandbox Code Playgroud)\n\n

获取请求:

\n\n
https://account.blob.core.cloudapi.de/container/filename.mp4?sv=2015-04-05&sr=b&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是当我使用生成的令牌发送该请求时,天蓝色出现此错误:

\n\n
<Error>\n <Code>AuthenticationFailed</Code>\n <Message>\n   Server failed to authenticate the request. Make sure the value of \n   Authorization header is formed correctly including the signature. \n </Message>\n <AuthenticationErrorDetail>\n   Signature did not match. String to sign used was rwd 2018-01-31T10:48:41Z \n   2018-04-06T18:48:41Z /blob/globalweb/..... https 2015-04-05\n </AuthenticationErrorDetail>\n</Error>\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑:

\n\n

我很绝望......我不明白\xc2\xb4t明白......这个“签名字符串”有什么问题?为什么“签名不匹配”?

\n\n
--------\nrwd\\n\n2018-01-31T10:48:41Z\\n\n2018-04-06T18:48:41Z\\n\n/blob/globalweb/videos-martindale\\n\n\\n\n\\n\nhttps\\n\n2015-04-05\\n\n\\n\n\\n\n\\n\n\\n\n\n-------\n\n//link: https://globalweb.blob.core.cloudapi.de/videos-martindale/somevideo.mp4?sv=2015-04-05&sr=c&st=2018-01-31T10:48:41Z&se=2018-04-06T18:48:41Z&sp=rwd&spr=https&sig=kd09Y%2FTL5V%2F570VWRuEfq7XbEHvcgo4Z%2F2y9t4OswY8%3D\n\n<Error>\n    <Code>AuthenticationFailed</Code>\n    <Message>\n        Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:644e47a6-001e-0050-3f20-abc0f0000000 Time:2018-02-21T14:31:10.9429817Z\n    </Message>\n    <AuthenticationErrorDetail>\n        Signature did not match. String to sign used was rwd 2018-01-31T10:48:41Z 2018-04-06T18:48:41Z /blob/globalweb/videos-martindale https 2015-04-05\n    </AuthenticationErrorDetail>\n</Error>\n
Run Code Online (Sandbox Code Playgroud)\n

dio*_*sgg 2

主要问题出在你的generateSasSignature方法上。它应该从 中解码密钥Base64。就像下面这样:

public static String generateSasSignature(String key, String input) {
    SecretKeySpec secret_key = new SecretKeySpec(Base64.getDecoder().decode(key), "HmacSHA256");
    Encoder encoder = Base64.getEncoder();
    Mac sha256_HMAC = null;
    String hash = null;

    try {
        sha256_HMAC = Mac.getInstance("HmacSHA256");
        sha256_HMAC.init(secret_key);
        hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
    }
    catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return hash;
}
Run Code Online (Sandbox Code Playgroud)

然后,假设您有兴趣访问名为 的容器mycontainer,那么您应该这样做:

SharedAccessSignature s = new SharedAccessSignature.SasBuilder()
    .signedPermission("rwd")
    .signedStart("2018-01-31T10:48:41Z")
    .signedExpiry("2018-04-06T18:48:41Z")
    .signedVersion("2015-04-05")
    .signedResource("c")  // <<---- note here
    .canonicalizedResource("/blob/globalweb/mycontainer") // No ending slash!
    .signedProtocol("https")
    .build();
Run Code Online (Sandbox Code Playgroud)

但是,如果您想生成 Account SAS,可以使用以下代码:

public static void main(String[] args) throws UnsupportedEncodingException {
    String accountName = "globalweb";
    String signedPermissions = "rl"; //read and list
    String signedService = "b";  //blob
    String signedResType = "sco";  //service, container, objects
    String start = "2018-02-22T17:16:25Z";
    String expiry = "2018-02-28T01:16:25Z";
    String signedIp = "";
    String protocol = "https";
    String signedVersion = "2017-07-29";

    String stringToSign = 
            accountName + "\n" +  
        signedPermissions + "\n" +  
        signedService + "\n" +  
        signedResType + "\n" +  
        start + "\n" +  
        expiry + "\n" +  
        signedIp + "\n" +  
        protocol + "\n" +  
        signedVersion + "\n";

    //outputs SAS Token
    System.out.println(
            "?sv="+signedVersion +
            "&ss="+signedService +
            "&srt="+signedResType + 
            "&sp="+signedPermissions +
            "&st="+start+
            "&se="+expiry+
            "&spr="+protocol+
            "&sig="+
            URLEncoder.encode(SasBuilder.generateSasSignature(MY_KEY_BASE64, stringToSign), "UTF-8"));
}
Run Code Online (Sandbox Code Playgroud)