您的位置:首页 > 移动开发 > IOS开发

IOS中json字符串原生数据请求&IOS跨平台AES128字符串加解密&AFNetworking框架的简单封装使用

2016-07-15 19:57 761 查看
@废话在前



IOS开发中原始的数据请求是以字符串的形式,字符串参数传到服务器,然后接收服务器返回的字符串进行解析。

通常一个完整的数据请求过程中数据处理经如下几个阶段:

1.制作参数,用NSDictionary封装,即一个son对象;

2.json对象转成json字符串;

3.字符串加密成密文(可选);

4.将json字符串(或加密后的密文)作为参数发送请求;

5.接受服务器返回的数据NSData,并转成字符串;

6.字符串解密(可选);

7.json字符串转json对象(NSDictionary);

一.IOS原生数据请求与数据解析

这里建立一个IOS原生session回话任务封装一个post请求(post请求更安全常用):

//
//  RequestSingleton.h
//  JXHDemo
//
//  Created by Xinhou Jiang on 6/12/16.
//  Copyright © 2016 Jiangxh. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface RequestSingleton : NSObject

/**
*  获取QueuesSingleton单例对象
*/
+ (RequestSingleton *)Ins;

/**
* 原生POST请求(最基础的请求参数是字符串,这里原生的请求参数是一个json字符串)
*/
- (void) POST: (NSString *)url param: (NSString *)param success:(void(^)(id json))success failure: (void(^)(NSError *error))flaiure;

@end

//
//  RequestSingleton.m
//  JXHDemo
//
//  Created by Xinhou Jiang on 6/12/16.
//  Copyright © 2016 Jiangxh. All rights reserved.
//

#import "RequestSingleton.h"

@interface RequestSingleton()

/**
* session,创建一个共用的即可
*/
@property(nonatomic, strong)NSURLSession *session;

@end

@implementation RequestSingleton

/**
*  获取单例对象
*/
+ (RequestSingleton *)Ins
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}

/**
*  init
*/
- (id)init
{
if (self = [super init])
{
// 通用session
_session = [NSURLSession sharedSession];
}
return self;
}

/**
* 原生POST请求, 客可对此进一步封装,进行参数的拼接,加密等等
*/
- (void)POST:(NSString *)url param:(NSString *)param success:(void (^)(id json))success failure:(void (^)(NSError *))flaiure {
// url对象
NSURL *URL = [NSURL URLWithString:url];
// request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
// post请求
request.HTTPMethod = @"POST";
// 参数
request.HTTPBody = [param dataUsingEncoding:NSUTF8StringEncoding];
// 请求超时
request.timeoutInterval = 30;

//根据会话对象创建一个发送请求Task
NSURLSessionDataTask *dataTask = [_session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

// 解析数据, 将NSData转成json对象
id json = [self decrypeJsonWithData:data];

// 如果error为nil说明没有网络错误,请求成功
if (!error) {
// 将数据上抛传出去
success(json);
// 打印
NSLog(@"返回数据:%@",json);
}else {
// 网络错误,请求失败,包括请求超时等等
flaiure(error);
}
}];

//执行任务
[dataTask resume];
}

/**
*  NSData转JSON对象
*/
- (id)decrypeJsonWithData:(NSData *)data
{
// 1. 转成字符串
NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// 2. 解密
// 如果是加密传输在这里进行解密

// 3. 转成json对象
return [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
}

@end


使用方法是将上面的类加入工程,然后调用单例类的类函数即可:

#import "RequestSingleton.h"
/**
* 原生网络请求测试示例
*/
- (void)request {
// 1.服务器url接口
NSString *url = @"";
// 2.制作参数
NSMutableDictionary *paramDic = [[NSMutableDictionary alloc]init];
[paramDic setObject:@"919575700@qq.com" forKey:@"username"];
[paramDic setObject:@"jxh123" forKey:@"password"];
// 转成json字符串,用到MJExtension归档插件
NSString *param = [paramDic JSONString];
// post请求
[[RequestSingleton Ins] POST:url param:param success:^(id json) {
// 请求成功
} failure:^(NSError *error) {
// 请求错误
}];
}


二.AES128加解密(解决ios与服务器等其他平台加密密文尾巴不一致的问题)



加密解密的函数封装在下面的工具类中(其中用到了谷歌的GTMBase64编码工具类可网上自行下载):

#import <Foundation/Foundation.h>

@interface DES3Util : NSObject

// 加密
+ (NSString*) AES128Encrypt:(NSString *)plainText;
// 解密
+ (NSString*) AES128Decrypt:(NSString *)encryptText;

@end
#import "DES3Util.h"
#import <CommonCrypto/CommonCryptor.h>
#import "GTMBase64.h"

@implementation DES3Util

// 加密
+(NSString *)AES128Encrypt:(NSString *)plainText
{
char keyPtr[kCCKeySizeAES128+1];
memset(keyPtr, 0, sizeof(keyPtr));
[AES128Key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

char ivPtr[kCCBlockSizeAES128+1];
memset(ivPtr, 0, sizeof(ivPtr));
[AES128Iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];

NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];

int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
int newSize = 0;

if(diff > 0)
{
newSize = (int)dataLength + diff;
}

char dataPtr[newSize];
memcpy(dataPtr, [data bytes], [data length]);
for(int i = 0; i < diff; i++)
{
dataPtr[i + dataLength] = 0x00;
}

size_t bufferSize = newSize + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
memset(buffer, 0, bufferSize);

size_t numBytesCrypted = 0;

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x0000,               //No padding
keyPtr,
kCCKeySizeAES128,
ivPtr,
dataPtr,
sizeof(dataPtr),
buffer,
bufferSize,
&numBytesCrypted);

if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];

return [GTMBase64 stringByEncodingData:resultData];
}
free(buffer);
return nil;
}

// 解密
+(NSString *)AES128Decrypt:(NSString *)encryptText
{
char keyPtr[kCCKeySizeAES128 + 1];
memset(keyPtr, 0, sizeof(keyPtr));
[AES128Key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

char ivPtr[kCCBlockSizeAES128 + 1];
memset(ivPtr, 0, sizeof(ivPtr));
[AES128Iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];

NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);

size_t numBytesCrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
0x0000,
keyPtr,
kCCBlockSizeAES128,
ivPtr,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesCrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
free(buffer);
return nil;
}

@end
实际应用中会发现上面的加解密方法在ios本地没有问题,但和服务器加密的密文尾巴不一致,导致服务器无法解析,需要对密文进行特殊字符的处理,在发送请求前将加密的参数密文经过下面的函数处理一下即可:

/**
*  aes128加密后的密文编码处理,参数为128加密后的密文
*/
- (NSString *)AES128Convert: (NSString *)aes128 {

NSString *charactersToEscape = @"!*'();:@&=+$,/?%#[]\" ";
NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];

return [aes128 stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
}


三.AFNetworking网络请求框架的使用



AFNetworking框架基础介绍:http://blog.csdn.net/cordova/article/details/51614695

未完待续... ...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: