ios摘要认证编程

第一部分:http认证介绍


摘要认证 digest authentication   ← HTTP1.1提出的基本认证的替代方法

    服务器端以nonce进行质询,客户端以用户名,密码,nonceHTTP方法,请求的URI等信息为基础产生的response信息进行认证的方式。

     不包含密码的明文传递

    

    摘要认证步骤:

     1. 客户端访问一个受http摘要认证保护的资源。

     2. 服务器返回401状态以及nonce等信息,要求客户端进行认证。

HTTP/1.1 401 Unauthorized

WWW-Authenticate: Digest

realm="testrealm@host.com",

qop="auth,auth-int",

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",

opaque="5ccc069c403ebaf9f0171e9517f40e41"

     3. 客户端将以用户名,密码,nonce值,HTTP方法, 和被请求的URI为校验值基础而加密(默认为MD5算法)的摘要信息返回给服务器。

           认证必须的五个情报:

     ? realm : 响应中包含信息

     ? nonce  响应中包含信息

     ? username  用户名

     ? digest-uri  请求的URI

     ? response  以上面四个信息加上密码信息,使用MD5算法得出的字符串。


Authorization: Digest 

username="Mufasa",   客户端已知信息

realm="testrealm@host.com",    服务器端质询响应信息

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  ← 服务器端质询响应信息

uri="/dir/index.html",  客户端已知信息

qop=auth,    服务器端质询响应信息

nc=00000001,  客户端计算出的信息

cnonce="0a4f113b",  客户端计算出的客户端nonce

response="6629fae49393a05397450978507c4ef1",  最终的摘要信息 ha3

opaque="5ccc069c403ebaf9f0171e9517f40e41"   服务器端质询响应信息

     4. 如果认证成功,则返回相应的资源。如果认证失败,则仍返回401状态,要求重新进行认证。


    特记事项:

     1. 避免将密码作为明文在网络上传递,相对提高了HTTP认证的安全性。

     2. 当用户为某个realm首次设置密码时,服务器保存的是以用户名,realm,密码为基础计算出的哈希值(ha1),而非密码本身。

     3. 如果qop=auth-int,在计算ha2时,除了包括HTTP方法,URI路径外,还包括请求实体主体,从而防止PUTPOST请求表示被人篡改。

     4. 但是因为nonce本身可以被用来进行摘要认证,所以也无法确保认证后传递过来的数据的安全性。


    nonce:随机字符串,每次返回401响应的时候都会返回一个不同的nonce 

    nounce:随机字符串,每个请求都得到一个不同的nounce 

       MD5(Message Digest algorithm 5,信息摘要算法)

          用户名:realm:密码  ha1

          HTTP方法:URI  ha2

          ha1:nonce:nc:cnonce:qop:ha2  ha3


上面摘自:http://blog.csdn.net/hotnet522/article/details/5824716  作者:hotnet522


第二部分:摘要认证在ios中实现


备注:我实现的摘要认证是针对某一个特定的服务器。如果是别的服务器我觉得步骤大同小异,有什么不对请多多指教。


第一步:先发一个请求给服务器:

第二步:从-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response方法中得到状态码401.然后编码[request1 addValue:auth forHTTPHeaderField:@"Authorization"];

注意我当时auth字符串中

 Authorization = "Digest realm="tms",nonce="dG46MTM5MjgzNTY3ODgxMjoxNzIuMTcuMS4xNDc6MjRiZDM5OTRkM2IzZGNjNTY0ZmJjNDU1NzhiZmFiZmM=",qop=auth,username="Mobile1@domain.xx",uri="http://168.1.1.1:3080/TMS/GetDeviceList",response="5a9b68a86de1bafaad5da3f1e59b33e1",cnonce="13927765621396831105",nc=0000001D,algorithm="MD5"";

中添加了\r\n。结果Authorization显示不出来。


第三步:再重新请求发给同一个服务器地址。



demo


viewController.m

#import "HttpConnection"


-(void)click

{

    NSString *urlStr = @"http://192.168.1.1:3080/TconfS/put?ID=Mobile1@xx.yy&Type=Environment_MB";

    

    HttpConnection*con = [[[HttpConnection alloc]init]autorelease];

    con.delegate = self;

    [con downLoadFromUrl:urlStr];//调用HttpConnection.m类中的方法

}


HttpConnection.h


#import


@class HttpConnection;

@protocol HttpConnectionDelegate


-(void)downloadComplete:(HttpConnection*)hc;

-(void)downloadFail:(HttpConnection*)hc;


@end


@interface HttpConnection : NSObject,NSURLConnectionDataDelegate>

{

   

}


@property(nonatomic,assign)id<>HttpConnectionDelegate>delegate;

@property(nonatomic,retain)NSMutableData *downloadData;

-(void)downLoadFromUrl:(NSString *)urlStr;

@end



HttpConnection.m


#import "HttpConnection.h"

#import "NSString+Hashing.h"//这个是MD5算法类


@implementation HttpConnection

{

    

    NSString *_account;

    NSString *_password;

    NSInteger _statusCode;

    NSURLConnection * _urlConnect;

    

}


@synthesize delegate=_delegate;

@synthesize downloadData=_downloadData;


- (void)dealloc

{

    [_downloadData release];

    _downloadData = nil;

    

    if (_urlConnect) {

        [_urlConnect cancel];

        [_urlConnect release];

        _urlConnect = nil;

    }

    

    [super dealloc];

}


-(id)init

{

    if(self = [super init])

    {

        _downloadData = [[NSMutableData alloc]initWithCapacity:0];

     }

    return self;

}


//下载

-(void)downLoadFromUrl:(NSString *)urlStr

{

    NSString *rePath = nil;

    

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:[urlStrstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];//使用utf-8编码以防网址上有中文

    

    _account = @"Mobile@xx.yy";

    _password = @"123456";


     [request setHTTPMethod:@"get"];

     [request setValue:_account forHTTPHeaderField:@"From"];


    [NSURLConnection connectionWithRequest:request delegate:self];

    [request release];

    

}


#pragma mark -

#pragma mark - NSUrlConnect delegate method


-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

    NSLog(@"did receive data");

    [UIApplication sharedApplication].networkActivityIndicatorVisible=YES;

    [_downloadData appendData:data];

    

}


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    NSLog(@"did receive response");

    _statusCode = [(NSHTTPURLResponse*)response statusCode];

    [_downloadData setLength:0];

    

    NSLog(@"statusCode = %d",_statusCode);

    if (_statusCode == 401) {

        NSLog(@"401认证");

        

        NSString *urlStr = @"http://192.168.1.1:3080/TconfS/put?ID=Mobile1@xx.yy&Type=Environment_MB";

        

        NSMutableURLRequest *request1 = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];

        

      NSString *auth = [self handle401Code:(NSHTTPURLResponse*)response];//注意此auth中不含有\r\n.

        

        [request1 addValue:auth forHTTPHeaderField:@"Authorization"];

        [request1 setValue:_account forHTTPHeaderField:@"From"];

        [request1 setHTTPMethod:@"get"];

        [NSURLConnection connectionWithRequest:request1 delegate:self];

        [request1 release];


    }

    

}


-(void)connectionDidFinishLoading:(NSURLConnection *)connection

{

    NSLog(@"did finish loading");    

    [UIApplication sharedApplication].networkActivityIndicatorVisible=NO;

    if (_statusCode == 200) {

        [_delegate downloadComplete:self];//回调到上层去解析服务器上的数据。

    }

    

}


-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

    

    NSLog(@"did fail error:%@",error);


    if (_statusCode == 404) {

        [_delegate downloadFail:self];

    }

    

}


#pragma mark 解析401得到Authorization字段


-(NSString*)handle401Code:(NSHTTPURLResponse *)response

{

    NSString *wwwAuthenticate = [[response allHeaderFields ]objectForKey:@"Www-Authenticate"];

    NSString *realm = nil;

    NSString *qop = nil;

    NSString*nonce = nil;

    NSString *opaque = nil;

    //解析wwwAuthenticate

    NSArray *arr = [wwwAuthenticate componentsSeparatedByString:@","];

    for (NSString *perStr in arr) {

        NSRange range= [perStr rangeOfString:@"="];

        //提取=后面的

        NSString *perStrFirst = [perStr substringToIndex:range.location];

        NSString *perStrSecond =[perStr substringWithRange:NSMakeRange(range.location+range.length+1,perStr.length-range.location-range.length-2)];

        if ([perStrFirst rangeOfString:@"realm"].location != NSNotFound) {

            realm = perStrSecond;

            NSLog(@"realm = %@",realm);

        }

        if ([perStrFirst rangeOfString:@"qop"].location != NSNotFound) {

            qop = perStrSecond;

            NSLog(@"qop = %@",qop);

        }

        if ([perStrFirst rangeOfString:@"nonce"].location != NSNotFound) {

            nonce=perStrSecond;

            NSLog(@"nonce = %@",nonce);

        }

        if ([perStrFirst rangeOfString:@"opaque"].location != NSNotFound) {

            opaque=perStrSecond;

            NSLog(@"opaque = %@",nonce);

        }

    }

    

    // 以从1970年到现在时间差作为branch的值

    NSTimeInterval time = [[NSDate date]timeIntervalSince1970];

    long long int t = (long long int)time;

    NSString *cnonce = [[[NSString alloc]initWithFormat:@"%lld%d",t,arc4random()+10000]autorelease];

    NSString *algorithm = @"MD5";

    

    NSString *uri = @"http://192.168.1.1:3080/TconfS/put?ID=Mobile1@xx.yy&Type=Environment_MB"

    

    NSString *method = @"GET";

    static unsigned int ncCnt = 1;

    NSString *nc = [[NSString alloc]initWithFormat:@"X",ncCnt++];

    NSString *md5First = [[[NSStringalloc]initWithFormat:@"%@:%@:%@",_account,realm,_password.MD5Hash]autorelease];

    

    

    NSString *md5Second = [[[NSString alloc]initWithFormat:@"%@:%@",method,uri]autorelease];

    NSString *responseStr = [[[NSStringalloc]initWithFormat:@"%@:%@:%@:%@:%@:%@",md5First.MD5Hash,nonce,nc,cnonce,qop,md5Second.MD5Hash]autorelease];

    

    NSString *response11 = responseStr.MD5Hash;

    NSString *authorization = nil;

    if (opaque != nil) {

        authorization = [[[NSString alloc]initWithFormat:@"Digest realm="%@",nonce="%@",qop=%@,username="%@",uri="%@",response="%@",cnonce="%@",nc=%@,opaque="%@",algorithm="%@"",realm,nonce,qop,_account,uri,response11,cnonce,nc,opaque,algorithm]autorelease];

        

    }else{

        authorization = [[[NSString alloc]initWithFormat:@"Digest realm="%@",nonce="%@",qop=%@,username="%@",uri="%@",response="%@",cnonce="%@",nc=%@,algorithm="%@"",realm,nonce,qop,_account,uri,response11,cnonce,nc,algorithm]autorelease];

        

    }

    return authorization;

    

}


@end


 

************************************************************************************************************************************

背景:项目做的差不多了,不过在http认证这块有一个很大的隐患:当第一个启动程序时 http认证没有问题,之后当程序安装到手机上时,再次启动就有可能出现循环401 并且代码没变 用户名和密码都没错。终于有时间下定决心好好研究这块


第一:第一次运行xcode,把程序安装到iphone模拟器上,使用Wireshark抓包发现:401-401-》200 ok。两次401,一次200 ok。

当程序装到iphone虚拟器上时,再次运行xcode,使用Wireshark抓包发现:401-401-27304 ok。两次401,一次27304.ok。

疑问:为什么会出现两次401呢,我检查程序中我只实现一次。


决定重新研究一下401这块,看苹果sdk发现

1.Authentication Challenges and TLS Chain Validation

An NSURLRequest object often encounters an authentication challenge, or a request for credentials from the server it is connecting to. The NSURLSessionNSURLConnection, and NSURLDownload classes notify their delegates when a request encounters an authentication challenge, so that they can act accordingly.

Important: The URL loading system classes do not call their delegates to handle request challenges unless the server response contains a WWW-Authenticate header. Other authentication types, such as proxy authentication and TLS trust validation do not require this header.

URL调用系统类除非是服务器响应中带有www-Authenticate 头域,否则不会使代理来处理请求挑战。


2.Deciding How to Respond to an Authentication Challenge

If an NSURLRequest object requires authentication, the way that the challenge is presented to your app varies depending on whether the request is performed by an NSURLSession object, an NSURLConnection object, or an NSURLDownload object:

  • If the request is associated with an NSURLSession object, all authentication requests are passed to the delegate, regardless of authentication type.
  • If the request is associated with an NSURLConnection or NSURLDownload object, that object’s delegate receives a connection:canAuthenticateAgainstProtectionSpace: (or download:canAuthenticateAgainstProtectionSpace:message. This allows the delegate to analyze properties of the server, including its protocol and authentication method, before attempting to authenticate against it. If your delegate is not prepared to authenticate against the server’s protection space, you can return NO, and the system attempts to authenticate with information from the user’s keychain.
  • If the delegate of an NSURLConnection or NSURLDownload object does not implement the connection:canAuthenticateAgainstProtectionSpace: (or download:canAuthenticateAgainstProtectionSpace:) method and the protection space uses client certificate authentication or server trust authentication, the system behaves as if you had returned NO. The system behaves as if you returned YES for all other authentication types.

Next, if your delegate agrees to handle authentication and there are no valid credentials available, either as part of the requested URL or in the shared NSURLCredentialStorage, the delegate receives one of the following messages:


3.备注:If connection:willSendRequestForAuthenticationChallenge: is not implemented, the older, deprecated methodsconnection:canAuthenticateAgainstProtectionSpace:, connection:didReceiveAuthenticationChallenge:, andconnection:didCancelAuthenticationChallenge: are called instead.


4.Responding to an Authentication Challenge

Providing Credentials

To attempt to authenticate, the application should create an NSURLCredential object with authentication information of the form expected by the server. You can determine the server’s authentication method by calling authenticationMethod on the protection space of the provided authentication challenge. Some authentication methods supported by NSURLCredential are:

  • HTTP basic authentication (NSURLAuthenticationMethodHTTPBasic) requires a user name and password. Prompt the user for the necessary information and create an NSURLCredential object with credentialWithUser:password:persistence:.
  • HTTP digest authentication (NSURLAuthenticationMethodHTTPDigest), like basic authentication, requires a user name and password. (The digest is generated automatically.) Prompt the user for the necessary information and create an NSURLCredential object with credentialWithUser:password:persistence:.
  • Client certificate authentication (NSURLAuthenticationMethodClientCertificate) requires the system identity and all certificates needed to authenticate with the server. Create an NSURLCredential object with credentialWithIdentity:certificates:persistence:.
  • Server trust authentication (NSURLAuthenticationMethodServerTrust) requires a trust provided by the protection space of the authentication challenge. Create an NSURLCredential object with credentialForTrust:.

After you’ve created the NSURLCredential object:

  • For NSURLSession, pass the object to the authentication challenge’s sender using the provided completion handler block.
  • For NSURLConnection and NSURLDownload, pass the object to the authentication challenge’s sender with useCredential:forAuthenticationChallenge:.


5.An Authentication Example


The implementation shown in Listing 6-1 responds to the challenge by creating an NSURLCredential instance with a user name and password supplied by the application’s preferences. If the authentication has failed previously, it cancels the authentication challenge and informs the user.

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

{

    NSLog(@"willSendRequestForAuthenticationChallenge");

    if ([challenge previousFailureCount]== 0) {

        NSLog(@"previous FailureCount == 0");

        NSURLCredential*credential = [NSURLCredential credentialWithUser:_accountpassword:_password.MD5Hash persistence:NSURLCredentialPersistenceForSession];

        [[challenge sender]useCredential:credential forAuthenticationChallenge:challenge];


    }else{

        NSLog(@"认证失败");

        [[challenge sender]cancelAuthenticationChallenge:challenge];


    }

    

}


6.demo:

#pragma mark -

#pragma mark - NSUrlConnect delegate method


-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

{

   //新浪怎么了,自动屏蔽我的注释 -_-

    NSLog(@"willSendRequestForAuthenticationChallenge");

    if ([challenge previousFailureCount]== 0) {

        NSLog(@"previous FailureCount == 0");

        NSURLCredential*credential = [NSURLCredential credentialWithUser:_accountpassword:_password.MD5Hash persistence:NSURLCredentialPersistenceForSession];

        [[challenge sender]useCredential:credential forAuthenticationChallenge:challenge];


    }else{

        NSLog(@"认证失败");

        [[challenge sender]cancelAuthenticationChallenge:challenge];


    }

    

}


-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

    NSLog(@"did receive data");

    [UIApplication sharedApplication].networkActivityIndicatorVisible=YES;

    [_downloadData appendData:data];

    

}


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

{

    NSLog(@"did receive response");


}


-(void)connectionDidFinishLoading:(NSURLConnection *)connection

{

    NSLog(@"did finish loading");    

    [UIApplication sharedApplication].networkActivityIndicatorVisible=NO;

    if (_statusCode == 200) {

        [_delegate downloadComplete:self];//回调到上层去解析服务器上的数据。

    }

    

}


-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

{

    NSLog(@"did fail error:%@",error);

}


//通过上面输出可以看出这是http 摘要认证。_password.MD5Hash用户密码传的是经过md5编码后的,因为服务器上的密码也是经过md5使用的。

原理很简单:当发送一个异步request时,收到response里面含有www-Authenticate头域,则执行connection:willSendRequestForAuthenticationChallenge:方法,发送给server,再次收到response才进入到connection: didReceiveResponse:函数中执行。

总结:

1.网络编程时多使用wireshark这样的抓包工具来进行抓包测试。

2.iphone的sDK还需要细心的读。其实第一次在connection: didReceiveResponse:里面截图到401进行重新发送request时,我已经看到上述方法是用在http 基本认证中,当时不是很理解再加上在NSCredential类中的password没有进行md5编码就放弃了,改用在didReceiveResponse中处理401.才造成两次发送401的局面。还是应该锲而不舍。

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值