Explorar el Código

添加 oss-common 公共组建

reghao hace 2 años
padre
commit
519b8b868a

+ 23 - 0
oss-common/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>cn.reghao.oss</groupId>
+    <artifactId>oss-common</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.reghao.jutil</groupId>
+            <artifactId>web</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 408 - 0
oss-common/src/main/java/cn/reghao/oss/common/AWS4Signer.java

@@ -0,0 +1,408 @@
+package cn.reghao.oss.common;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Example: Signing AWS Requests with Signature Version 4 in Java.
+ *
+ * @reference: http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
+ * @author javaQuery
+ * @date 19th January, 2016
+ * @Github: https://github.com/javaquery/Examples
+ */
+public class AWS4Signer {
+    private AWS4Signer() {
+    }
+
+    public static class Builder {
+
+        private String accessKeyID;
+        private String secretAccessKey;
+        private String regionName;
+        private String serviceName;
+        private String xAmzDate;
+        private String httpMethodName;
+        private String canonicalURI;
+        private TreeMap<String, String> queryParametes;
+        private TreeMap<String, String> awsHeaders;
+        private byte[] payload;
+        private String sha256sum;
+
+        public Builder(String accessKeyID, String secretAccessKey) {
+            this.accessKeyID = accessKeyID;
+            this.secretAccessKey = secretAccessKey;
+        }
+
+        public Builder regionName(String regionName) {
+            this.regionName = regionName;
+            return this;
+        }
+
+        public Builder serviceName(String serviceName) {
+            this.serviceName = serviceName;
+            return this;
+        }
+
+        public Builder xAmzDate(String xAmzDate) {
+            this.xAmzDate = xAmzDate;
+            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(byte[] payload) {
+            this.payload = payload;
+            return this;
+        }
+
+        public Builder sha256sum(String sha256sum) {
+            this.sha256sum = sha256sum;
+            return this;
+        }
+
+        public AWS4Signer build() {
+            return new AWS4Signer(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 byte[] payload;
+    private String sha256sum;
+
+    /* 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 AWS4Signer(Builder builder) {
+        accessKeyID = builder.accessKeyID;
+        secretAccessKey = builder.secretAccessKey;
+        regionName = builder.regionName;
+        serviceName = builder.serviceName;
+        httpMethodName = builder.httpMethodName;
+        canonicalURI = builder.canonicalURI;
+        queryParametes = builder.queryParametes;
+        awsHeaders = builder.awsHeaders;
+        payload = builder.payload;
+        sha256sum = builder.sha256sum;
+
+        /* Get current timestamp value.(UTC) */
+        //xAmzDate = getTimeStamp();
+        xAmzDate = builder.xAmzDate;
+        currentDate = getDate();
+    }
+
+    /**
+     * Task 1: Create a Canonical Request for Signature Version 4.
+     *
+     * @return
+     */
+    private String prepareCanonicalRequest() {
+        StringBuilder canonicalURL = new StringBuilder("");
+
+        /* Step 1.1 Start with the HTTP request method (GET, PUT, POST, etc.), followed by a newline character. */
+        canonicalURL.append(httpMethodName).append("\n");
+
+        /* Step 1.2 Add the canonical URI parameter, followed by a newline character. */
+        canonicalURI = canonicalURI == null || canonicalURI.trim().isEmpty() ? "/" : canonicalURI;
+        canonicalURL.append(canonicalURI).append("\n");
+
+        /* Step 1.3 Add the canonical query string, followed by a newline character. */
+        StringBuilder queryString = new StringBuilder("");
+        if (queryParametes != null && !queryParametes.isEmpty()) {
+            for (Map.Entry<String, String> entrySet : queryParametes.entrySet()) {
+                String key = entrySet.getKey();
+                String value = entrySet.getValue();
+                queryString.append(key).append("=").append(encodeParameter(value)).append("&");
+            }
+
+            /* @co-author https://github.com/dotkebi @git #1 @date 16th March, 2017 */
+            queryString.deleteCharAt(queryString.lastIndexOf("&"));
+
+            queryString.append("\n");
+        } else {
+            queryString.append("\n");
+        }
+        canonicalURL.append(queryString);
+
+        /* Step 1.4 Add the canonical headers, followed by a newline character. */
+        StringBuilder signedHeaders = new StringBuilder("");
+        if (awsHeaders != null && !awsHeaders.isEmpty()) {
+            for (Map.Entry<String, String> entrySet : awsHeaders.entrySet()) {
+                String key = entrySet.getKey();
+                String value = entrySet.getValue();
+                signedHeaders.append(key).append(";");
+                canonicalURL.append(key).append(":").append(value).append("\n");
+            }
+
+            /* Note: Each individual header is followed by a newline character, meaning the complete list ends with a newline character. */
+            canonicalURL.append("\n");
+        } else {
+            canonicalURL.append("\n");
+        }
+
+        /* Step 1.5 Add the signed headers, followed by a newline character. */
+        strSignedHeader = signedHeaders.substring(0, signedHeaders.length() - 1); // Remove last ";"
+        canonicalURL.append(strSignedHeader).append("\n");
+
+        /* Step 1.6 Use a hash (digest) function like SHA256 to create a hashed value from the payload in the body of the HTTP or HTTPS. */
+        canonicalURL.append(sha256sum);
+        /*payload = payload == null ? "UNSIGNED-PAYLOAD".getBytes(StandardCharsets.UTF_8) : payload;
+        try {
+            String sha256Hex = DigestUtil.sha256sum(payload);
+            canonicalURL.append(sha256Hex);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }*/
+
+        return canonicalURL.toString();
+    }
+
+    /**
+     * Task 2: Create a String to Sign for Signature Version 4.
+     *
+     * @param canonicalURL
+     * @return
+     */
+    private String createStringToSign(String canonicalURL) {
+        String stringToSign = "";
+
+        /* Step 2.1 Start with the algorithm designation, followed by a newline character. */
+        stringToSign = HMACAlgorithm + "\n";
+
+        /* Step 2.2 Append the request date value, followed by a newline character. */
+        stringToSign += xAmzDate + "\n";
+
+        /* Step 2.3 Append the credential scope value, followed by a newline character. */
+        stringToSign += currentDate + "/" + regionName + "/" + serviceName + "/" + aws4Request + "\n";
+
+        /* Step 2.4 Append the hash of the canonical request that you created in Task 1: Create a Canonical Request for Signature Version 4. */
+        stringToSign += generateHex(canonicalURL);
+        return stringToSign;
+    }
+
+    /**
+     * Task 3: Calculate the AWS Signature Version 4.
+     *
+     * @param stringToSign
+     * @return
+     */
+    private String calculateSignature(String stringToSign) {
+        try {
+            /* Step 3.1 Derive your signing key */
+            byte[] signatureKey = getSignatureKey(secretAccessKey, currentDate, regionName, serviceName);
+
+            /* Step 3.2 Calculate the signature. */
+            byte[] signature = HmacSHA256(signatureKey, stringToSign);
+
+            /* Step 3.2.1 Encode signature (byte[]) to Hex */
+            String strHexSignature = bytesToHex(signature);
+            return strHexSignature;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * Task 4: Add the Signing Information to the Request. We'll return Map of
+     * all headers put this headers in your request.
+     *
+     * @return
+     */
+    public Map<String, String> getHeaders() {
+        awsHeaders.put("x-amz-date", xAmzDate);
+
+        /* Execute Task 1: Create a Canonical Request for Signature Version 4. */
+        String canonicalURL = prepareCanonicalRequest();
+
+        /* Execute Task 2: Create a String to Sign for Signature Version 4. */
+        String stringToSign = createStringToSign(canonicalURL);
+
+        /* Execute Task 3: Calculate the AWS Signature Version 4. */
+        String signature = calculateSignature(stringToSign);
+        if (signature != null) {
+            Map<String, String> header = new HashMap<>(0);
+            header.put("x-amz-date", xAmzDate);
+            header.put("Authorization", buildAuthorizationString(signature));
+            return header;
+        } else {
+            return null;
+        }
+    }
+
+    public String getSignature() {
+        /* Execute Task 1: Create a Canonical Request for Signature Version 4. */
+        String canonicalURL = prepareCanonicalRequest();
+
+        /* Execute Task 2: Create a String to Sign for Signature Version 4. */
+        String stringToSign = createStringToSign(canonicalURL);
+
+        /* Execute Task 3: Calculate the AWS Signature Version 4. */
+        String signature = calculateSignature(stringToSign);
+        return signature;
+    }
+
+    /**
+     * Build string for Authorization header.
+     *
+     * @param strSignature
+     * @return
+     */
+    private String buildAuthorizationString(String strSignature) {
+        return HMACAlgorithm + " "
+                + "Credential=" + accessKeyID + "/" + getDate() + "/" + regionName + "/" + serviceName + "/" + aws4Request + ","
+                + "SignedHeaders=" + strSignedHeader + ","
+                + "Signature=" + strSignature;
+    }
+
+    /**
+     * Generate Hex code of String.
+     *
+     * @param data
+     * @return
+     */
+    private String generateHex(String data) {
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-256");
+            messageDigest.update(data.getBytes(StandardCharsets.UTF_8));
+            byte[] digest = messageDigest.digest();
+            return String.format("%064x", new java.math.BigInteger(1, digest));
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * Apply HmacSHA256 on data using given key.
+     *
+     * @param data
+     * @param key
+     * @return
+     * @throws Exception
+     * @reference:
+     * http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
+     */
+    private byte[] HmacSHA256(byte[] key, String data) throws Exception {
+        String algorithm = "HmacSHA256";
+        Mac mac = Mac.getInstance(algorithm);
+        mac.init(new SecretKeySpec(key, algorithm));
+        return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
+    }
+
+    /**
+     * Generate AWS signature key.
+     *
+     * @param key
+     * @param date
+     * @param regionName
+     * @param serviceName
+     * @return
+     * @throws Exception
+     * @reference
+     * http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java
+     */
+    private byte[] getSignatureKey(String key, String date, String regionName, String serviceName) throws Exception {
+        byte[] kSecret = ("AWS4" + key).getBytes(StandardCharsets.UTF_8);
+        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();
+
+    /**
+     * Convert byte array to Hex
+     *
+     * @param bytes
+     * @return
+     */
+    private 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();
+    }
+
+    /**
+     * Get timestamp. yyyyMMdd'T'HHmmss'Z'
+     *
+     * @return
+     */
+    private String getTimeStamp() {
+        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
+        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));//server timezone
+        return dateFormat.format(new Date());
+    }
+
+    /**
+     * Get date. yyyyMMdd
+     *
+     * @return
+     */
+    private String getDate() {
+        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));//server timezone
+        return dateFormat.format(new Date());
+    }
+
+    /**
+     * Using {@link URLEncoder#encode(String, String) } instead of
+     * {@link URLEncoder#encode(String) }
+     *
+     * @co-author https://github.com/dotkebi
+     * @date 16th March, 2017
+     * @git #1
+     * @param param
+     * @return
+     */
+    private String encodeParameter(String param){
+        try {
+            return URLEncoder.encode(param, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            return URLEncoder.encode(param, StandardCharsets.UTF_8);
+        }
+    }
+}

+ 154 - 0
oss-common/src/main/java/cn/reghao/oss/common/OssUtil.java

@@ -0,0 +1,154 @@
+package cn.reghao.oss.common;
+
+import cn.reghao.jutil.web.ServletUtil;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.TreeMap;
+
+/**
+ * @author reghao
+ * @date 2023-03-24 13:46:08
+ */
+public class OssUtil {
+    public static String getObjectName() {
+        String uri = ServletUtil.getRequest().getRequestURI();
+        String decodedUri = URLDecoder.decode(uri, StandardCharsets.UTF_8);
+        return decodedUri.replaceFirst("/", "");
+    }
+
+    public static String getAccessKey() {
+        HttpServletRequest servletRequest = ServletUtil.getRequest();
+        String authorization = servletRequest.getHeader("authorization");
+        String[] auths = authorization.split(",");
+        String credential = auths[0].replace("AWS4-HMAC-SHA256 ", "").split("=")[1];
+        String[] strs = credential.split("/");
+        String accessKey = strs[0];
+        return accessKey;
+    }
+
+    public static boolean matchSignature(String secretKey, File file) throws IOException {
+        HttpServletRequest servletRequest = ServletUtil.getRequest();
+        String host = servletRequest.getHeader("host");
+        String contentType = servletRequest.getHeader("content-type");
+        String contentMd5 = servletRequest.getHeader("content-md5");
+        String sha256sum = servletRequest.getHeader("x-amz-content-sha256");
+        String date = servletRequest.getHeader("x-amz-date");
+
+        String authorization = servletRequest.getHeader("authorization");
+        String[] auths = authorization.split(",");
+        String credential = auths[0].replace("AWS4-HMAC-SHA256 ", "").split("=")[1];
+        String[] strs = credential.split("/");
+        String accessKey = strs[0];
+        String date1 = strs[1];
+        String region = strs[2];
+        String service = strs[3];
+        String version = strs[4];
+
+        String[] signedHeaders = auths[1].split("=")[1].split(";");
+        String signature = auths[2].split("=")[1];
+
+        String xAmzDate = servletRequest.getHeader("x-amz-date");
+        TreeMap<String, String> awsHeaders = new TreeMap<>();
+        for (String name : signedHeaders) {
+            servletRequest.getHeader(name);
+            awsHeaders.put(name, servletRequest.getHeader(name));
+        }
+
+        FileInputStream fis = new FileInputStream(file);
+        String method = servletRequest.getMethod();
+        String uri = servletRequest.getRequestURI();
+        AWS4Signer aWSV4Signer = new AWS4Signer.Builder(accessKey, secretKey)
+                .regionName(region)
+                .serviceName(service)
+                .xAmzDate(xAmzDate)
+                .httpMethodName(method)
+                .canonicalURI(uri)
+                .queryParametes(null)
+                .awsHeaders(awsHeaders)
+                .payload(fis.readAllBytes())
+                .build();
+
+        String signature1 = aWSV4Signer.getSignature();
+        return signature.equals(signature1);
+    }
+
+    public static boolean matchSignature(String secretKey, String sha256sum) throws IOException {
+        HttpServletRequest servletRequest = ServletUtil.getRequest();
+        String host = servletRequest.getHeader("host");
+        String contentType = servletRequest.getHeader("content-type");
+        String contentMd5 = servletRequest.getHeader("content-md5");
+        String date = servletRequest.getHeader("x-amz-date");
+
+        String authorization = servletRequest.getHeader("authorization");
+        String[] auths = authorization.split(",");
+        String credential = auths[0].replace("AWS4-HMAC-SHA256 ", "").split("=")[1];
+        String[] strs = credential.split("/");
+        String accessKey = strs[0];
+        String date1 = strs[1];
+        String region = strs[2];
+        String service = strs[3];
+        String version = strs[4];
+
+        String[] signedHeaders = auths[1].split("=")[1].split(";");
+        String signature = auths[2].split("=")[1];
+
+        String xAmzDate = servletRequest.getHeader("x-amz-date");
+        TreeMap<String, String> awsHeaders = new TreeMap<>();
+        for (String name : signedHeaders) {
+            servletRequest.getHeader(name);
+            awsHeaders.put(name, servletRequest.getHeader(name));
+        }
+
+        //FileInputStream fis = new FileInputStream(file);
+        String method = servletRequest.getMethod();
+        String uri = servletRequest.getRequestURI();
+        AWS4Signer aWSV4Signer = new AWS4Signer.Builder(accessKey, secretKey)
+                .regionName(region)
+                .serviceName(service)
+                .xAmzDate(xAmzDate)
+                .httpMethodName(method)
+                .canonicalURI(uri)
+                .queryParametes(null)
+                .awsHeaders(awsHeaders)
+                //.payload(fis.readAllBytes())
+                .sha256sum(sha256sum)
+                .build();
+
+        String signature1 = aWSV4Signer.getSignature();
+        return signature.equals(signature1);
+    }
+
+    public static byte[] getSigningKey(String secretAccessKey, String date, String regionName, String serviceName) throws Exception {
+        byte[] kSecret = ("AWS4" + secretAccessKey).getBytes(StandardCharsets.UTF_8);
+        byte[] kDate = hmacSha256(kSecret, date);
+        byte[] kRegion = hmacSha256(kDate, regionName);
+        byte[] kService = hmacSha256(kRegion, serviceName);
+        byte[] kSigning = hmacSha256(kService, "aws4_request");
+        return kSigning;
+    }
+
+    public static byte[] hmacSha256(byte[] key, String data) throws Exception {
+        String algorithm = "HmacSHA256";
+        Mac mac = Mac.getInstance(algorithm);
+        mac.init(new SecretKeySpec(key, algorithm));
+        return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
+    }
+
+    final static char[] hexArray = "0123456789ABCDEF".toCharArray();
+    public 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();
+    }
+}