【问题标题】:NSURLSession authentication with Rails/Devise API使用 Rails/Devise API 进行 NSURLSession 身份验证
【发布时间】:2014-01-04 09:53:38
【问题描述】:

我有一个 ROR 应用程序,其 API 由 Devise + simple_token_authentication 保护 - 一切正常。现在我正在使用 NSURLSession 构建一个 iOS 应用程序来访问 API 并处理身份验证,这就是我遇到麻烦的地方。

在加载时,我调用以下方法从服务器检索数据。据我了解,在获得 401 未授权但没有任何反应时应该调用 didReceiveChallenge 代表。我对iOS相当陌生,我可能做错了,但我希望有人能帮助我解决这个问题。谢谢!:)

- (void)fetch:(id)sender {

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    config.HTTPAdditionalHeaders = @{ @"Accept":@"application/json"};

    self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    NSURLSessionTask *dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:@"http://localhost:3000/api/v1/tasks"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        // handle response
        NSLog(@"data %@", data);
    }];

    [dataTask resume];

}

即使在收到 401 标头之后,也不会调用此方法。

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

    NSString *user = @"email";
    NSString *password = @"secretpass";

    NSLog(@"didReceiveChallenge");

    // should prompt for a password in a real app but we will hard code this baby
    NSURLCredential *secretHandshake = [NSURLCredential credentialWithUser:user password:password persistence:NSURLCredentialPersistenceForSession];

    // use block
    completionHandler(NSURLSessionAuthChallengeUseCredential,secretHandshake);

}

【问题讨论】:

    标签: ruby-on-rails api devise ios7 nsurlsession


    【解决方案1】:

    如果你在 dataTaskWithURL 中包含了一个completionHandler,那么它就是被使用的并且永远不会调用委托。

    尝试将 completionHandler 设置为 Nil:

    NSURLSessionTask *dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:@"http://localhost:3000/api/v1/tasks"] completionHandler:Nil];
    

    然后将使用委托方法。

    在进一步测试时,您需要返回一个 WWW-Authenticate 标头来触发 didReceiveChallenge 委托方法。来自 Apple 文档:

    重要提示:URL 加载系统类不会调用它们的委托 处理请求挑战,除非服务器响应包含 WWW-身份验证标头。其他身份验证类型,例如代理 身份验证和 TLS 信任验证不需要此标头。

    您可以通过向您的 Rails 应用程序添加自定义身份验证方法来做到这一点,例如

      before_filter :authenticate_user!
    
      private
    
        def authenticate_user!
          unless current_user
              headers["WWW-Authenticate"] = %(Basic realm="My Realm")          
              render :json => {:message =>I18n.t("errors.messages.authorization_error")}, :status => :unauthorized
          end
        end
    

    我仍在我的应用程序上解决此问题,但上述方法确实触发了 didReceiveChallenge 委托。希望对您有用。

    更多信息,didReceiveChallenge 中的以下代码(与原始问题相同)将处理对 Rails 服务器的登录:

    -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
     //   NSLog(@"didReceiveChallenge");
    
        NSString *ftfID    = (NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:@"ftfID"];
        NSString *ftfPassword    = (NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:@"ftfPassword"];
        NSString *user = ftfID;
        NSString *password = ftfPassword;
    
        NSURLCredential *secretHandshake = [NSURLCredential credentialWithUser:user password:password persistence:NSURLCredentialPersistenceForSession];
    
        // use block
        completionHandler(NSURLSessionAuthChallengeUseCredential,secretHandshake);
    
    }
    

    要下载通过 json 请求进行通信的 Rails 和 iOS 应用程序的工作示例,请参阅 https://github.com/petetodd/bright-green-star-clienthttps://github.com/petetodd/bright-green-star-server

    【讨论】:

    • 感谢greentor!这很有帮助。 didReceiveChallenge 现在正在工作。如果您发现更多好东西,请发布:]我会尽快接受您的回答
    • 很高兴您发现它很有用。如果您希望使用 NSURLSession 发布数据,您可能会发现这个答案很有用:Using NSDictionary to Post params 在我的 iPhone 应用程序中,我注册/登录用户,然后将数据发布到我的 Rails 应用程序。
    • 嘿@greentor,我能问一下你是如何使用设计处理json登录过程的吗?
    • 现在在答案中添加了更多信息,显示如何处理登录挑战。
    • 嗨@user3108730 - 我想你已经在做我为 didReceiveChallenge 添加的内容了。我尝试发帖,收到挑战,登录成功,发帖继续(Rails 应用程序使用我登录的用户)。如果您的 didReceiveChallenge 触发了您从设计中得到什么响应? (使用 didCompleteWithError 委托获取详细信息)
    【解决方案2】:

    确保您在用户模型中使用 :database_authenticatable 策略,并在设计初始化程序中使用 config.http_authenticatable = true:

    # models/user.rb
    ...
    devise :database_authenticatable, # and more
    ...
    
    
    # config/initializers/devise.rb
    ...
    config.http_authenticatable = true
    ...
    

    【讨论】:

    • 嘿特洛伊,感谢您的回答。我没有config.http_authenticable = true,但它仍然不起作用。我认为问题可能与 iOS 部分和 didReceiveChallenge 委托更相关
    • 尝试添加其他委托方法以查看发生了什么 - 即 – URLSession:task:didCompleteWithError: 和 – URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:
    猜你喜欢
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    相关资源
    最近更新 更多