使用Rails / Devise API进行NSURLSession身份验证

时间:2013-12-16 20:46:05

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

我有一个带有由Devise + simple_token_authentication保护的API的ROR应用程序 - 一切正常。现在,我正在使用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);

}

2 个答案:

答案 0 :(得分: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加载系统类不会调用其委托   除非服务器响应包含a,否则处理请求质询   WWW-Authenticate标头。其他身份验证类型,例如代理   身份验证和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

答案 1 :(得分:0)

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

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


# config/initializers/devise.rb
...
config.http_authenticatable = true
...