2014-09-25 164 views
1

我有一個Rails應用程序,我正在設計iOS應用程序。 Rails應用程序使用Devise進行用戶登錄。當用戶通過移動應用程序登錄時,Rails應用程序應返回一個身份驗證令牌,然後在整個應用程序中使用該令牌。使用Rails應用程序+設計iOS登錄問題設計

我已經有一個工作的Android應用程序,我跟着這個頁面上的教程通過Android應用啓用登錄:

http://lucatironi.github.io/tutorial/2012/10/15/ruby_rails_android_app_authentication_devise_tutorial_part_one/

這是我的自定義設計SessionsController樣子:

class SessionsController < Devise::SessionsController 
    skip_before_filter :verify_authenticity_token, 
        :if => Proc.new { |c| c.request.format == 'application/json' } 
warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure") 
render :status => 200, 
     :json => { :success => true, 
        :info => "Logged in", 
        :data => { :auth_token => current_user.authentication_token } } 
end 
end 

這一直對我的Android應用程序有效。

但我在使用我的iOS應用程序登錄時遇到了一個奇怪的問題。以下是我的登錄名:

-(IBAction)authenticateUser { 
    [keychainItem resetKeychainItem]; // remove any existing auth_token 

    NSURL *url=[NSURL URLWithString:sessionsBaseURL]; 
    NSError *error = nil; 
    NSDictionary * userDict = [[NSDictionary alloc] initWithObjectsAndKeys: [_txtUsername text], @"username", [_txtPassword text], @"password", nil]; 
    NSDictionary * holderDict = [[NSDictionary alloc] initWithObjectsAndKeys: userDict, @"user", nil]; 
    NSLog(@"holderDict: %@", holderDict); 
    NSData * holder = [NSJSONSerialization dataWithJSONObject:holderDict options:0 error:&error]; 

    NSLog(@"auth_token%@", [keychainItem objectForKey:(__bridge id)(kSecAttrType)]); 
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 
    [request setURL:url]; 
    [request setHTTPMethod:@"POST"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
    [request setHTTPBody:holder]; 

    NSURLResponse * response = nil; 
    NSData * receivedData = nil; 

    receivedData = [NSMutableData data]; 
    receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 
    NSLog(@"attempting login"); 

    // get dictionary from json data 
    NSDictionary * jsonResponse = [NSJSONSerialization 
            JSONObjectWithData: receivedData 
            options:kNilOptions 
            error:&error]; 
    if(error == nil){ 
     NSLog(@"successful login"); 
     [keychainItem setObject:[_txtUsername text] forKey:(__bridge id)(kSecAttrAccount)]; 
     NSLog(@"jsonResponse: %@", jsonResponse); 
     NSDictionary * dataResponse = [jsonResponse objectForKey:@"data"]; 
     auth_token = [dataResponse objectForKey:@"auth_token"]; 
     // save user authentication token 
     [keychainItem setObject:auth_token forKey:(__bridge id)(kSecValueData)]; 
    }else{ 
     NSLog(@"jsonResponse: %@", jsonResponse); 
    } 
    NSLog(@"error: %@" , [error localizedDescription]); 

    [self checkLoginApproved]; 
} 

用戶能夠在第一次正確登錄並返回正確的身份驗證令牌。但是,如果用戶註銷然後在iOS應用程序中使用不正確的密碼重新登錄,Rails應用程序似乎認爲用戶已正確登錄(它不會返回未經授權的用戶,並且它會返回空認證令牌) 。

這使我相信warden.authenticate有問題。在Rails應用程序或iOS應用程序中,我很難找出問題所在。

有沒有人有一個讓他們的iOS應用程序使用Rails和設計用戶登錄的例子?還是有人有其他的想法,爲什麼我有什麼不工作?

回答

0

你好StackOverflow World。

它最終成爲大多數與warden.authenticate問題,如我所料。我最後寫一個自定義的方法來確定用戶的登錄憑證是否有效(導軌):

def create 
    user = User.find_for_authentication(:username=>params[:user][:username]) 
    if user && user.valid_password?(params[:user][:password]) 
     # generate token if it doesn't exist 
     if user.authentication_token.blank? 
      Rails.logger.debug "generating authentication token for #{user.username} #{user.id}" 
      new_token = generate_authentication_token 
      Rails.logger.debug "new authentication token: #{new_token}" 
      user.update_column("authentication_token", new_token) 
     end 

     render :status => 200, 
      :json => { :success => true, 
         :info => "Logged in", 
         :data => { :auth_token => user.authentication_token } } 
     Rails.logger.debug "current user: #{current_user.username} #{current_user.id}" 
     Rails.logger.debug "current user authentication_token: #{current_user.authentication_token}" 
    else 
     render :status => 401, 
     :json => { :success => false, 
        :info => "Login Failed", 
        :data => {} } 
    end 

def generate_authentication_token 
    loop do 
     token = Devise.friendly_token 
     break token unless User.where(authentication_token: token).first 
    end 
    end 

這是我在我的iOS在日誌記錄:

-(IBAction)authenticateUser { 
    [keychainItem resetKeychainItem]; // remove any existing auth_token 

    NSURL *url=[NSURL URLWithString:sessionsBaseURL]; 
    NSError *error = nil; 
    NSDictionary * userDict = [[NSDictionary alloc] initWithObjectsAndKeys: [_txtUsername text], @"username", [_txtPassword text], @"password", nil]; 
    NSDictionary * holderDict = [[NSDictionary alloc] initWithObjectsAndKeys: userDict, @"user", nil]; 
    NSLog(@"holderDict: %@", holderDict); 
    NSData * holder = [NSJSONSerialization dataWithJSONObject:holderDict options:0 error:&error]; 

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 
    [request setURL:url]; 
    [request setHTTPMethod:@"POST"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
    [request setHTTPBody:holder]; 

    NSURLResponse * response = nil; 
    NSData * receivedData = nil; 

    receivedData = [NSMutableData data]; 
    receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 
// NSLog(@"attempting login"); 

    // get dictionary from json data 
    NSDictionary * jsonResponse = [NSJSONSerialization 
            JSONObjectWithData: receivedData 
            options:kNilOptions 
            error:&error]; 

    NSLog(@"jsonResponse: %@", jsonResponse); 

    if([[jsonResponse objectForKey:@"data"] objectForKey:@"auth_token"]) { 
     NSLog(@"saving login"); 
     NSDictionary * dataResponse = [jsonResponse objectForKey:@"data"]; 
     auth_token = [dataResponse objectForKey:@"auth_token"]; 
     [keychainItem setObject:[_txtUsername text] forKey:(__bridge id)(kSecAttrAccount)]; 
     // save user authentication token 
     [keychainItem setObject:auth_token forKey:(__bridge id)(kSecAttrType)]; 
    } 

    [self checkLoginApproved]; 
} 

和註銷:

NSString *logoutURLString = [NSString stringWithFormat:[sessionsBaseURL stringByAppendingFormat:@"?auth_token=%@", auth_token]]; 
    NSLog(@"logoutURLString: %@", logoutURLString); 


    [request setURL:[NSURL URLWithString:logoutURLString]]; 
    [request setHTTPMethod:@"DELETE"]; 

    // receive JSON response 
    NSURLResponse * response = nil; 
    NSData * receivedData = nil; 

    NSError *error = [[NSError alloc] init]; 

    receivedData = [NSMutableData data]; 
    receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 

    NSString *jsonString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding]; 

    [self.keychainItem resetKeychainItem]; 

我沒有找到像這樣的例子,所以我希望這可以幫助別人。