java - 将对象放入 Azure 存储时出现身份验证错误

标签 java azure azure-storage azure-blob-storage azure-authentication

我正在使用 java 对 Azure 进行 REST Api 调用,将一个对象放入其存储中。 我上周成功地做到了这一点,但现在由于某些原因它现在可以工作了。 错误信息如下:

<?xml version="1.0" encoding="utf-8" ?>
<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:a15f2626-0001-004f-778c-f34383000000 Time:2017-07-02T23:43:20.2826278Z</Message>
<AuthenticationErrorDetail>The Date header in the request is incorrect.</AuthenticationErrorDetail>
 </Error>

我认为这不是由错误的时间戳引起的,因为“日期”字段和响应时间在 15 分钟内。 header 中的“日期”字段为 Sun, 2 Jul 2017 23:38:04 GMT 这是我的 java 代码,用于生成 token 并发送请求。

 public void putObject(String blobName) {
    try {
        URL restServiceURL = new URL(getCallAddress() + "/" + blobName);
        HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL.openConnection();

        Calendar cd = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = sdf.format(cd.getTime());

        httpConnection.setDoInput(true);
        httpConnection.setDoOutput(true);
        try {
            httpConnection.setRequestMethod("PUT");
        } catch (ProtocolException e) {
            e.printStackTrace();
        }
        httpConnection.setFixedLengthStreamingMode(getFile().length()); //set output size to avoid out of memory error

      try {
        String token = createToken(blobName, date);
        httpURLConnection.setRequestProperty("Authorization", "SharedKey " + Azure_AccountName + ":" + token);
        } catch (Exception e) {
            log.error("Cannot get token");
            e.printStackTrace();
        }

        httpURLConnection.setRequestProperty("Content-Length", String.valueOf(getFile().length()));
        httpURLConnection.setRequestProperty("x-ms-blob-type", "BlockBlob");
        httpURLConnection.setRequestProperty("x-ms-version", "2015-12-11");
        httpURLConnection.setRequestProperty("x-ms-date",date);
        } catch (IOException e) {
            log.error(e);
            e.printStackTrace();
    }

    FileInputStream inputStream = new FileInputStream(getFile());
    try {
        byte[] buffer = new byte[inputStream.available()];
        inputStream.read(buffer);
        OutputStream out = httpConnection.getOutputStream();
        out.write(buffer);
        out.flush();
        out.close();

        int code = httpConnection.getResponseCode();
        if (code != 201 && code != 200) {
            log.error(code + httpConnection.getResponseMessage());
            throw new UnsupportedOperationException("Put object failed");
        }
        httpConnection.disconnect();

    } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
    } finally {
        IOUtils.closeQuietly(inputStream);
    }
}

private String createToken(String blobName, String date) throws InvalidKeyException, NoSuchAlgorithmException,
        UnsupportedEncodingException {
    String signature = "PUT\n\n\n" + getFile().length() + "\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:" + date +
            "\nx-ms-version:2015-12-11\n" + "/" + Azure_AccountName + "/" + Azure_BucketName + "/" + blobName;
    SecretKey secreteKey = new SecretKeySpec(Base64.decode(KEY), "HmacSHA256");
    Mac sha256HMAC = Mac.getInstance(secreteKey.getAlgorithm());
    sha256HMAC.init(secreteKey);
    byte[] digest = sha256HMAC.doFinal(signature.getBytes("UTF8"));
    return new String(Base64.encode(digest));
}

最佳答案

如果您还没有解决此身份验证错误,可以引用以下代码:

public class PutTest {

    private static final String account = <your account name>;
    private static final String key = <your account key>;

    public static void main(String args[]) throws Exception {

        File file = new File(<your file path>);
        FileInputStream inputStream = new FileInputStream(<your file path>);

        String urlString = "https://" + account + ".blob.core.windows.net/<your container>/<your file name e.g:test.txt>";
        HttpURLConnection connection = (HttpURLConnection) (new URL(urlString)).openConnection();
        getFileRequest(connection, account, key,  file.length());
        // connection.connect();
        connection.setDoInput(true);
        connection.setDoOutput(true);

        byte[] buffer = new byte[inputStream.available()];
        inputStream.read(buffer);
        OutputStream out = connection.getOutputStream();
        out.write(buffer);
        out.flush();
        out.close();
        System.out.println("Response message : " + connection.getResponseMessage());
        System.out.println("Response code : " + connection.getResponseCode());

        BufferedReader br = null;
        if (connection.getResponseCode() != 200) {
            br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
        } else {
            br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
        }
        System.out.println("Response body : " + br.readLine());
    }

    public static void getFileRequest(HttpURLConnection request, String account, String key, long length)
            throws Exception {
        SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
        String stringToSign = "PUT\n" + "\n" // content encoding
                + "\n" // content language
                +length+"\n"// content length
                + "\n" // content md5
                +"\n" // content type
                + "\n" // date
                + "\n" // if modified since
                + "\n" // if match
                + "\n" // if none match
                + "\n" // if unmodified since
                + "\n" // range
                + "x-ms-blob-type:BlockBlob" + "\n" 
                + "x-ms-date:" + date + "\n"
                + "x-ms-version:2015-02-21"+"\n" // headers
                + "/" + account + request.getURL().getPath(); // resources
        System.out.println("stringToSign : " + stringToSign);
        String auth = getAuthenticationString(stringToSign);
        request.setRequestMethod("PUT");

        request.setRequestProperty("x-ms-blob-type", "BlockBlob");
        request.setRequestProperty("x-ms-date", date);
        request.setRequestProperty("x-ms-version", "2015-02-21");
        request.setRequestProperty("Authorization", auth);
        request.setRequestProperty("Content-Length", String.valueOf(length));

    }

    private static String getAuthenticationString(String stringToSign) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
        String authKey = new String(Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));
        String auth = "SharedKey " + account + ":" + authKey;
        return auth;
    }
}

希望有帮助。

关于java - 将对象放入 Azure 存储时出现身份验证错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44891375/

相关文章:

java - 在 Apache Tomcat 8 上部署 Struts 2 应用程序时出现 NoSuchMethodError : ConfigurationManager. addConfigurationProvider

azure - 如何调用部署在 Service Fabric 集群中的 Web api Controller ?

azure - 如何使用 Visual Studio 2017 创建 Azure 响应式静态网站?

c# - 超出一定数量的实体后,Azure 表存储上的查询不起作用?

java - 如何根据字符串java中的一个单词对链接列表进行排序

java - 400 错误请求 - 将 JSON 数据发布到 RESTful Controller 时

java - 如何保护程序在中断时不丢失数据?

azure - 通过 Microsoft Graph API 请求使用 $filter

azure-storage - Microsoft Azure Blob 存储上传性能

azure - 使用代理下载私有(private) Blob 图像?