tl;dr
SAS トークンの構造を学習するために、ライブラリを使わないで、 Java で生成しました。
( Node.js 版は こちら )
公式ドキュメント : サービス SAS を作成する
コード
BLOB オブジェクト を 30秒 だけ Read 可能なURL
Main.java
public class Main {
public static void main(String[] args) {
String name = "ストレージアカウント名";
String key = "キー";
String container = "コンテナ名";
String blob = "ブロブ名";
int expiry = 30; // 30 秒間有効
String filename = "ファイル名";
SAS sas = new SAS(name, key);
String url = sas.getUrl(container, blob, expiry, filename);
System.out.println(url);
}
}
SAS.java
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.StringJoiner;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class SAS {
String account_name;
String account_key;
// コンストラクタ
// @param name ストレージアカウント名
// @param key ストレージアカウントキー
public SAS(String name, String key) {
account_name = name;
account_key = key;
}
// トークン付きURLを生成する
// @param container コンテナ名
// @param blob ブロブ名
// @param expiry_second トークン有効期間(秒)
// @param filename ファイル名
public String getUrl(String container, String blob, int expiry_second, String filename) {
String token = getToken(container, blob, expiry_second, filename);
String url = "https://" + account_name + ".blob.core.windows.net/" + container + "/" + blob;
return url + "?" + token;
}
// トークンを生成する
// @param container コンテナ名
// @param blob ブロブ名
// @param expiry_second トークン有効期間(秒)
// @param filename ファイル名
String getToken(String container, String blob, int expiry_second, String filename) {
// パラメータ
Date now = new Date();
String start = ""; // isoDate(now, start_second);
String expiry = isoDate(now, expiry_second);
String version = "2018-11-09";
String resource = "b";
String permission = "r";
String ip = ""; // "0.0.0.0/0";
String protocol = ""; // "https";
String canonicalizedResource = "/blob/" + account_name + "/" + container + "/" + blob;
String rscc = "";
String rscd = "attachment; filename=\"" + filename + "\"";
String rsce = "";
String rscl = "";
String rsct = "";
String identifier = "";
String snapshot = "";
// シグネチャ (順番は厳守)
String[] arr = { //
permission, //
start, //
expiry, //
canonicalizedResource, //
identifier, //
ip, //
protocol, //
version, //
resource, //
snapshot, //
rscc, // Cache-Control
rscd, // Content-Disposition
rsce, // Content-Encoding
rscl, // Content-Language
rsct, // Content-Type
};
String stringToSign = String.join("\n", arr);
// HMAC256
String signature = getHMAC256(stringToSign);
// クエリパラメータ (順番は任意)
String params[][] = { //
{ "sp", permission }, //
{ "sr", resource }, //
// { "st", start }, //
{ "se", expiry }, //
// { "sip", ip }, //
// { "spr", protocol }, //
{ "sv", version }, //
{ "sig", signature }, //
{ "rscd", rscd }, //
};
StringJoiner sas = new StringJoiner("&");
Arrays.asList(params).forEach(v -> sas.add(v[0] + "=" + encode(v[1])));
return sas.toString();
}
String encode(String str) {
try {
return URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InternalError(e.toString());
}
}
String isoDate(Date date, int second) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.SECOND, second);
return fmt.format(cal.getTime());
}
String getHMAC256(String input) {
try {
String algo = "HmacSHA256";
// 1. キー は バイト形式 (Base64 で デコード)
byte[] key = Base64.getDecoder().decode(account_key);
SecretKeySpec secretKey = new SecretKeySpec(key, algo);
Mac sha256HMAC = Mac.getInstance(algo);
sha256HMAC.init(secretKey);
// 2. 入力 は バイト形式 (UTF8 で デコード)
byte[] inp = input.getBytes("UTF-8");
// 3. 出力 は バイト形式 を Base64 で エンコード
byte[] out = sha256HMAC.doFinal(inp);
return Base64.getEncoder().encodeToString(out);
} catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
throw new InternalError(e.toString());
}
}
}