我有一个带有由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);
}
答案 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-client和https://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
...