1

我有一个 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);

}
4

2 回答 2

1

如果您在 dataTaskWithURL 中包含了完成处理程序,那么这就是所使用的并且永远不会调用委托。

尝试将 completionHandler 设置为 Nil:

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

然后将使用委托方法。

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

重要提示:除非服务器响应包含 WWW-Authenticate 标头,否则 URL 加载系统类不会调用它们的委托来处理请求质询。其他身份验证类型(例如代理身份验证和 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 .

于 2013-12-18T21:36:02.403 回答
0

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

# models/user.rb
...
devise :database_authenticatable, # and more
...


# config/initializers/devise.rb
...
config.http_authenticatable = true
...
于 2013-12-17T07:02:27.880 回答