我希望在我的UIWebView中支持HTTP Basic Authentication。
目前,我正在取消请求
然后,webView:shouldStartLoadWithRequest:navigationType:
在我自己的NSURLConnectionDelegate中处理它们,以便在需要时检查并提供凭据。然后我使用loadData:MIMEType:textEncodingName:baseURL:
在web视图中显示超文本标记语言。这对于传递给委托的任何URL都很有效。
我的问题是,对于嵌入的元素,比如图像、JavaScript或CSS文件,委托从未被调用过。因此,如果我的HTML页面引用了受基本身份验证保护的图像,则无法正确加载该图像。此外,webView:didFinishLoad:
永远不会被调用,因为web视图无法完全加载页面。
我已经用应用商店上的第三方浏览器Terra验证了这种情况,它完全可以应对这种情况。我认为可以通过提供我自己的NSURLProtocol来解决这个问题,但这似乎太复杂了。我遗漏了什么?
发布于 2012-03-07 02:51:47
尝试对所有需要进行身份验证的域使用sharedCredentialStorage。
以下是UIWebView的工作示例,它是在仅启用BasicAuthentication的Windows IIS上进行测试的
下面是如何添加站点凭据的方法:
NSString* login = @"MYDOMAIN\\myname";
NSURLCredential *credential = [NSURLCredential credentialWithUser:login
password:@"mypassword"
persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost:@"myhost"
port:80
protocol:@"http"
realm:@"myhost" // check your web site settigns or log messages of didReceiveAuthenticationChallenge
authenticationMethod:NSURLAuthenticationMethodDefault];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential
forProtectionSpace:protectionSpace];
[protectionSpace release];
编辑: Swift 4中的相同代码
let login = "MYDOMAIN\\myname"
let credential = URLCredential(user:login, password:"mypassword", persistence:.forSession)
let protectionSpace = URLProtectionSpace(host:"myhost", port:80, protocol:"http", realm:"myhost", authenticationMethod:NSURLAuthenticationMethodDefault)
URLCredentialStorage.shared.setDefaultCredential(credential, for:protectionSpace)
您的webView现在应该可以工作了,如果它不工作,请使用下一步代码进行调试,特别是检查didReceiveAuthenticationChallenge的日志消息。
#import "TheSplitAppDelegate.h"
#import "RootViewController.h"
@implementation TheSplitAppDelegate
@synthesize window = _window;
@synthesize splitViewController = _splitViewController;
@synthesize rootViewController = _rootViewController;
@synthesize detailViewController = _detailViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Add the split view controller's view to the window and display.
self.window.rootViewController = self.splitViewController;
[self.window makeKeyAndVisible];
NSLog(@"CONNECTION: Add credentials");
NSString* login = @"MYDOMAIN\\myname";
NSURLCredential *credential = [NSURLCredential credentialWithUser:login
password:@"mypassword"
persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost:@"myhost"
port:80
protocol:@"http"
realm:@"myhost" // check your web site settigns or log messages of didReceiveAuthenticationChallenge
authenticationMethod:NSURLAuthenticationMethodDefault];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace];
[protectionSpace release];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://myhost/index.html"]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:12
];
NSLog(@"CONNECTION: Run request");
[[NSURLConnection alloc] initWithRequest:request delegate:self];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
- (void)dealloc
{
[_window release];
[_splitViewController release];
[_rootViewController release];
[_detailViewController release];
[super dealloc];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
NSLog(@"CONNECTION: got auth challange");
NSString* message = [NSString stringWithFormat:@"CONNECTION: cred cout = %i", [[[NSURLCredentialStorage sharedCredentialStorage] allCredentials] count]];
NSLog(message);
NSLog([connection description]);
NSLog([NSString stringWithFormat:@"CONNECTION: host = %@", [[challenge protectionSpace] host]]);
NSLog([NSString stringWithFormat:@"CONNECTION: port = %i", [[challenge protectionSpace] port]]);
NSLog([NSString stringWithFormat:@"CONNECTION: protocol = %@", [[challenge protectionSpace] protocol]]);
NSLog([NSString stringWithFormat:@"CONNECTION: realm = %@", [[challenge protectionSpace] realm]]);
NSLog([NSString stringWithFormat:@"CONNECTION: authenticationMethod = %@", [[challenge protectionSpace] authenticationMethod]]);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
// release the connection, and the data object
[connection release];
// inform the user
NSLog(@"CONNECTION: failed! Error - %@ %@",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
{
NSLog(@"CONNECTION: received response via nsurlconnection");
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
{
NSLog(@"CONNECTION: USE!");
return YES;
}
@end
WebView身份验证的最终解决方案是基于自定义协议实现的。所有协议都注册为一个堆栈,因此如果您重新定义HTTP协议,它将拦截来自webView的所有请求,因此您必须检查与传入请求关联的属性,并将其重新打包为新请求,然后通过您自己的连接再次发送。由于你在堆栈中,你的请求会立即再次出现,你必须忽略它。因此,它沿着协议栈向下到真正的HTTP协议实现,因为你的请求没有被认证,你将得到认证请求。在身份验证之后,你会从服务器得到一个真实的响应,所以你需要重新打包响应,并回复从webView收到的原始请求,仅此而已。
不要试图创建新的请求或响应正文,只需重新发送它们即可。最终的代码大约是30-40行代码,它非常简单,但需要大量的调试和调试。
不幸的是,我不能在这里提供代码,因为我已经被分配到不同的项目,我只想说我的帖子是错误的,当用户更改密码时,它卡住了。
发布于 2014-03-28 13:09:39
我刚刚通过使用UIWebView
的NSMutableURLRequest
设置基本身份验证凭据来实现这一点。这也避免了在实现sharedCredentialStorage
时产生的往返(当然需要权衡)。
解决方案:
NSString *url = @"http://www.my-url-which-requires-basic-auth.io"
NSString *authStr = [NSString stringWithFormat:@"%@:%@", username, password];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodedString]];
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[mutableRequest setValue:authValue forHTTPHeaderField:@"Authorization"];
NSURLRequest *request = [mutableRequest copy];
NSURLRequest *request = [NSURLRequest basicAuthHTTPURLRequestForUrl:url];
[self.webView loadRequest:request];
您可以从Matt Gallagher's page获取NSData+Base64类别,它实现了NSData的base64EncodedString
(当我下载它时,它位于博客文章的底部)
发布于 2012-10-15 19:03:51
对于适用于http://kadao.dir.bg/cocoa.htm https://github.com/samvermette/SVWebViewController的TKAURLProtocolPro SVWebViewController
https://stackoverflow.com/questions/8999776
复制相似问题