业务需求:把接口传递的参数先排序并MD5加密 生成一个验签字符串
系统会为每个接入的应用系统提供一个唯一的key, 应用系统需要使用这个key和有效的access_token用于生成加密的验签, 接口参数加密方式详细定义如下:
第一步: 设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA(access_token作为其中的一个参数参与验签计算)。
特别注意以下重要规则:
参数名ASCII码从小到大排序(字典序);
如果参数的值为空不参与签名;
版本号参数不参与验签;
参数名区分大小写;
传送的sign参数不参与签名,将生成的签名与该sign值作校验。
接口可能增加字段,验证签名时必须支持增加的扩展字段
第二步: 在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
例如 signValue="flag=1&isWaitDeal=2&pageNo=1&pageSize=10"
以下为整理好的工具类:
导包:
#define CC_MD5_DIGEST_LENGTH 16
#import <CommonCrypto/CommonCrypto.h>
1.排序工具类
20191023修改: 格式化value 去除无value的key
/** wuxifan
对字典(Key-Value)排序 区分大小写
@param dict 要排序的字典
*/
- (NSString *)sortedDictionary:(NSDictionary *)dict{
//将所有的key放进数组
NSArray *allKeyArray = [dict allKeys];
//序列化器对数组进行排序的block 返回值为排序后的数组
NSArray *afterSortKeyArray = [allKeyArray sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id
_Nonnull obj2) {
/**
In the compare: methods, the range argument specifies the
subrange, rather than the whole, of the receiver to use in the
comparison. The range is not applied to the search string. For
example, [@"AB" compare:@"ABC" options:0 range:NSMakeRange(0,1)]
compares "A" to "ABC", not "A" to "A", and will return
NSOrderedAscending. It is an error to specify a range that is
outside of the receiver's bounds, and an exception may be raised.
- (NSComparisonResult)compare:(NSString *)string;
compare方法的比较原理为,依次比较当前字符串的第一个字母:
如果不同,按照输出排序结果
如果相同,依次比较当前字符串的下一个字母(这里是第二个)
以此类推
排序结果
NSComparisonResult resuest = [obj1 compare:obj2];为从小到大,即升序;
NSComparisonResult resuest = [obj2 compare:obj1];为从大到小,即降序;
注意:compare方法是区分大小写的,即按照ASCII排序
*/
//排序操作
NSComparisonResult resuest = [obj1 compare:obj2];
return resuest;
}];
//排序好的字典
NSLog(@"afterSortKeyArray:%@",afterSortKeyArray);
NSString *tempStr = @"";
//通过排列的key值获取value
NSMutableArray *valueArray = [NSMutableArray array];
for (NSString *sortsing in afterSortKeyArray) {
//格式化一下 防止有些value不是string
NSString *valueString = [NSString stringWithFormat:@"%@",[dict objectForKey:sortsing]];
if(valueString.length>0){
[valueArray addObject:valueString];
tempStr=[NSString stringWithFormat:@"%@%@=%@&",tempStr,sortsing,valueString];
}
}
//去除最后一个&符号
if(tempStr.length>0){
tempStr=[tempStr substringToIndex:([tempStr length]-1)];
}
//排序好的对应值
// NSLog(@"valueArray:%@",valueArray);
//最终参数
NSLog(@"tempStr:%@",tempStr);
//md5加密
// NSLog(@"tempStr:%@",[self getmd5WithString:tempStr]);
return tempStr;
}
2.MD5加密工具类
//字符串MD5加密
- (NSString*)getmd5WithString:(NSString *)string
{
const char* original_str=[string UTF8String];
unsigned char digist[CC_MD5_DIGEST_LENGTH]; //CC_MD5_DIGEST_LENGTH = 16
CC_MD5(original_str, (uint)strlen(original_str), digist);
NSMutableString* outPutStr = [NSMutableString stringWithCapacity:10];
for(int i =0; i<CC_MD5_DIGEST_LENGTH;i++){
[outPutStr appendFormat:@"%02X", digist[i]];//小写x表示输出的是小写MD5,大写X表示输出的是大写MD5
}
// return [outPutStr lowercaseString];
return outPutStr;
}
3.测试调用
//生成一个s参数进行验签
NSString *sStr=[self sortedDictionary:request.parameters];
//MD5加密
NSString *sMD5Str=[self getmd5WithString:sStr];
//放到接口参数里
[parameters setObject:sMD5Str forKey:@"s"];
4.截图
s为新生成的验签参数(截图未调用MD5)