iOS实现HTTP认证之摘要认证-Digest

2020-09-04  本文已影响0人  一意孤行的程序猿

收录:shenshi_bing

什么是Digest?

摘要访问认证是一种协议规定的Web服务器用来同网页浏览器进行认证信息协商的方法。它在密码发出前,先对其应用哈希函数,这相对于HTTP基本认证发送明文而言,更安全。 从技术上讲,摘要认证是使用随机数来阻止进行密码分析的MD5加密哈希函数应用.

1. 基本流程

  1. 客户端发起GET(PUT、POST、DELETE...)请求
  2. 服务器响应401 Unauthorized,WWW-Authenticate指定认证算法,realm指定安全域
  3. 客户端重新发起请求,Authorization指定用户名和密码信息
  4. 服务器认证成功,响应200,可选Authentication-Info 如下图所示

2.basic和digest的区别

3.具体操作流程

第一步

第二步

第三步

第四步

第五步

第六步

代码实现 *注:nonceStr 声明一个全局的NSString来接收请求的nonce

-(void)getRequest{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
//以GET请求为例,以下方法为封装的配置方法
    [self setHttpHeaderDigestURI:identifier requestType:RequestType_GET nonce:self.nonceStr];
NSURLSession *session = [NSURLSession sharedSession];
//发送请求
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:self.request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSDictionary * pFieldd =[(NSHTTPURLResponse*)response allHeaderFields];
        NSInteger statusCode =[(NSHTTPURLResponse*)response statusCode];
        if (statusCode == 401) {//digest auth
            NSString * strAuthenticate = [pFieldd valueForKey:@"Www-Authenticate"];
            if ([strAuthenticate containsString:@"nonce="]) {
                NSArray *arr = [strAuthenticate componentsSeparatedByString:@"nonce="];
                NSArray *newArr = [[arr lastObject] componentsSeparatedByString:@","];
                NSMutableString *newStr = [NSMutableString stringWithString:[newArr firstObject]] ;
                if (newStr.length >= 3) {
                    [newStr replaceCharactersInRange:NSMakeRange(0, 1) withString:@""];
                    [newStr replaceCharactersInRange:NSMakeRange(newStr.length - 1, 1) withString:@""];
                }
                NSString *nonce = newStr ;
                weakself.nonceStr = nonce;
                weakself.count += 1;
                if (weakself.count > 3) {
                    weakself.count = 0;
                    [weakself error:error finishedBlock:finishedBlock];
                }else{
                    [weakself sendGetRequestWithParams:params getValues:values resultType:type finishedBlock:finishedBlock];
                }
            }else{
                [weakself error:error finishedBlock:finishedBlock];
            }
        }else{
            NSError *error;
            NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
            if (responseObject && [responseObject isKindOfClass:[NSDictionary class]]) {
                if (finishedBlock) {
                    finishedBlock(CODE_JSON_OK,responseObject);
                    NSError *error;
                    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:&error];
                    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                }
            }else{
                if (finishedBlock) {
                    if (responseObject != nil) {
                        finishedBlock(CODE_ERROR_JSON, responseObject);
                    }else{
                        finishedBlock(CODE_ERROR_JSON, @"responseObject为nil");
                    }
                }
            }
        }
    }];
    //执行任务
    [dataTask resume];
    }
    //配置请求的header
-(void)setHttpHeaderDigestURI:(NSString *)digestURI requestType:(RequestType)requestType nonce:(NSString *)nonce{
    NSString *username = @"ApiAdmin";
    NSString *password = @"xxx";
    NSString *realm = @"xxx.com";
    NSString *method ;
    switch (requestType) {
        case RequestType_POST:{
            method = @"POST";
        }
            break;
        case RequestType_GET:{
            method = @"GET";
        }
            break;
        case RequestType_PUT:{
            method = @"PUT";
        }
            break;
        case RequestType_DELETE:{
            method = @"DELETE";
        }
            break;
        default:
            break;
    }
    //修改请求方法
    self.request.HTTPMethod = method;
    //此字符串可任意
    nonce = @"9e6146023a70bdb0b4d1da795a029990";
    if (nonce.length > 0) {
        nonce = self.nonceStr;
        self.nonceStr = nil;
    }
    //这里是SHA256加密如果你是MD5或者其他的可自由切换
    NSString *HA1 = [[NSString stringWithFormat:@"%@:%@:%@",username,realm,password] SHA256];
    NSString *HA2 = [[NSString stringWithFormat:@"%@:%@",method,digestURI] SHA256];
    NSString *sha265 = [NSString stringWithFormat:@"%@:%@:%@",HA1,nonce,HA2];
    NSString *algorithm = @"SHA-256";
    NSString *response = [sha265 SHA256];
    NSString *authorization = [NSString stringWithFormat:@"Digest username=\"%@\", realm=\"%@\", nonce=\"%@\", uri=\"%@\", algorithm=\"%@\", response=\"%@\"",username,realm,nonce,digestURI,algorithm,response];
    [self.request setValue:authorization forHTTPHeaderField:@"Authorization"];
    [self.request  setValue :@"application/soap+xml;charset=utf-8"  forHTTPHeaderField:@"Content-Type" ] ;
}

顺便送上SHA256加密的方法,新建一个NSString的category,实现方法如下

#import "NSString+SHA256.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString (SHA256)

- (NSString *)SHA256
{
    const char *s = [self cStringUsingEncoding:NSUTF8StringEncoding];
    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
    uint8_t digest[CC_SHA256_DIGEST_LENGTH] = {0};
    CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
    NSData *out = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
    const unsigned *hashBytes = [out bytes];
    NSString *hash = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                      ntohl(hashBytes[0]), ntohl(hashBytes[1]), ntohl(hashBytes[2]),
                      ntohl(hashBytes[3]), ntohl(hashBytes[4]), ntohl(hashBytes[5]),
                      ntohl(hashBytes[6]), ntohl(hashBytes[7])];
    return hash;
}

看到这里你基本上已经明白什么是Digest 和 怎么实现了。 感谢 https://www.jianshu.com/p/18fb07f2f65e 给我的一些帮助!

当你从不了解到熟悉的过程才是提升的过程,不要胆怯,勇敢的去追寻!

结交人脉

最后推荐个我的iOS交流群:789143298
'有一个共同的圈子很重要,结识人脉!里面都是iOS开发,全栈发展,欢迎入驻,共同进步!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)

上一篇 下一篇

猜你喜欢

热点阅读