3

我有以下问题:我正在向服务器发出请求,该服务器使用 HTTP 基本身份验证并给了我

  • 如果我不发送身份验证,则为 401
  • 如果我发送无效身份验证,则为 401
  • 如果我发送有效的身份验证但该用户禁止该资源,则为 403。

收到 401 时,我的 NSURLSession 非常友好,可以通过

URLSession(
    session: NSURLSession,
    task: NSURLSessionTask, didReceiveChallenge
    challenge: NSURLAuthenticationChallenge,
    completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)

然后我可以在其中修改发送到服务器的凭据。

但是,当收到 403 时,我遇到了问题。从那里我无法让会话使用除用于获取 403 之外的任何其他凭据。在 403 上,不询问代表(这没关系,它不是 401),所以我如何控制哪些凭据是将来为那个保护空间发送?即使手动清空共享的 NSURLCredentialStorage 和/或直接在那里设置正确的凭据也无济于事:

let credential = NSURLCredential(user: username, password: password, persistence: .ForSession)
    let protectionSpace = NSURLProtectionSpace(
        host: self.host,
        port: self.apiRootURL.port!.integerValue,
        protocol: self.apiRootURL.scheme!,
        realm: "MyRealm",
        authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
    NSURLCredentialStorage.sharedCredentialStorage().setDefaultCredential(credential, forProtectionSpace: protectionSpace)

在此调用之后,正确的凭据是唯一在 NSURLCredentialStorage 中列出的凭据 - 但是下一次对服务器的调用仍将包含旧凭据,这将不可避免地导致另一个 403。

即使使用其reset(completionHandler: @escaping () -> Void)方法重置会话也无济于事。

TLDR ; 如何更改 NSURLSession 在给定保护域成功使用它们后继续使用的凭据?

4

1 回答 1

0

你捕捉到 403 响应消息,然后要么

  • 发出对注销 URL 的请求,然后是登录 URL。
  • 始终防止凭证存储在凭证存储中,以便您始终收到回调。
  • 在 403 后删除现有凭据以强制回调。

我推荐第二种或第三种方法,具体取决于哪种方法平均会减少请求。为避免持久化,请传递 NSURLCredentialPersistenceNone 或 Swift 等效项,而不是告诉它在会话期间持续存在。要删除凭据,请调用removeCredential:forProtectionSpace:options:

根据您的应用程序设计和服务器设计,还有其他几种可能可行的方法:

  • 将正确的凭据预先添加到钥匙串/凭据存储中。警告:只有一个钥匙串支持它,所以如果您有多个需要来自不同帐户的同时请求,这不是一个好方法,因为您无法控制为给定请求发送哪个凭证。
  • 对于需要以不同用户身份进行身份验证的事物,请使用不同的身份验证领域。
于 2016-10-21T16:46:33.507 回答