aws s3 v4 Authorization Header java签名算法以及注意的地方

阅读: 评论:0

aws s3 v4 Authorization Header java签名算法以及注意的地方

aws s3 v4 Authorization Header java签名算法以及注意的地方

整个签名流程图
  • 任务1 创建规范请求:

* 以下##:后面为注释内容

1.1 <HTTPMethod>n   ##:如:GET PUT DELETE 

1.2 <CanonicalURI>n  ##:URI 如:/admin/user

1.3 <CanonicalQueryString>n ##:特别注意当查询参数为空的时候1.2与1.4之间必须留一空的行

1.4 <CanonicalHeaders>n ##: 每个header都需要换行

1.5 <SignedHeaders>n ##:将所有请求头中的参数排序并且Lowercase()后用;连接起来,如:host;x-amz-content-sha256;x-amz-date

1.6 <HashedPayload> ##:空字符计算之后的值:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

 


通过以上6步计算出 CanonicalRequest

 

  • 任务2 创建要签名的字符串:

2.1: "AWS4-HMAC-SHA256" + "n" +  ##:固定的一行字符串

2.2: timeStampISO8601Format + "n" + ##:格式:20190104T080059Z

2.3: <Scope> + "n" + ##:格式:20190104/us-east-1/s3/aws4_request

2.4: Hex(SHA256Hash(<CanonicalRequest>))  ##:将任务1计算的值进行加密


通过以上4步计算出 stringToSign

 

 

  • 任务3 用secretAccessKey生成真正的签名密钥

3.1: DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>")

3.2: DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>")

3.3: DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>")

3.4: SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")


生成的Signingkey为签名的密钥

 

  • 任务4 生成最终的签名

 

  • 注意点

  1. UriEncode()方法必须自己实现,用其它工具的该方法可能不会对像*这样的字符编码

  2. 一定要注意和官方文档的格式要完全一样

 

 

  • 工具类代码

public class AWSV4Auth {private AWSV4Auth() {}public static class Builder {private String accessKeyID;private String secretAccessKey;private String regionName;private String serviceName;private String httpMethodName;private String canonicalURI;private TreeMap<String, String> queryParametes;private TreeMap<String, String> awsHeaders;private String payload;public Builder(String accessKeyID, String secretAccessKey) {this.accessKeyID = accessKeyID;this.secretAccessKey = secretAccessKey;}public Builder regionName(String regionName) {ionName = regionName;return this;}public Builder serviceName(String serviceName) {this.serviceName = serviceName;return this;}public Builder httpMethodName(String httpMethodName) {this.httpMethodName = httpMethodName;return this;}public Builder canonicalURI(String canonicalURI) {this.canonicalURI = canonicalURI;return this;}public Builder queryParametes(TreeMap<String, String> queryParametes) {this.queryParametes = queryParametes;return this;}public Builder awsHeaders(TreeMap<String, String> awsHeaders) {this.awsHeaders = awsHeaders;return this;}public Builder payload(String payload) {this.payload = payload;return this;}public AWSV4Auth build() {return new AWSV4Auth(this);}}private String accessKeyID;private String secretAccessKey;private String regionName;private String serviceName;private String httpMethodName;private String canonicalURI;private TreeMap<String, String> queryParametes;private TreeMap<String, String> awsHeaders;private String payload;/* Other variables */private final String HMACAlgorithm = "AWS4-HMAC-SHA256";private final String aws4Request = "aws4_request";private String strSignedHeader;private String xAmzDate;private String currentDate;private AWSV4Auth(Builder builder) {accessKeyID = builder.accessKeyID;secretAccessKey = builder.secretAccessKey;regionName = ionName;serviceName = builder.serviceName;httpMethodName = builder.httpMethodName;canonicalURI = builder.canonicalURI;queryParametes = builder.queryParametes;awsHeaders = builder.awsHeaders;payload = builder.payload;//Get current timestamp value.(UTC)xAmzDate = getTimeStamp();currentDate = getDate();}/*** 任务 1:针对签名版本 4 创建规范请求** @return*/private String prepareCanonicalRequest() {StringBuilder canonicalURL = new StringBuilder("");//Step 1.1 HTTP方法 GET, PUT, POST,DELETEcanonicalURL.append(httpMethodName).append("n");//Step 1.2 URIcanonicalURI = canonicalURI == null || im().isEmpty() ? "/" : canonicalURI;canonicalURL.append(uriEncode(canonicalURI, false)).append("n");///* Step 1.3 添加查询参数StringBuilder queryString = new StringBuilder("");if (queryParametes != null && !queryParametes.isEmpty()) {for (Map.Entry<String, String> entrySet : Set()) {String key = Key();String value = Value();queryString.append(key).append("=").append(uriEncode(value, false)).append("&");}queryString.deleteCharAt(queryString.lastIndexOf("&"));queryString.append("n");canonicalURL.append(queryString);} else {queryString.append("n");canonicalURL.append("n");}// Step 1.4 添加headers, 每个header都需要换行StringBuilder signedHeaders = new StringBuilder("");if (awsHeaders != null && !awsHeaders.isEmpty()) {for (Map.Entry<String, String> entrySet : Set()) {String key = Key();String value = Value();signedHeaders.append(key).append(";");canonicalURL.append(key).append(":").im()).append("n");}canonicalURL.append("n");} else {canonicalURL.append("n");}//Step 1.5 添加签名的headersstrSignedHeader = signedHeaders.substring(0, signedHeaders.length() - 1); // 删掉最后的 ";"canonicalURL.append(strSignedHeader).append("n");/* Step 1.6 对HTTP或HTTPS的body进行SHA256处理. */payload = payload == null ? "" : payload;canonicalURL.append(generateHex(payload));System.out.println("##Canonical Request:n" + String());String();}/*** 任务 2:创建签名版本 4 的待签字符串* stringToSign** @param canonicalURL* @return*/private String prepareStringToSign(String canonicalURL) {String stringToSign = "";/* Step 2.1 以算法名称开头,并换行. */stringToSign = HMACAlgorithm + "n";/* Step 2.2 添加日期,并换行. */stringToSign += xAmzDate + "n";/* Step 2.3 添加认证范围,并换行. */stringToSign += currentDate + "/" + regionName + "/" + serviceName + "/" + aws4Request + "n";/* Step 2.4 添加任务1返回的规范URL哈希处理结果,然后换行. */stringToSign += generateHex(canonicalURL);System.out.println("##String to sign:n" + stringToSign);return stringToSign;}/*** 任务 3:为 AWS Signature 版本 4 计算签名* Signatrue** @param stringToSign* @return*/private String calculateSignature(String stringToSign) {try {/* Step 3.1 获取签名的key */byte[] signatureKey = getSignatureKey(secretAccessKey, currentDate, regionName, serviceName);/* Step 3.2 计算签名. */byte[] signature = HmacSHA256(signatureKey, stringToSign);/* Step 3.2.1 对签名编码处理 */String strHexSignature = bytesToHex(signature);return strHexSignature;} catch (Exception ex) {ex.printStackTrace();}return null;}/*** 任务 4:将签名信息添加到请求并返回headers** @return*/public Map<String, String> getHeaders() {awsHeaders.put("x-amz-date", xAmzDate);awsHeaders.put("x-amz-content-sha256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");/* 执行任务 1: 创建aws v4签名的规范请求字符串. */String canonicalURL = prepareCanonicalRequest();/* 执行任务 2: 创建用来认证的字符串 4. */String stringToSign = prepareStringToSign(canonicalURL);/* 执行任务 3: 计算签名. */String signature = calculateSignature(stringToSign);if (signature != null) {Map<String, String> header = new HashMap<String, String>(0);header.put("x-amz-date", xAmzDate);header.put("Authorization", buildAuthorizationString(signature));header.put("x-amz-content-sha256", generateHex(payload));System.out.println("##Signature:n" + signature);System.out.println("##Header:");for (Map.Entry<String, String> entrySet : Set()) {System.out.Key() + ":" + Value());}System.out.println("================================");return header;} else {System.out.println("##Signature:n" + signature);return null;}}/*** 连接前几步处理的字符串生成Authorization header值.** @param strSignature* @return*/private String buildAuthorizationString(String strSignature) {return HMACAlgorithm + " "+ "Credential=" + accessKeyID + "/" + getDate() + "/" + regionName + "/" + serviceName + "/" + aws4Request + ", "+ "SignedHeaders=" + strSignedHeader + ", "+ "Signature=" + strSignature;}/*** 将字符串16进制化.* Hex(SHA256Hash(<payload>)** @param data* @return*/private String generateHex(String data) {MessageDigest messageDigest;try {messageDigest = Instance("SHA-256");messageDigest.Bytes("UTF-8"));byte[] digest = messageDigest.digest();return String.format("%064x", new java.math.BigInteger(1, digest));} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {e.printStackTrace();}return null;}/*** 以给定的key应用HmacSHA256算法处理数据.** @param data* @param key* @return* @throws Exception* @reference: .html#signature-v4-examples-java*/private byte[] HmacSHA256(byte[] key, String data) throws Exception {String algorithm = "HmacSHA256";Mac mac = Instance(algorithm);mac.init(new SecretKeySpec(key, algorithm));return mac.Bytes("UTF8"));}/*** 获取AWS 签名密钥** @param key* @param date* @param regionName* @param serviceName* @return* @throws Exception* @reference .html#signature-v4-examples-java*/private byte[] getSignatureKey(String key, String date, String regionName, String serviceName) throws Exception {byte[] kSecret = ("AWS4" + key).getBytes("UTF8");byte[] kDate = HmacSHA256(kSecret, date);byte[] kRegion = HmacSHA256(kDate, regionName);byte[] kService = HmacSHA256(kRegion, serviceName);byte[] kSigning = HmacSHA256(kService, aws4Request);return kSigning;}final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();/*** 将字节数组转换为16进制字符串** @param bytes* @return*/private static String bytesToHex(byte[] bytes) {char[] hexChars = new char[bytes.length * 2];for (int j = 0; j < bytes.length; j++) {int v = bytes[j] & 0xFF;hexChars[j * 2] = hexArray[v >>> 4];hexChars[j * 2 + 1] = hexArray[v & 0x0F];}return new String(hexChars).toLowerCase();}/*** 获取yyyyMMdd'T'HHmmss'Z'格式的当前时间** @return*/private String getTimeStamp() {DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");dateFormat.TimeZone("UTC"));//server timezonereturn dateFormat.format(new Date());}/*** 获取yyyyMMdd格式的当前日期** @return*/private String getDate() {DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");dateFormat.TimeZone("UTC"));//server timezonereturn dateFormat.format(new Date());}/*** @param input* @param encodeSlash* @return*/private String uriEncode(CharSequence input, boolean encodeSlash) {//对于中文还没有处理(需要与encodeParameter做对比进行分析)StringBuilder result = new StringBuilder();for (int i = 0; i < input.length(); i++) {char ch = input.charAt(i);if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' || ch == '-' || ch == '~' || ch == '.') {result.append(ch);} else if (ch == '/') {result.append(encodeSlash ? "%2F" : ch);} else {result.append(byteToHexUTF8(ch));}}String();}//    public static byte[] charToByteArray(char c){
//        byte[] b = new byte[2];
//        b[0] = (byte) ((c & 0xFF00) >> 8);
//        b[1] = (byte) (c & 0xFF);
//        return b;
//    }private String byteToHexUTF8(char c) {Charset charset = Charset.forName("utf-8");CharBuffer charBuffer = CharBuffer.allocate(1);charBuffer.put(c);charBuffer.flip();//字符编码为字节数组ByteBuffer byteBuffer = de(charBuffer);byte[] bytes = byteBuffer.array();StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i < bytes.length; i++) {stringBuffer.append("%").HexString(bytes[i] & 0xFF).toUpperCase());}String();}
  • 请求代码

@Slf4j
@Component
public class AWSV4AuthUtil {@Resourceprivate S3Configure s3Configure;/*** 如果没有传入其它的key,则表示使用admin账户进行操作* @param uri* @param method* @param querys* @param body* @param accessKeyID* @param secretAccessKey* @return*/public Map<String, String> getHeaders(String uri, String method, TreeMap<String, String> querys,String body, String accessKeyID, String secretAccessKey) {TreeMap<String, String> awsHeaders = new TreeMap();awsHeaders.put("host", Hostname());AWSV4Auth.Builder builder;if (NullUtil.isNull(accessKeyID) || NullUtil.isNull(secretAccessKey)) {builder = new AWSV4Auth.AccessKey(), SecretKey());} else {builder = new AWSV4Auth.Builder(accessKeyID, secretAccessKey);}ionName("us-east-1").serviceName("s3").httpMethodName(method).canonicalURI(uri).queryParametes(querys).awsHeaders(awsHeaders).payload(body).build().getHeaders();}/*** caps: user read* @param uid* @param accessKeyID* @param secretAccessKey* @return*///查询某个用户public FindOneUserR findOneUser(String uid, String accessKeyID, String secretAccessKey) {String uri = "/admin/user";TreeMap<String, String> queyrs = new TreeMap();queyrs.put("uid", uid);Map<String, String> header = getHeaders(uri, "GET", queyrs, null, accessKeyID, secretAccessKey);String entityString;try {HttpResponse httpResponse = HttpUtils.doGet("" + Hostname(), uri, header, queyrs);if (200 != StatusLine().getStatusCode()) {return null;}HttpEntity httpEntity = Entity();entityString = String(httpEntity,"utf-8");} catch (Exception e) {throw new MyException("解析某个用户错误!");}FindOneUserR findUserR = MyObject(entityString, FindOneUserR.class);return findUserR;}
}

 

 

 

 

 

 

 

本文发布于:2024-02-05 05:11:57,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170724928663336.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:算法   地方   aws   java   Header
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23