来实作Sign值的计算
我的想法是把要发送到api的request写成一个Object,像这样
import lombok.Data;
@Data
public class OrderCreateReq {
public enum PayType { A, C };
public enum AutoBilling { Y, N };
@Data
public class ATMParam{
private Integer ExpireDate;
}
@Data
public class CardParam{
private AutoBilling AutoBilling;
private Integer ExpBillingDays;
private Integer ExpMinutes;
private String PayTypeSub;
}
private String ShopNo;
private String OrderNo;
private Integer Amount;
private String CurrencyID;
private String PrdtName;
private String Memo;
private String Param1;
private String Param2;
private String Param3;
private String ReturnURL;
private String BackendURL;
private PayType PayType;
private ATMParam ATMParam;
private CardParam CardParam;
}
回到QpayHelper,建一个getSign方法,
到时候我会先用ObjectMapper将OrderCreateReq转为TreeMap,
因此这边先订定接收的是Map物件
因为ObjectMapper会将含有sub object的object转为LinkedHashMap,
我们可以透过指定移除value的class为LinkedHashMap的物件
以此来把多节点参数给拿掉
再来因为转为TreeMap时,透过TreeMap自动排序的特性,已经把map中的key由小到大排列了,不用再多做处理
因此getSign方法只需要:
1.将map转为key1=vale1&key2=value2...这样格式的字串
2.将字串接上nonce、Hash ID
3.最後,只要再用DigestUtils转为sha256、转大写就完成sign了。
private String getSign(Map<String, Object> map,String nonce,String hashid){
//remove sub object
map.values().removeIf(entries->entries.getClass().equals(java.util.LinkedHashMap.class)
||entries.toString().isBlank());
//order
String param=map.entrySet().stream()
.map(p -> p.getKey() + "=" + p.getValue())
.reduce((p1, p2) -> p1 + "&" + p2)
.orElse("");
//convert to string
StringBuilder content = new StringBuilder();
content.append(param).
append(nonce).
append(hashid);
String sign= DigestUtils.sha256Hex(content.toString()).toUpperCase();
return sign;
}
现在Sign也有了,剩下message
依规格书所述,要以AES CBC进行加密,因此先写加密方法
我找了网路上一个简单的AES CBC加密的范例来改写,其他解密之类的之後有需要再补
建一个EncryptUtil.java,传入欲加密的内容、key、iv,回传加密後的Hex字串
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.springframework.stereotype.Component;
@Component
public class EncryptUtil {
public String encrypt(String content, String key,String iv) throws Exception {
byte[] raw = key.getBytes("UTF-8");
SecretKeySpec keySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ips = new IvParameterSpec(iv.getBytes("UTF-8"));
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ips);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Hex.encodeHexString(encrypted);
}
}
东西都准备得差不多,
接下来就可以开始串前面的写的东西了
<<: [day-17] 认识Python的资料结构!(Part .4)
标题参考来源 大家好~ 如果有个表单验证需要大量重复使用的话, 我们可以为此表单验证建立一个 For...
由於我们前面每加入一个 插件(plugin) 就要引入一次 会发现其实超级麻烦 而且会显得程序码非常...
前言 昨天讲了在各个资料库中都通用的权限管理,而今天要则是要谈谈所有 SQL 的头号公敌:SQL i...
学了半个月终於要端出「爆浆濑尿虾牛丸」了吗?要开始让大家体会一下牛肉(MCU)的鲜、濑尿虾(AI)的...
四开四个主题实在太累,ASP.NET Core的学习笔记这个主题,只是想记录一下之前写专案的过程,透...