这个文章的目的是, 我希望用postman测试一下andnext的接口, 结果发现里面有几个小问题, 折腾了一下(确切的说是折腾了一天).
1. 是之前文档里面写道, 敏感数据, 比如注册用的密码, 需要加密, 加密方法是Base64, 我试了直接Base64, 拿来加密, 根本不行, 仔细看了一下, 加上后来看了新的在线的文档, 说是"HEX", 就是把byte[]转成了16进制的字符串, 要拿出来得到RSA的公钥,需要先将这个HEX的字符串还原成byte数组, byte是16位的, 16bit, 即字符串的每两个byte组成一个byte, 比如, 它的public key加密后是, 打个比方"30820122300D0609....", 那么, 30, 80, 01, 22...每两位就是一个16进制的byte, 要每两个字符一组, 转成一个byte数组, 当作java security的RSA的X509EncodedKeySpec的构造方法公钥输入.
private byte[] hexToString(String hexStr) { //先搞清楚数组长度, 是字符串的长度的1/2
int arrayLeng = hexStr.length() / 2;
System.out.println(arrayLeng); //建结果数组
byte[] sourceByteArray = new byte[arrayLeng];
int counter = 0;
for (int i = 0; i < arrayLeng; i++) {
//(getDecimal(hexStr.substring(i, i = i + 1))) * 16+getDecimal(hexStr.substring(i, i = i + 1)); //每两个字符拿出来, 组成一个byte, 这里很容易就晕菜了, 因为数据结构101告诉我们, 每个字符是8bit,两个字符是16个bit,怎么又还原成一个byte. //方法就是拿第一个出来, 升高位, 再补低位
int temp = (getDecimal(hexStr.substring(counter, counter + 1))) * 16 + getDecimal(hexStr.substring(counter + 1, counter + 2));
// System.out.println("temp: " + temp);
byte b = (byte) (temp);
//System.out.println("b: " + b);
sourceByteArray[i] = b;
//System.out.println("" + i + " : " + sourceByteArray[i]);
counter = counter + 2;
}
return sourceByteArray;
}
这个方法把单独的看上去像16进制的字符, 例如01234EFAB转成一个int
public static int getDecimal(String hex) {
String digits = "0123456789ABCDEF";
hex = hex.toUpperCase();
int val = 0;
for (int i = 0; i < hex.length(); i++) {
char c = hex.charAt(i);
int d = digits.indexOf(c);
val = 16 * val + d;
}
return val;
}
你可以理解成这整个hexToString的方法, 代替了Base64的decode, 因为默认RSA拿到公钥字符串是用Base64将字符串进行decode成byte数组之后来使用的, 这个hexStringToArray的方法, 代替了decode的过程.
2. 拿到公钥, 加密完敏感信息, 还要用同样或者反向的方法, 把加密后的数据, 用16进制的字符串形式作为post的数据.
private static String byteArrayToHexString(byte[] sourceArray) {
String resultStr = "";
StringBuilder sb = new StringBuilder();
for (byte b : sourceArray) {
sb.append(String.format("%02X", b));
}
resultStr = sb.toString();
return resultStr;
}
所有敏感数据都要经过RSA之后, 再用这个(奇葩的)编码方式编码.
3. 顺利(或者不顺利)的完成注册, 需要调用认证接口的时候, 第二个难关是公共请求头, 他们的认证方法是, 需要AppId, 需要时间码加随机字符作为message, 用AppSecret作为密钥, 这个信息可以找我或者阿楠要.
然后用HmacSHA256加密, 结果再HEX一下, 当作签名Signature, HmacSHA256是什么鬼我没细研究, 估计跟MD5差不多, 算摘要的, 单向, 拿来做签名使.
另外, 所有的必要选项都要放在请求头里面, 不然就会各种"token过期"的错误:
如图, 记住, Signature最后也要转成HEX字符串形式.
public void SHA356Test() {
try { //secret就是AppSecret,阿楠那里有
String secret = "dfb00303-f6bc-4fdf.....";
String randomStr = getRandomString(12);
System.out.println("随机字符串长度为" + randomStr.getBytes().length); //根据文档的说法, message是时间码加上随机字符
String message = new Date().getTime() + randomStr;
System.out.println(message);
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
System.out.println("hex: " + byteArrayToHexString(sha256_HMAC.doFinal(message.getBytes())));
//String hash = Base64.encode(sha256_HMAC.doFinal(message.getBytes()));
//System.out.println(hash);
} catch (Exception e) {
System.out.println("Error");
}
}
这个"hex"的打印结果跟时间码还是随机字符, 都贴到postman里面, 加上之前登陆成功获得的token, 七七八八, 就能认证成功了, 不行的话, 赶紧来问我, 别重复造轮子浪费时间.