2013-01-05 14 views
5

Utilizzo di AFOAuth2Client e AFNetworking su iOS 6 Sono in grado di ottenere un token di accesso, ma non riesco ad accedere a una risorsa, il server risponde con un codice di stato 401 non autorizzato. Si tratta di un backend API Rails 3 personalizzato che utilizza doorkeeper come provider OAuth. Il seguente codice client rubino, utilizzando la gemma OAuth2, funziona bene:AFOAuth2Client non è in grado di accedere alla risorsa

client = OAuth2::Client.new(app_id, secret, site: "http://subdomain.example.com/") 
access_token = client.password.get_token('username', 'password') 
access_token.get('/api/1/products').parsed 

Il codice di IOS è come sotto, nel gestore pulsante di accesso ho autenticarsi utilizzando il nome utente e la password, e memorizzare le credenziali:

- (IBAction)login:(id)sender { 
    NSString *username = [usernameField text]; 
    NSString *password = [passwordField text]; 

    NSURL *url = [NSURL URLWithString:kClientBaseURL]; 
    AFOAuth2Client *client = [AFOAuth2Client clientWithBaseURL:url clientID:kClientID secret:kClientSecret]; 

    [client authenticateUsingOAuthWithPath:@"oauth/token" 
           username:username 
           password:password 
           scope:nil 
           success:^(AFOAuthCredential *credential) { 
            NSLog(@"Successfully received OAuth credentials %@", credential.accessToken); 
            [AFOAuthCredential storeCredential:credential 
                 withIdentifier:client.serviceProviderIdentifier]; 
            [self performSegueWithIdentifier:@"LoginSegue" sender:sender]; 
           } 
           failure:^(NSError *error) { 
            NSLog(@"Error: %@", error); 
            [passwordField setText:@""]; 
           }]; 
} 

e ho sottoclasse AFHTTPClient per il mio punto finale e nel initWithBaseURL recupera le credenziali e imposta l'intestazione di autorizzazione con il token di accesso:

- (id)initWithBaseURL:(NSURL *)url { 
    self = [super initWithBaseURL:url]; 
    if (!self) { 
     return nil; 
    } 

    [self registerHTTPOperationClass:[AFJSONRequestOperation class]]; 
    [self setDefaultHeader:@"Accept" value:@"application/json"]; 

    AFOAuthCredential *credential = [AFOAuthCredential retrieveCredentialWithIdentifier:@"subdomain.example.com"]; 
    [self setAuthorizationHeaderWithToken:credential.accessToken]; 

    return self; 
} 

È questo il modo corretto di utilizzare AFOAuth2Client e AFNetworking? E qualche idea del perché questo non funziona?

risposta

5

riusciti a ottenere questo lavoro modificando:

AFOAuthCredential *credential = [AFOAuthCredential retrieveCredentialWithIdentifier:@"subdomain.example.com"]; 
    [self setAuthorizationHeaderWithToken:credential.accessToken]; 

a:

AFOAuthCredential *credential = [AFOAuthCredential retrieveCredentialWithIdentifier:@"subdomain.example.com"]; 
    NSString *authValue = [NSString stringWithFormat:@"Bearer %@", credential.accessToken]; 
    [self setDefaultHeader:@"Authorization" value:authValue]; 

UPDATE

Quello che avevo mancato di notare era che AFOAuth2Client è di per sé una sottoclasse di AFHTTPClient così può essere utilizzato come classe base della classe API, ad esempio:

@interface YFExampleAPIClient : AFOAuth2Client 

    + (YFExampleAPIClient *)sharedClient; 

    /** 

    */ 
    - (void)authenticateWithUsernameAndPassword:(NSString *)username 
             password:(NSString *)password 
             success:(void (^)(AFOAuthCredential *credential))success 
             failure:(void (^)(NSError *error))failure; 

    @end 

e l'implementazione diventa:

@implementation YFExampleAPIClient 

+ (YFExampleAPIClient *)sharedClient { 
    static YFExampleAPIClient *_sharedClient = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     NSURL *url = [NSURL URLWithString:kClientBaseURL]; 
     _sharedClient = [YFExampleAPIClient clientWithBaseURL:url clientID:kClientID secret:kClientSecret]; 
    }); 

    return _sharedClient; 
} 

- (void)authenticateWithUsernameAndPassword:(NSString *)username 
            password:(NSString *)password 
            success:(void (^)(AFOAuthCredential *credential))success 
            failure:(void (^)(NSError *error))failure { 
    [self authenticateUsingOAuthWithPath:@"oauth/token" 
            username:username 
            password:password 
            scope:nil 
            success:^(AFOAuthCredential *credential) { 
             NSLog(@"Successfully received OAuth credentials %@", credential.accessToken); 
             [self setAuthorizationHeaderWithCredential:credential]; 
             success(credential); 
            } 
            failure:^(NSError *error) { 
             NSLog(@"Error: %@", error); 
             failure(error); 
            }]; 
} 

- (id)initWithBaseURL:(NSURL *)url 
      clientID:(NSString *)clientID 
       secret:(NSString *)secret { 
    self = [super initWithBaseURL:url clientID:clientID secret:secret]; 
    if (!self) { 
     return nil; 
    } 

    [self setDefaultHeader:@"Accept" value:@"application/json"]; 

    return self; 
} 

@end 

noti che initWithBaseURL viene sostituita per impostare l'HTTP accetta intestazione.

Il codice sorgente completo è disponibile su GitHub - https://github.com/yellowfeather/rails-saas-ios

+1

Date un'occhiata al file di https://github.com/AFNetworking/AFOAuth2Client/blob/master/AFOAuth2Client/AFOAuth2Client.h. C'è una nota in cima alla quale si raccomanda di non usarla come classe base. – davidbitton

Problemi correlati