签名字段格式不正确

签名字段格式不正确

本文介绍了SAS令牌-签名字段格式不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想生成一个SAS令牌以访问我的一些媒体文件所在的blob容器.

I want to generate a SAS token for access to my blob container where are some of my media files.

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

So I created a class SharedAccessSignature.java with this code:

public class SharedAccessSignature
{
    private final String signature;

    private final String signedPermission;
    private final String signedStart;
    private final String signedExpiry;
    private final String signedIdentifier;
    private final String signedIp;
    private final String signedProtocol;
    private final String signedVersion;
    private final String signedResource;

    private SharedAccessSignature(SasBuilder builder)
    {
        signedPermission = formatAsUrlParameter("sp", builder.signedPermission);
        signedStart = formatAsUrlParameter("st", builder.signedStart);
        signedExpiry = formatAsUrlParameter("se", builder.signedExpiry);
        signedIdentifier = formatAsUrlParameter("si", builder.signedIdentifier);
        signedIp = formatAsUrlParameter("sip", builder.signedIp);
        signedProtocol = formatAsUrlParameter("spr", builder.signedProtocol);
        signedVersion = formatAsUrlParameter("sv", builder.signedVersion);
        signedResource = formatAsUrlParameter("sr", builder.signedResource);

        signature = "sig=" + new SasBuilder().encodeUtf8(builder.signature);
    }

    private String formatAsUrlParameter(String parameterKey, String parameterValue)
    {
        if (StringUtils.isNotBlank(parameterValue))
        {
            return parameterKey + "=" + parameterValue + "&";
        }
        return "";
    }

    @Override
    public String toString()
    {
        return new StringBuilder()
            .append(signedVersion)
            .append(signedResource)
            .append(signedStart)
            .append(signedExpiry)
            .append(signedPermission)
            .append(signedIp)
            .append(signedProtocol)
            .append(signedIdentifier)
            .append(signature)
            .toString();
    }

    public static class SasBuilder
    {
        private String signature = "";

        private String signedPermission = "";
        private String signedStart = "";
        private String signedExpiry = "";
        private String canonicalizedResource = "";
        private String signedIdentifier = "";
        private String signedIp = "";
        private String signedProtocol = "";
        private String signedVersion = "";
        private String signedResource = "";

        public SasBuilder signedVersion(String signedVersion)
        {
            this.signedVersion = signedVersion;
            return this;
        }

        public SasBuilder signedPermission(String signedPermission)
        {
            this.signedPermission = signedPermission;
            return this;
        }

        public SasBuilder canonicalizedResource(String canonicalizedResource)
        {
            this.canonicalizedResource = canonicalizedResource;
            return this;
        }

        public SasBuilder signedIp(String signedIp)
        {
            this.signedIp = signedIp;
            return this;
        }

        public SasBuilder signedProtocol(String signedProtocol)
        {
            this.signedProtocol = signedProtocol;
            return this;
        }

        public SasBuilder signedIdentifier(String signedIdentifier)
        {
            this.signedIdentifier = signedIdentifier;
            return this;
        }

        public SasBuilder signedExpiry(String signedExpiry)
        {
            this.signedExpiry = signedExpiry;
            return this;
        }

        public SasBuilder signedStart(String signedStart)
        {
            this.signedStart = signedStart;
            return this;
        }

        public SasBuilder signedResource(String signedResource)
        {
            this.signedResource = signedResource;
            return this;
        }

        public SharedAccessSignature build()
        {
            String toBeAsEnvironmentVariable_securityKey = "....";
            signature = generateSasSignature(toBeAsEnvironmentVariable_securityKey, stringToSign());
            checkPreconditions();
            return new SharedAccessSignature(this);
        }

        private String generateSasSignature(String key, String input)
        {
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "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;
        }

        private String stringToSign()
        {
            StringBuilder strToSign = new StringBuilder();
            strToSign.append(signedPermission).append("\n");
            strToSign.append(signedStart).append("\n");
            strToSign.append(signedExpiry).append("\n");
            strToSign.append(canonicalizedResource).append("\n");
            strToSign.append(signedIdentifier).append("\n");
            strToSign.append(signedIp).append("\n");
            strToSign.append(signedProtocol).append("\n");
            strToSign.append(signedVersion).append("\n");
            strToSign.append("").append("\n");
            strToSign.append("").append("\n");
            strToSign.append("").append("\n");
            strToSign.append("").append("\n");
            strToSign.append("");
            return strToSign.toString();
        }

        private void checkPreconditions()
        {
            if (StringUtils.isBlank(signedVersion) || StringUtils.isBlank(signedResource) || StringUtils.isBlank(signedPermission) || StringUtils.isBlank(signedExpiry) || StringUtils.isBlank(signature))
            {
                throw new IllegalStateException("SAS Builder: SignedVersion, signedResource, SignedPermission, SignedExpiry, Signature must be set.");
            }
        }

        private String encodeUtf8(String textToBeEncoded)
        {
            try
            {
                return URLEncoder.encode(textToBeEncoded, "UTF-8");
            }
            catch (UnsupportedEncodingException e)
            {
                e.printStackTrace();
            }
            return textToBeEncoded;
        }
    }
}

然后我尝试生成这样的SAS令牌:

And then I try to generate a SAS token like this:

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

结果:

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

获取请求:

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

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

But as I am sending that request with this generated token there commes this Error from azure:

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

我很拼命...我不明白...这个字符串签名"出了什么问题?为什么签名不匹配"?

I am desperate... I don´t understand it... What is wrong on this "string-to-sign"? Why the "Signature did not match"?

--------
rwd\n
2018-01-31T10:48:41Z\n
2018-04-06T18:48:41Z\n
/blob/globalweb/videos-martindale\n
\n
\n
https\n
2015-04-05\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

<Error>
    <Code>AuthenticationFailed</Code>
    <Message>
        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
    </Message>
    <AuthenticationErrorDetail>
        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
    </AuthenticationErrorDetail>
</Error>

推荐答案

主要问题在于您的 generateSasSignature 方法.它应该解码来自 Base64 的密钥.如下所示:

The main problem is on you generateSasSignature method. It should decode the key from Base64. Like the following:

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;
}

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

Then, assuming you're interested in having access to the container called mycontainer, this is how you should do:

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();

但是,如果要生成帐户SAS,则以下代码可以解决问题:

However, if you want to generate an Account SAS, the following code does the trick:

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"));
}

这篇关于SAS令牌-签名字段格式不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 00:58