Rails 4 iOS身份验证和授权

时间:2014-04-26 22:20:36

标签: ios ruby-on-rails ruby-on-rails-4 devise

我正在使用Devise和CanCanCan来管理用户身份验证和授权,但由于某种原因,我的current_user对象始终是nil Rails端,即使我使用我的登录获得成功消息。我不确定断开连接是什么,但在成功登录后我无法检索任何资源。

我正在寻找的是,我想更好地了解幕后发生的事情。一旦用户登录,我就会从rails侧发回X-CSRF-Token标头(form_authenticity_token),但我的理解是,这只需要从我的iOS应用程序传回服务器以获取写入服务器(POST,PUT,DELETE)。如果是这种情况,那么如何向服务器标识自己的GET请求?

1 个答案:

答案 0 :(得分:2)

经过一番研究,我就是如何总结我最终做的事情。

  • 对于GET请求,您使用iOS网络库中内置的cookie存储。默认情况下,它在NSURLRequest(和可变变体)类中打开。对于GET来说,这几乎是你所需要的。当然,您必须成功登录才能获取cookie并登录需要POST。

  • 对于POST,PUT和DELETE,您必须在请求中提供X-CSRF-Token作为标头。但是,对于除登录请求之外的所有请求都是如此,这些请求需要禁用X-CSRF-Token标头要求才能创建会话,但更多内容将在下面进行。

首先,这是针对设计安装在iOS上进行登录的实现(更改设计登录路由<server_url>/users/login.json而不是默认<server_url>/users/sign_in.json):

- (void)loginWithUsername:(NSString*)username
                 password:(NSString*)password
          completionBlock:(void(^)(id response, NSError *error))block
{
    NSDictionary *loginDictionary = @{@"user" : @{@"email" : username,
                                                  @"password" : password}
                                      };

    // Convert dictionary to NSData for POST body
    NSError *error = nil;
    NSData *data = [NSJSONSerialization dataWithJSONObject:loginDictionary 
                                                   options:0 
                                                     error:&error];

    NSString *postUrlString = [NSString stringWithFormat:@"%@users/login.json", 
                                                             kApiEndpointURL];

    NSMutableURLRequest *request = [NSMutableURLRequest 
                     requestWithURL:[NSURL URLWithString:postUrlString]
                        cachePolicy:NSURLRequestReloadIgnoringCacheData
                    timeoutInterval:kTimeoutInterval];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-type"];
    [request setHTTPBody:data];

    // This is the default--here for clarity
    [request setHTTPShouldHandleCookies:YES];

    NSURLSession *session = [NSURLSession sharedSession];

    [[UIApplication sharedApplication] showNetworkActivityIndicator];

    NSURLSessionDataTask *dataTask = 
                             [session dataTaskWithRequest:request 
                               completionHandler:^(NSData *data, 
                                            NSURLResponse *response, 
                                                  NSError *error) {
        // Save the token so we can perform POSTs, PUTS, and DELETEs
        NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*)response;
        self.xcsrfToken = httpResp.allHeaderFields[@"X-CSRF-Token"];

        [[UIApplication sharedApplication] hideNetworkActivityIndicator];
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@", json);
        dispatch_async(dispatch_get_main_queue(), ^{
            if (block) {
                block(json, error);
            }
        });
    }];

    [dataTask resume];
}
  • 在rails方面,您需要有一种方法来创建会话而不需要X-CSRF-Token,并且一旦用户进行了身份验证,您还需要传回X-CSRF-Token以便将来写入行动将成功。

我在会话控制器中执行了以下操作:

class SessionsController < Devise::SessionsController
    after_filter :set_csrf_header, only: [:create]
    skip_before_filter :verify_authenticity_token, only: [:create]


    def set_csrf_header
        response.headers['X-CSRF-Token'] = form_authenticity_token
    end
end

我的会话控制器中有更多内容,但这显示了相关部分。请求成功完成创建操作后,我发送回X-CSRF-Token。但是,我跳过了创建的真实性验证。这意味着虽然创建会话本身并不需要真实性令牌,但是一旦操作完成,它将向请求者发送一个令牌,这样请求者就可以在将来的所有写操作中使用该令牌。

如果我遗漏了某些内容或做错了什么,请告诉我,我会更新此答案。