All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.com.antcloud.api.common.GwSigns Maven / Gradle / Ivy

Go to download

Ant Fin Tech API SDK For Java Copyright (c) 2015-present Alipay.com, https://www.alipay.com

The newest version!
/*
 * Copyright (c) 2015-present Alipay.com, https://www.alipay.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.com.antcloud.api.common;

import cn.com.antcloud.api.utils.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.com.antcloud.api.common.SDKConstants.BASE64URL;

public class GwSigns {

    private static final Logger  logger           = LoggerFactory.getLogger(GwSigns.class);
    private static final Pattern ENCODED_CHARACTERS_PATTERN;
    private static final String  DEFAULT_ENCODING = "UTF-8";

    static {
        StringBuilder pattern = new StringBuilder();

        pattern.append(Pattern.quote("+")).append("|").append(Pattern.quote("*")).append("|")
            .append(Pattern.quote("%7E")).append("|").append(Pattern.quote("%2F"));

        ENCODED_CHARACTERS_PATTERN = Pattern.compile(pattern.toString());
    }

    public static List signKeyFilter(Map params) {
        List keys = new ArrayList();
        // 对签名参数进行过滤,除去
        for (Map.Entry item : params.entrySet()) {
            if (item.getValue() == null || !item.getValue().startsWith(BASE64URL)) {
                keys.add(item.getKey());
            }
        }
        return keys;
    }

    /**
     * 对参数进行签名
     *
     * @param params    the params
     * @param algorithm the algorithm
     * @param secret    the secret
     * @param charset   the charset
     * @return the string
     * @throws NoSuchAlgorithmException the no such algorithm exception
     * @throws InvalidKeyException      the invalid key exception
     */
    public static String sign(Map params, String algorithm, String secret,
                              Charset charset) throws NoSuchAlgorithmException,
                                               InvalidKeyException {
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(secret.getBytes(charset), algorithm));
        List keys = signKeyFilter(params);

        Collections.sort(keys);

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            if (i != 0) {
                mac.update("&".getBytes(charset));
            }
            mac.update(urlEncode(key).getBytes(charset));
            mac.update("=".getBytes(charset));
            mac.update(urlEncode(params.get(key)).getBytes(charset));
        }

        byte[] signData = mac.doFinal();

        return Base64.encodeToString(signData, false);
    }

    /**
     * 对字符串进行签名
     *
     * @param text      the text
     * @param algorithm the algorithm
     * @param secret    the secret
     * @param charset   the charset
     * @return the string
     * @throws InvalidKeyException      the invalid key exception
     * @throws NoSuchAlgorithmException the no such algorithm exception
     */
    public static String sign(String text, String algorithm, String secret,
                              Charset charset) throws InvalidKeyException,
                                               NoSuchAlgorithmException {
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(secret.getBytes(charset), algorithm));
        byte[] signData = mac.doFinal(text.getBytes(charset));
        return Base64.encodeToString(signData, false);
    }

    /**
     * 从产品返回的Response中抽取需要签名的字段。
     * Response中的固定格式为:{"response": RESPONSE_JSON, "sign": SIGN_STRING}
     * 其中RESPONSE_JSON为需要签名的字段,SIGN_STRING为产品返回的签名
     *
     * @param responseString the response string
     * @return the string
     */
    public static String extractStringToSign(String responseString) {
        String responseNodeKey = "\"response\"";
        String signNodeKey = "\"sign\"";

        int indexOfResponseNode = responseString.indexOf(responseNodeKey);
        int indexOfSignNode = responseString.lastIndexOf(signNodeKey);

        if (indexOfResponseNode < 0) {
            return null;
        }

        if (indexOfSignNode < 0 || indexOfSignNode < indexOfResponseNode) {
            indexOfSignNode = responseString.lastIndexOf('}') - 1;
        }

        int startIndex = responseString.indexOf('{',
            indexOfResponseNode + responseNodeKey.length());
        int endIndex = responseString.lastIndexOf("}", indexOfSignNode);

        // XXX: 这里可以用JSON解析一下这个子串,看他是不是合法的JSON
        try {
            return responseString.substring(startIndex, endIndex + 1);
        } catch (IndexOutOfBoundsException e) {
            logger.error(responseString);
            logger.error("{}, {}", startIndex, endIndex);
            throw e;
        }
    }

    /**
     * 在JsonString中添加签名字段
     *
     * @param responseString the response string
     * @param sign           the sign
     * @return the string
     */
    public static String attachSign(String responseString, String sign) {
        String signNodeKey = "\"sign\"";
        int indexOfSignNode = responseString.lastIndexOf(signNodeKey);
        if (indexOfSignNode < 0) {
            return null;
        }

        int indexOfOpenQuote = responseString.indexOf('"', indexOfSignNode + signNodeKey.length());
        int indexOfCloseQuote = responseString.indexOf('"', indexOfOpenQuote + 1);
        return responseString.substring(0, indexOfOpenQuote + 1) + sign
               + responseString.substring(indexOfCloseQuote);
    }

    /**
     * url编码
     *
     * @param value the response string
     * @return the string
     */
    public static String urlEncode(final String value) {
        if (value == null) {
            return "";
        }

        try {
            String encoded = URLEncoder.encode(value, DEFAULT_ENCODING);

            Matcher matcher = ENCODED_CHARACTERS_PATTERN.matcher(encoded);
            StringBuffer buffer = new StringBuffer(encoded.length());

            while (matcher.find()) {
                String replacement = matcher.group(0);

                if ("+".equals(replacement)) {
                    replacement = "%20";
                } else if ("*".equals(replacement)) {
                    replacement = "%2A";
                } else if ("%7E".equals(replacement)) {
                    replacement = "~";
                }

                matcher.appendReplacement(buffer, replacement);
            }

            matcher.appendTail(buffer);
            return buffer.toString();

        } catch (UnsupportedEncodingException ex) {
            throw new RuntimeException(ex);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy