GlobalAuthUtil.java 8.7 KB
Newer Older
智布道's avatar
智布道 已提交
1 2 3
package me.zhyd.oauth.utils;

import cn.hutool.core.codec.Base64;
4 5
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
H
Hongwei Peng 已提交
6
import cn.hutool.http.HttpUtil;
7
import com.alibaba.fastjson.JSON;
智布道's avatar
智布道 已提交
8 9 10 11 12
import me.zhyd.oauth.exception.AuthException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
智布道's avatar
智布道 已提交
13
import java.net.URLDecoder;
智布道's avatar
智布道 已提交
14
import java.net.URLEncoder;
15 16
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
智布道's avatar
智布道 已提交
17
import java.security.InvalidKeyException;
18
import java.security.MessageDigest;
智布道's avatar
智布道 已提交
19
import java.security.NoSuchAlgorithmException;
20
import java.util.*;
智布道's avatar
智布道 已提交
21

智布道's avatar
智布道 已提交
22 23 24 25
/**
 * 全局的工具类
 *
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
智布道's avatar
智布道 已提交
26
 * @since 1.0.0
智布道's avatar
智布道 已提交
27
 */
智布道's avatar
智布道 已提交
28
public class GlobalAuthUtil {
29
    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
智布道's avatar
智布道 已提交
30 31
    private static final String ALGORITHM = "HmacSHA256";

32 33 34 35 36 37 38
    /**
     * 生成钉钉请求的Signature
     *
     * @param secretKey 平台应用的授权密钥
     * @param timestamp 时间戳
     * @return Signature
     */
39
    public static String generateDingTalkSignature(String secretKey, String timestamp) {
40 41
        byte[] signData = sign(secretKey.getBytes(DEFAULT_ENCODING), timestamp.getBytes(DEFAULT_ENCODING));
        return urlEncode(new String(Base64.encode(signData, false)));
智布道's avatar
智布道 已提交
42 43
    }

44 45 46 47 48 49 50
    /**
     * 签名
     *
     * @param key  key
     * @param data data
     * @return byte[]
     */
智布道's avatar
智布道 已提交
51 52 53 54 55 56 57 58 59 60 61 62
    private static byte[] sign(byte[] key, byte[] data) {
        try {
            Mac mac = Mac.getInstance(ALGORITHM);
            mac.init(new SecretKeySpec(key, ALGORITHM));
            return mac.doFinal(data);
        } catch (NoSuchAlgorithmException ex) {
            throw new AuthException("Unsupported algorithm: " + ALGORITHM, ex);
        } catch (InvalidKeyException ex) {
            throw new AuthException("Invalid key: " + Arrays.toString(key), ex);
        }
    }

63 64 65 66 67 68
    /**
     * 编码
     *
     * @param value str
     * @return encode str
     */
69
    public static String urlEncode(String value) {
智布道's avatar
智布道 已提交
70 71 72 73
        if (value == null) {
            return "";
        }
        try {
74 75
            String encoded = URLEncoder.encode(value, GlobalAuthUtil.DEFAULT_ENCODING.displayName());
            return encoded.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F");
智布道's avatar
智布道 已提交
76
        } catch (UnsupportedEncodingException e) {
智布道's avatar
智布道 已提交
77 78 79 80
            throw new AuthException("Failed To Encode Uri", e);
        }
    }

81 82 83 84 85 86 87

    /**
     * 解码
     *
     * @param value str
     * @return decode str
     */
智布道's avatar
智布道 已提交
88 89 90 91 92
    public static String urlDecode(String value) {
        if (value == null) {
            return "";
        }
        try {
93
            return URLDecoder.decode(value, GlobalAuthUtil.DEFAULT_ENCODING.displayName());
智布道's avatar
智布道 已提交
94 95 96 97 98
        } catch (UnsupportedEncodingException e) {
            throw new AuthException("Failed To Decode Uri", e);
        }
    }

99 100 101 102 103 104
    /**
     * string字符串转map,str格式为 {@code xxx=xxx&xxx=xxx}
     *
     * @param accessTokenStr 待转换的字符串
     * @return map
     */
智布道's avatar
智布道 已提交
105 106 107 108 109 110 111 112 113 114
    public static Map<String, String> parseStringToMap(String accessTokenStr) {
        Map<String, String> res = new HashMap<>();
        if (accessTokenStr.contains("&")) {
            String[] fields = accessTokenStr.split("&");
            for (String field : fields) {
                if (field.contains("=")) {
                    String[] keyValue = field.split("=");
                    res.put(GlobalAuthUtil.urlDecode(keyValue[0]), keyValue.length == 2 ? GlobalAuthUtil.urlDecode(keyValue[1]) : null);
                }
            }
智布道's avatar
智布道 已提交
115
        }
智布道's avatar
智布道 已提交
116
        return res;
智布道's avatar
智布道 已提交
117
    }
118

119 120 121 122 123 124 125
    /**
     * map转字符串,转换后的字符串格式为 {@code xxx=xxx&xxx=xxx}
     *
     * @param params 待转换的map
     * @param encode 是否转码
     * @return str
     */
126 127 128 129 130 131 132 133 134 135 136 137
    public static String parseMapToString(Map<String, Object> params, boolean encode) {
        List<String> paramList = new ArrayList<>();
        params.forEach((k, v) -> {
            if (ObjectUtil.isNull(v)) {
                paramList.add(k + "=");
            } else {
                String valueString = v.toString();
                paramList.add(k + "=" + (encode ? urlEncode(valueString) : valueString));
            }
        });
        return CollUtil.join(paramList, "&");
    }
138 139 140 141 142 143 144

    /**
     * 将url的参数列表转换成map
     *
     * @param url 待转换的url
     * @return map
     */
H
Hongwei Peng 已提交
145 146 147 148 149
    public static Map<String, Object> parseQueryToMap(String url) {
        Map<String, Object> paramMap = new HashMap<>();
        HttpUtil.decodeParamMap(url, "UTF-8").forEach(paramMap::put);
        return paramMap;
    }
150

151 152 153 154 155 156
    /**
     * 是否为http协议
     *
     * @param url 待验证的url
     * @return true: http协议, false: 非http协议
     */
157 158 159 160 161 162 163
    public static boolean isHttpProtocol(String url) {
        if (StringUtils.isEmpty(url)) {
            return false;
        }
        return url.startsWith("http://");
    }

164 165 166 167 168 169
    /**
     * 是否为https协议
     *
     * @param url 待验证的url
     * @return true: https协议, false: 非https协议
     */
170 171 172 173 174 175
    public static boolean isHttpsProtocol(String url) {
        if (StringUtils.isEmpty(url)) {
            return false;
        }
        return url.startsWith("https://");
    }
176

177 178 179 180 181 182
    /**
     * 是否为本地主机(域名)
     *
     * @param url 待验证的url
     * @return true: 本地主机(域名), false: 非本地主机(域名)
     */
183 184 185 186
    public static boolean isLocalHost(String url) {
        return StringUtils.isEmpty(url) || url.contains("127.0.0.1") || url.contains("localhost");
    }

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    /**
     * 生成饿了么请求的Signature
     * <p>
     * 代码copy并修改自:https://coding.net/u/napos_openapi/p/eleme-openapi-java-sdk/git/blob/master/src/main/java/eleme/openapi/sdk/utils/SignatureUtil.java
     *
     * @param appKey     平台应用的授权key
     * @param secret     平台应用的授权密钥
     * @param timestamp  时间戳,单位秒。API服务端允许客户端请求最大时间误差为正负5分钟。
     * @param action     饿了么请求的api方法
     * @param token      用户授权的token
     * @param parameters 加密参数
     * @return Signature
     */
    public static String generateElemeSignature(String appKey, String secret, long timestamp, String action, String token, Map<String, Object> parameters) {
        final Map<String, Object> sorted = new TreeMap<>();
        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
            sorted.put(entry.getKey(), entry.getValue());
        }
        sorted.put("app_key", appKey);
        sorted.put("timestamp", timestamp);
        StringBuffer string = new StringBuffer();
        for (Map.Entry<String, Object> entry : sorted.entrySet()) {
            string.append(entry.getKey()).append("=").append(JSON.toJSONString(entry.getValue()));
        }
        String splice = String.format("%s%s%s%s", action, token, string, secret);
        String calculatedSignature = md5(splice);
        return calculatedSignature.toUpperCase();
    }

    /**
     * MD5加密饿了么请求的Signature
     * <p>
     * 代码copy并修改自:https://coding.net/u/napos_openapi/p/eleme-openapi-java-sdk/git/blob/master/src/main/java/eleme/openapi/sdk/utils/SignatureUtil.java
     *
     * @param str 饿了么请求的Signature
     * @return md5 str
     */
    private static String md5(String str) {
        MessageDigest md = null;
        StringBuilder buffer = null;
        try {
            md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes(StandardCharsets.UTF_8));
            byte[] byteData = md.digest();
            buffer = new StringBuilder();
            for (byte byteDatum : byteData) {
                buffer.append(Integer.toString((byteDatum & 0xff) + 0x100, 16).substring(1));
            }
        } catch (Exception ignored) {
        }

        return null == buffer ? "" : buffer.toString();
    }

H
harrylee 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    /**
     * 京东md5加密
     * link: https://github.com/pingjiang/jd-open-api-sdk-src/blob/master/src/main/java/com/jd/open/api/sdk/internal/util/CodecUtil.java
     * @param source
     * @return
     * @throws Exception
     */
    public static String jdMd5(String source) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] bytes = md.digest(source.getBytes(StandardCharsets.UTF_8));
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xff);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }
智布道's avatar
智布道 已提交
261
}