URL Session Programming Guide中重要的类如下:
在Networking Overview——Making HTTP and HTTPS Requests中的配置身份认证(Configuring Authentication),摘录如下:
对于NSURLSession
,代理对象要实现URLSession:task:didReceiveChallenge:completionHandler:
方法。
对于NSURLConnection
类:
connection:willSendRequestForAuthenticationChallenge:
方法。connection:canAuthenticateAgainstProtectionSpace:
和connection:didReceiveAuthenticationChallenge:
方法。URL Session Programming Guide中的Authentication Challenges and TLS Chain Validation
有如何响应认证请求?(Deciding How to Respond to an Authentication Challenge)
NSURLSession
: 所有的认证请求都被传递给代理对象,不论它是什么认证类型NSURLConnection
或者NSURLDownload
: 代理对象收到connection:canAuthenticateAgainstProtectionSpace:
(或者download:canAuthenticateAgainstProtectionSpace:
)消息,允许代理,在尝试来验证它之前,来分析服务器的属性,包括它的协议和认证方法。如果代理不打算来验证服务器的protection space,返回NO。然后系统会尝试从用户的keychain来验证信息。NSURLConnection
或者NSURLDownload
的代理没有实现connection:canAuthenticateAgainstProtectionSpace:
(或者download:canAuthenticateAgainstProtectionSpace:
)方法,protection space使用客户端证书认证(client certificate authentication)或者服务器信任认证server trust authentication),系统的行为就像你返回了NO。系统的行为就像对其它的所有的认证类型,你返回的是YES。接下来,如果代理同意处理认证,并且没有可用的有效证书,无论是请求URL的一部分或者是NSURLCredentialStorage
中的共享。代理会收到下面其中之一的消息:
URLSession:didReceiveChallenge:completionHandler:
URLSession:task:didReceiveChallenge:completionHandler:
connection:didReceiveAuthenticationChallenge:
download:didReceiveAuthenticationChallenge:
为了继续连接,代理有如下的三个选择:
响应connection:didReceiveAuthenticationChallenge:
代理方法,有如下3种方式
为了认证,要创建一个NSURLCredential
对象。在提供的authentication challenge的protection space上调用authenticationMethod
方法,可以获取服务器的认证方法。NSURLCredential支持的认证方法有:
NSURLAuthenticationMethodHTTPBasic
) 需要一个用户名和密码。使用 credentialWithUser:password:persistence:
方法创建NSURLCredential
对象。NSURLAuthenticationMethodHTTPDigest
),与basic authentication类似,也需要一个用户名和密码。使用 credentialWithUser:password:persistence:
方法创建NSURLCredential
对象。NSURLAuthenticationMethodClientCertificate
) 需要system identity和需要与server进行身份验证的所有证书。使用credentialWithIdentity:certificates:persistence:
创建NSURLCredential
对象。NSURLAuthenticationMethodServerTrust
) 需要authentication challenge的protection space提供一个trust。使用credentialForTrust:
来创建NSURLCredential
对象。创建NSURLCredential
对象之后:
NSURLSession
,在completion handler中,把NSURLCredential
对象传递给authentication challenge的sender。NSURLConnection
和 NSURLDownload
,使用useCredential:forAuthenticationChallenge:
方法,把NSURLCredential
对象传递给authentication challenge的sender。如果代理选择不提供证书,可选择如下方式来继续:
NSURLSession
,传递如下之一的值给completion handler回调: NSURLSessionAuthChallengePerformDefaultHandling
处理请求,就好像代理没有提供一个代理方法来处理认证请求NSURLSessionAuthChallengeRejectProtectionSpace
拒接认证请求。基于服务器响应的认证类型,URL加载类可能会多次调用代理方法。NSURLConnection
和 NSURLDownload
,在[challenge sender]
上调用continueWithoutCredentialsForAuthenticationChallenge:
方法。不提供证书的话,可能会导致连接失败,调用connectionDidFailWithError:
方法 ,或者会返回一个不需要验证身份的替代的URL。代理也可以选择取消认证请求(authentication challenge)
NSURLSession
,传递NSURLSessionAuthChallengeCancelAuthenticationChallenge
到提供的completion handler中。NSURLConnection
和 NSURLDownload
,在[challenge sender]
上调用cancelAuthenticationChallenge:
。代理会收到connection:didCancelAuthenticationChallenge:
消息。下面的例子使用预先设置的用户名和密码来创建NSURLCredential
。如果身份认证先前失败过,就取消认证请求并通知用户。
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:[self preferencesName]
password:[self preferencesPassword]
persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential
forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
[self showPreferencesCredentialsAreIncorrectPanel:self];
}
}
如果代理没有实现connection:didReceiveAuthenticationChallenge:
方法,并且请求需要认证,URL credential storage中需存在有效的证书或者必须在请求的URL中提供。如果没有证书或者验证失败,代理会调用continueWithoutCredentialForAuthenticationChallenge:
方法。
除了提供证书到服务器,app还可以检查在TLS握手过程中服务器提供的证书,然后告知URL加载系统,是否应该接受或者拒接这些证书。
如果你需要以非标准方式来执行TLS链验证(例如接受一个自签名证书来测试),app应该这样做:
NSURLSession
,实现URLSession:didReceiveChallenge:completionHandler:
或者URLSession:task:didReceiveChallenge:completionHandler:
代理方法。如果你两个都实现,session-level方法负责处理身份认证。NSURLConnection
和 NSURLDownload
,实现connection:canAuthenticateAgainstProtectionSpace:
或者download:canAuthenticateAgainstProtectionSpace:
方法,如果 protection space有一个认证类型是NSURLAuthenticationMethodServerTrust
,返回YES。 connection:didReceiveAuthenticationChallenge:
或者download:didReceiveAuthenticationChallenge:
来处理身份认证。在身份认证处理方法中,要检查challenge的protection space是否有NSURLAuthenticationMethodServerTrust
类型,如果有,就从protection space中获取serverTrust
信息。
更多详细信息,请参考Overriding TLS Chain Validation Correctly
相关内容请参加HTTPS Server Trust Evaluation
protection space (also realm) — An HTTP or HTTPS server, or an area on such a server, that requires authentication. Within Foundation this is represented by the
NSURLProtectionSpace
class. See also authentication challenge.
NSURLProtectionSpace
表示需要认证的服务器或者域。
《iOS网络高级编程:iPhone和iPad的企业应用开发》书中介绍如下:
“最佳实践是使用NSURLProtectionSpace
验证手机银行应用的用户与安全的银行服务器进行通信,特别是在发出的请求会操纵后端数据时更是如此”
创建方式如下:
NSURLProtectionSpace *space = [[NSURLProtectionSpace alloc] initWithHost:@"67.205.6.121"
port:443
protocol:NSURLProtectionSpaceHTTPS
realm:@"mobilebanking"
authenticationMethod:NSURLAuthenticationMethodClientCertificate];
所有支持的认证方法有:
使用服务器的属性创建了保护空间后,就可以用于验证连接。在代码向需要认证的服务器请求资源时,服务器会使用HTTP状态码401进行响应,即访问拒绝。NSURLConnection会接收到响应并立刻使用认证challenge的一份副本来发送一条willSendRequestForAuthenticationChallenge:
委托消息。过程如下所示:
NSURLAuthenticationChallenge
encapsulates a challenge from a server requiring authentication from the client.
authentication challenge — An HTTP or HTTPS response indicating that the server requires authentication information from the client(服务器从客户端请求的验证信息). Foundation represents this with the
NSURLAuthenticationChallenge
class, and it also uses this infrastructure to support custom HTTPS server trust evaluation. An authentication challenge originates from a protection space.
NSURLCredential
代表的是一个身份验证证书。URL Loading系统支持3种类型的证书:password-based user credentials, certificate-based user credentials, and certificate-based server credentials。
NSURLCredential
适合大多数的认证请求,因为它可以表示由用户名/密码组合、客户端证书及服务器信任创建的认证信息。
认证信息有三种持久化选项:
认证指的是确认访问系统的用户身份的过程。对于手机银行应用的服务层来说,最重要的事情就是要能分辨出真实用户与虚假用户之间的差别。
手机银行应用有两种认证模式:
手机银行应用的标准认证模式使用HTTP Basic认证,而快速认证则使用从Web Service下载的客户端证书。
Basic、Digest与NTLM认证都是基于用户名/密码的认证。他们认证的响应逻辑是相同的。
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// validate that the authentication challenge came from a whitelisted protection space
if (![[[Model sharedModel] validProtectionSpaces] containsObject:challenge.protectionSpace]) {
// dispatch alert view message to the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:@"Unsecure Connection"
message:@"We're unable to establish a secure connection. Please check your network connection and try again."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
});
// cancel authentication
[challenge.sender cancelAuthenticationChallenge:challenge];
}
// respond to basic authentication requests
// others that follow this pattern include DIGEST and NTLM authentication
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic) {
// proceed with authentication
if (challenge.previousFailureCount == 0) {
NSURLCredential *creds = [[NSURLCredential alloc] initWithUser:_username
password:_password
persistence:NSURLCredentialPersistenceForSession];
[challenge.sender useCredential:creds forAuthenticationChallenge:challenge];
// authentication has previously failed. depending on authentication configuration, too
// many attempts here could lead to a poor user experience via locked accounts
} else {
// cancel the authentication attempt
[[challenge sender] cancelAuthenticationChallenge:challenge];
// alert observers of the failed attempt
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kNormalLoginFailedNotification object:nil];
});
}
}
}
基本认证请参考HTTP协议 (二) 基本认证