| package cc.mrbird.febs.pay.util; | 
|   | 
| import cc.mrbird.febs.common.exception.JPException; | 
| import cc.mrbird.febs.pay.model.Request; | 
| import cc.mrbird.febs.pay.model.Response; | 
| import cc.mrbird.febs.pay.model.SignTypeEnum; | 
| import cn.hutool.core.util.ObjectUtil; | 
| import com.alipay.service.schema.util.StringUtil; | 
|   | 
| import java.lang.reflect.Field; | 
| import java.util.*; | 
|   | 
| /** | 
|  * 签名、验签的工具类 | 
|  * @author chenyf | 
|  * @date 2018-12-15 | 
|  */ | 
| public class SignUtil { | 
|     public final static String SIGN_SEPARATOR = "&";//分隔符 | 
|     public final static String SIGN_EQUAL = "=";//等于号 | 
|     public final static String SIGN_KEY_PARAM_NAME = "key"; | 
|     public final static List<String> NOT_SIGN_PARAM = Arrays.asList(new String[]{"sign","aesKey","aes_key","sec_key"});//不参与签名/验签的参数 | 
|   | 
|     /** | 
|      * 验证签名 | 
|      * @param response | 
|      * @param key | 
|      * @return | 
|      */ | 
|     public static boolean verify(Response response, String key) throws Exception { | 
|         String signStr = getSortedString(response); | 
|         if(SignTypeEnum.MD5.getValue().equals(response.getSign_type())){ | 
|             signStr = HEXUtil.encode(genMD5Sign(signStr, key), true); | 
|             if(signStr.equals(response.getSign())){ | 
|                 return true; | 
|             }else{ | 
|                 return false; | 
|             } | 
|         }else if(SignTypeEnum.RSA.getValue().equals(response.getSign_type())){ | 
|             return RSAUtil.verify(signStr, key, HEXUtil.decode(response.getSign()), true); | 
|         }else{ | 
|             return false; | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 生成签名 | 
|      * @param request | 
|      * @param key | 
|      * @return | 
|      */ | 
|     public static void sign(Request request, String key) throws Exception { | 
|         if(ObjectUtil.isEmpty(request)){ | 
|             return; | 
|         }else if(StringUtil.isEmpty(request.getMch_id()) || StringUtil.isEmpty(request.getSign_type())){ | 
|             request.setSign(""); | 
|             return; | 
|         } | 
|   | 
|         if(StringUtil.isEmpty(request.getRand_str())){ | 
|             request.setRand_str(RandomUtil.get32LenStr()); | 
|         } | 
|   | 
|         String signStr = getSortedString(request); | 
|   | 
|         if(SignTypeEnum.MD5.getValue().equals(request.getSign_type())){ | 
|             signStr = HEXUtil.encode(genMD5Sign(signStr, key), true); | 
|         }else if(SignTypeEnum.RSA.getValue().equals(request.getSign_type())){ | 
|             signStr = HEXUtil.encode(RSAUtil.sign(signStr, key, true)); | 
|         }else{ | 
|             //抛出签名失败的异常 | 
|             throw new JPException("签名失败,未预期的签名类型:"+request.getSign_type()); | 
|         } | 
|         request.setSign(signStr); | 
|     } | 
|   | 
|     protected static String getSortedString(Object obj) throws Exception { | 
|         Field[] fields = obj.getClass().getDeclaredFields(); | 
|   | 
|         Map<String, String> map = new HashMap<String, String>(); | 
|         for(int i=0; i<fields.length; i++){ | 
|             Field filed = fields[i]; | 
|             String name = filed.getName(); | 
|             if(NOT_SIGN_PARAM.contains(name)){//不参与签名或验签的参数直接跳过 | 
|                 continue; | 
|             } | 
|             filed.setAccessible(true); | 
|             map.put(name, String.valueOf(filed.get(obj))); | 
|         } | 
|   | 
|         StringBuffer content = new StringBuffer(); | 
|         List<String> keys = new ArrayList(map.keySet()); | 
|         Collections.sort(keys); // 排序map | 
|         for (int i = 0; i < keys.size(); i++) { | 
|             String key = keys.get(i); | 
|             String value = map.get(key); | 
|   | 
|             if(i != 0){ | 
|                 content.append(SIGN_SEPARATOR); | 
|             } | 
|             content.append(key).append(SIGN_EQUAL).append(value); | 
|         } | 
|         return content.toString(); | 
|     } | 
|   | 
|     private static byte[] genMD5Sign(String signStr, String key){ | 
|         return MD5Util.getMD5(signStr + SIGN_SEPARATOR + SIGN_KEY_PARAM_NAME + SIGN_EQUAL + key); | 
|     } | 
| } |