PAYATHON 2026

多个 View Controller 应如何共享 HTTP Basic Auth delegate?

数据小陈

建议将 HTTP Basic Auth 认证逻辑放在独立对象中,供需要认证的 Web View 共用。各页面也可以通过自己的 delegate 将认证回调转发给这个对象。认证凭据由公共对象管理,设置页面负责编辑。通常不必将这些具体逻辑放进 AppDelegate.m。

原问题没有说明 Web View 的具体类型。下面的代码以 WKWebView 为前提;如果请求由 NSURLSession 发起,需要使用 NSURLSession 对应的认证 delegate。

delegate 能否接到回调,取决于对象绑定

把方法写进 FirstView.m,只会让对应类的实例拥有这个方法。同一项目中的其他 Web View 不会因此自动调用它。

对于 WKWebView,认证回调属于 WKNavigationDelegate。Web View 会把回调发送给它的 navigationDelegate:

webView.navigationDelegate = delegateObject;

需要确认各个 Web View 的 navigationDelegate 指向哪个对象,以及该对象是否实现了认证回调。文件名和方法是否“可见”不能决定回调的接收者。

将认证逻辑放进独立 delegate

如果几个页面的导航行为比较简单,可以让它们共用一个实现 WKNavigationDelegate 的对象。

下面是一个简化示例。它只向指定 HTTPS 主机的 443 端口提交 HTTP Basic Auth 凭据;认证失败后会取消挑战,避免反复提交同一组错误凭据。

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface WebAuthDelegate : NSObject <WKNavigationDelegate>

@property (nonatomic, copy) NSString *allowedHost;
@property (nonatomic, copy) NSString *username;
@property (nonatomic, copy) NSString *password;

@end

@implementation WebAuthDelegate

- (void)webView:(WKWebView *)webView
        didReceiveAuthenticationChallenge:
            (NSURLAuthenticationChallenge *)challenge
        completionHandler:
            (void (^)(NSURLSessionAuthChallengeDisposition disposition,
                      NSURLCredential *credential))completionHandler {
    NSURLProtectionSpace *space = challenge.protectionSpace;

    if (![space.authenticationMethod
            isEqualToString:NSURLAuthenticationMethodHTTPBasic]) {
        completionHandler(
            NSURLSessionAuthChallengePerformDefaultHandling, nil);
        return;
    }

    BOOL trustedEndpoint =
        [space.protocol.lowercaseString isEqualToString:@"https"] &&
        [space.host.lowercaseString
            isEqualToString:self.allowedHost.lowercaseString] &&
        space.port == 443;

    if (!trustedEndpoint ||
        challenge.previousFailureCount > 0 ||
        self.username.length == 0 ||
        self.password == nil) {
        completionHandler(
            NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        return;
    }

    NSURLCredential *credential =
        [NSURLCredential credentialWithUser:self.username
                                  password:self.password
                               persistence:NSURLCredentialPersistenceNone];

    completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}

@end

示例中的主机、端口和凭据检查需要按实际服务配置。如果同一个主机上有多个认证区域,还可以检查 protectionSpace.realm,限定凭据的使用范围。

在共同的上层对象中持有并分发实例

可以由自定义 Tab Bar Controller 或负责组装页面的协调对象创建 WebAuthDelegate,再传给需要认证的页面。

共同的上层对象需要强引用它:

@property (nonatomic, strong) WebAuthDelegate *webAuthDelegate;

初始化时创建一次:

self.webAuthDelegate = [[WebAuthDelegate alloc] init];
self.webAuthDelegate.allowedHost = @"example.com";

example.com 是占位主机,应替换为实际服务地址。随后将同一个实例传给各页面。每个页面可以声明:

@property (nonatomic, strong) WebAuthDelegate *webAuthDelegate;

并在自己的 WKWebView 创建完成后绑定:

self.webView.navigationDelegate = self.webAuthDelegate;

WKWebView 的 navigationDelegate 是弱引用,因此需要其他对象持续持有这个 delegate。如果只在局部变量中创建,delegate 可能被释放,之后就无法接收回调。

设置页面负责修改公共凭据

其他页面应能独立取得认证所需的数据,不必访问 secondView 的界面,也不必等待设置页面加载。

小型项目可以先让共享对象保存当前凭据,在设置页面保存配置时更新它的 username 和 password。项目变复杂后,可以把凭据管理拆成独立服务,让认证处理对象在收到挑战时读取最新值。

如果密码需要持久保存,应使用 Keychain 等适合保存敏感凭据的机制。示例中的 NSURLCredentialPersistenceNone 只控制该 NSURLCredential 的持久化行为,不负责保存设置页面中的密码。

页面已有导航 delegate 时,保留转发方式

一个 WKWebView 同时只有一个 navigationDelegate。如果各页面已经通过自身处理加载完成、加载失败或导航策略,将 navigationDelegate 指向公共对象会改变这些回调的接收者。

这种情况下,可以让页面继续担任 delegate,只把认证回调转发给公共对象:

- (void)webView:(WKWebView *)webView
        didReceiveAuthenticationChallenge:
            (NSURLAuthenticationChallenge *)challenge
        completionHandler:
            (void (^)(NSURLSessionAuthChallengeDisposition disposition,
                      NSURLCredential *credential))completionHandler {
    [self.webAuthDelegate webView:webView
        didReceiveAuthenticationChallenge:challenge
        completionHandler:completionHandler];
}

各页面可以继续处理自己的导航行为,由公共对象统一处理认证。每次挑战的 completionHandler 必须且只能调用一次;转发后,页面不要再次调用它。

AppDelegate 和 POST 请求需要注意什么

AppDelegate 可以参与创建和传递公共对象。把认证细节放在独立类里,更容易维护和复用。为了在几个页面之间共享逻辑,也不必将对象设计成全局单例。

还需要确认 POST 请求由谁发起。如果是 WKWebView 加载请求,上述 WKNavigationDelegate 方案适用;如果页面通过 NSURLSession 执行 POST,再展示返回内容,应在对应的 NSURLSession delegate 中处理认证。两种请求通道可以共享凭据服务,但使用不同的认证回调。

HTTP Basic Auth 的凭据编码不能代替加密,应通过 HTTPS 传输。对于非 Basic Auth 的挑战,示例交给系统默认处理,不应为了复用认证逻辑而无条件接受服务器证书。

备注:内容仅供参考。