在本地开发,Intellij Idea运行的是嵌入式tomcat,测试时签名没有任何问题。
发布到阿里云服务器上测试时,发现客户端和服务器端的签名不一致,总是导致认证失败。进一步排查,发现是参数值包含中文时才导致签名不一致。
当时用的是ios客户端,开始怀疑是AFNetworking框架处理中文参数的问题,后来用web前端调用接口,依然存在问题。所以排查不是客户端处理中文字符的问题。
于是判断是不是tomcat8+springboot的问题,参考以下文章的处理,问题依然存在:
springboot全局字符编码设置(解决乱码问题)
Spring boot http编码配置(CharacterEncodingFilter)
tomcat7和tomcat8中文乱码问题
也排除中文乱码的问题,因为其实tomcat8和springBoot默认都是采取UTF-8编码。
最后仔细看ios端签名的算法:
+ (NSString *)MD5String:(NSString *)str
{
const char* inString = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
NSMutableString *outStrg = [NSMutableString string];
CC_MD5(inString, (CC_LONG)strlen(inString), result);
unsigned int i;
for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[outStrg appendFormat:@"%02x", result[i]];
}
return [outStrg copy];
}
const char* inString = [str UTF8String];
这一行将字符串转换成utf-8再md5。
再看看java服务器端的md5算法:
public static String md5(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
byte[] after = md.digest();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < after.length; ++i) {
sb.append(Integer.toHexString((after[i] & 240) >> 4));
sb.append(Integer.toHexString((after[i] & 15) >> 0));
}
return sb.toString();
} catch (NoSuchAlgorithmException var5) {
throw new RuntimeException(var5);
}
}
md.update(str.getBytes());
str.getBytes()在本地开发环境默认获取的是UTF-8编码的字节,所以开发环境没有出现问题。
但部署到阿里云服务器后,获取的就不是UTF-8编码的字节了。
所以必须指定编码为UTF-8:
md.update(str.getBytes("utf-8"));
签名不一致的问题就解决了。