2012-04-26 61 views
4

对于我创建的(网络)应用程序,我需要使用基本认证来在我的UIWebView中加载页面。用基本认证加载UIWebView资源

我们设置授权头使用:

NSString *result = [NSString stringWithFormat:@"%@:%@", username, password]; 
NSData *resultData = [result dataUsingEncoding:NSASCIIStringEncoding]; 

NSString *result64 = [NSString stringWithFormat:@"Basic %@", [resultData base64Encoding]]; 
[request setValue:result64 forHTTPHeaderField:@"Authorization"]; 

在我的Apache访问日志,我可以看到登录是成功的。但是,然后UIWebView想要加载资源,如style.cssjquery.min.js,但对这些资源的请求失败,因为它们没有授权标头集。我怎样才能解决这个问题?

回答

4

解决的办法是继承NSURLProtocol来验证资源加载:

#import <Foundation/Foundation.h> 

#import "AuthenticationUtils.h" 

@interface CustomURLProtocol : NSURLProtocol <NSURLConnectionDelegate> 
{ 
    NSMutableURLRequest *_customRequest; 
    NSURLConnection *_connection; 
} 

@end 

@implementation CustomURLProtocol 

static NSString *AUTHORIZED_REQUEST_HEADER = @"X-AUTHORIZED"; 

+(BOOL) canInitWithRequest:(NSMutableURLRequest *)request 
{ 
    // check if the request is one you want to authorize 
    BOOL canInit = (![request.URL.scheme isEqualToString:@"file"] && [request valueForHTTPHeaderField:[AUTHORIZED_REQUEST_HEADER stringByAppendingString:[request.URL absoluteString]]] == nil); 
    return canInit; 
} 

-(id) initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client 
{   
    _customRequest = [request mutableCopy]; 
    [_customRequest setValue:@"" forHTTPHeaderField:[AUTHORIZED_REQUEST_HEADER stringByAppendingString:[request.URL absoluteString]]]; 

    self = [super initWithRequest:_customRequest cachedResponse:cachedResponse client:client]; 

    return self; 
} 

+(NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request 
{ 
    NSMutableURLRequest *customRequest = [request mutableCopy]; 
    [customRequest setValue:@"" forHTTPHeaderField:[AUTHORIZED_REQUEST_HEADER stringByAppendingString:[request.URL absoluteString]]]; 

    NSString *basicAuthentication = [AuthenticationUtils getBasicAuthentication]; 
    [customRequest setValue:basicAuthentication forHTTPHeaderField:@"Authorization"]; 

    return customRequest; 
} 

- (void) startLoading 
{ 
    NSString *basicAuthentication = [AuthenticationUtils getBasicAuthentication]; 
    [_customRequest setValue:basicAuthentication forHTTPHeaderField:@"Authorization"]; 

    _connection = [NSURLConnection connectionWithRequest:_customRequest delegate:self]; 
} 

- (void) stopLoading 
{ 
    [_connection cancel]; 
} 

#pragma mark - NSURLConnectionDelegate 

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    // This protocol forgets to store cookies, so do it manually 
    if([redirectResponse isKindOfClass:[NSHTTPURLResponse class]]) 
    { 
     [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:[NSHTTPCookie cookiesWithResponseHeaderFields:[(NSHTTPURLResponse*)redirectResponse allHeaderFields] forURL:[redirectResponse URL]] forURL:[redirectResponse URL] mainDocumentURL:[request mainDocumentURL]]; 
    } 

    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [[self client] URLProtocol:self didLoadData:data]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    [[self client] URLProtocol:self didFailWithError:error]; 
} 

-(void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    [[self client] URLProtocolDidFinishLoading:self]; 
} 

-(NSURLRequest *) connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse 
{  
    // This protocol forgets to store cookies, so do it manually 
    if([redirectResponse isKindOfClass:[NSHTTPURLResponse class]]) 
    { 
     [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:[NSHTTPCookie cookiesWithResponseHeaderFields:[(NSHTTPURLResponse*)redirectResponse allHeaderFields] forURL:[redirectResponse URL]] forURL:[redirectResponse URL] mainDocumentURL:[request mainDocumentURL]]; 
    } 

    // copy all headers to the new request 
    NSMutableURLRequest *redirect = [request mutableCopy]; 
    for (NSString *header in [request allHTTPHeaderFields]) 
    { 
     [redirect setValue:[[request allHTTPHeaderFields] objectForKey:header] forHTTPHeaderField:header]; 
    } 

    return redirect; 
} 

@end 

而在你的AppDelegate补充一点:

[NSURLProtocol registerClass:[CustomURLProtocol class]]; 
+0

您可以张贴代码片段,显示你是如何使用NSURLProtocol?我有你遇到的同样的问题:) – Stretch 2012-05-15 01:55:24

+1

我将示例代码添加到答案:) – Thys 2012-05-15 08:08:46

+0

+1,谢谢你,非常有用:) – Stretch 2012-05-15 22:56:28