Using AFNetworking and HTTP Basic Authentication

20,987

Answer updated for AFNetworking 2.x

For AFNetworking 2.x:

In 2.x, they did away with AFHTTPClient, so you'll need to extend AFHTTPRequestOperationManager with your own class. Then, you can call that class from other code. For example, here's a sample class that extends the AFHTTPRequestOperationManager:

SBAPIManager.h:

#import "AFHTTPRequestOperationManager.h"

@interface SBAPIManager : AFHTTPRequestOperationManager

- (void)setUsername:(NSString *)username andPassword:(NSString *)password;

+ (SBAPIManager *)sharedManager;

@end

SBAPIManager.m:

#import "SBAPIManager.h"
#import "AFNetworkActivityIndicatorManager.h"

@implementation SBAPIManager

#pragma mark - Methods

- (void)setUsername:(NSString *)username andPassword:(NSString *)password
{
    [self.requestSerializer clearAuthorizationHeader];
    [self.requestSerializer setAuthorizationHeaderFieldWithUsername:username password:password];
}

#pragma mark - Initialization

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

    self.requestSerializer = [AFJSONRequestSerializer serializer];

    [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];

    return self;
}

#pragma mark - Singleton Methods

+ (SBAPIManager *)sharedManager
{
    static dispatch_once_t pred;
    static SBAPIManager *_sharedManager = nil;

    dispatch_once(&pred, ^{ _sharedManager = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://localhost:3000"]]; }); // You should probably make this a constant somewhere
    return _sharedManager;
}

@end

Then, in your code, you can call it like this:

[[SBAPIManager sharedManager] setUsername:yourUsernameVariableHere andPassword:yourPasswordVariableHere];

[[SBAPIManager sharedManager] GET:@"/tasks.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    self.tasks = [responseObject objectForKey:@"results"];
    [self.activityIndicatorView stopAnimating];
    [self.tableView setHidden:NO];
    [self.tableView reloadData];

    NSLog(@"JSON");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // error stuff here
}];

For AFNetworking 1.x:

The best practice for this in AFNetworking is to extend the AFHTTPClient with your own class. Then, you can call that class from other code. For example, here's a sample class that extends the AFHTTPClient:

SBAPIManager.h:

#import "AFNetworking/AFHTTPClient.h"

@interface SBAPIManager : AFHTTPClient

- (void)setUsername:(NSString *)username andPassword:(NSString *)password;

+ (SBAPIManager *)sharedManager;

@end

SBAPIManager.m:

#import "SBAPIManager.h"
#import "AFJSONRequestOperation.h"
#import "AFNetworkActivityIndicatorManager.h"

@implementation SBAPIManager

#pragma mark - Methods

- (void)setUsername:(NSString *)username andPassword:(NSString *)password
{
    [self clearAuthorizationHeader];    
    [self setAuthorizationHeaderWithUsername:username password:password];
}

#pragma mark - Initialization

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

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

    [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];

    return self;
}

#pragma mark - Singleton Methods

+ (SBAPIManager *)sharedManager
{
    static dispatch_once_t pred;
    static SBAPIManager *_sharedManager = nil;

    dispatch_once(&pred, ^{ _sharedManager = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://localhost:3000"]]; }); // You should probably make this a constant somewhere
    return _sharedManager;
}

@end

Then, in your code, you can call it like this:

[[SBAPIManager sharedManager] setUsername:yourUsernameVariableHere andPassword:yourPasswordVariableHere];

[[SBAPIManager sharedManager] getPath:@"/tasks.json" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    self.tasks = [responseObject objectForKey:@"results"];
    [self.activityIndicatorView stopAnimating];
    [self.tableView setHidden:NO];
    [self.tableView reloadData];

    NSLog(@"JSON");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // error stuff here
}];
Share:
20,987

Related videos on Youtube

Paul Sylling
Author by

Paul Sylling

Building things. Running experiments. Growing @Vouchful. Always UI UX.

Updated on July 09, 2022

Comments

  • Paul Sylling
    Paul Sylling almost 2 years

    The following code successfully connects to my Ruby on Rails API and returns JSON using AFNetworking. What do I need to do to edit this to pass in a username and password so my API can use HTTP Basic Authentication?

    I've read their documentation, but I am new to both Objective-C and AFNetworking and it isn't currently making sense.

    NSURL *url = [[NSURL alloc] initWithString:@"http://localhost:3000/tasks.json"];
    
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    
    AFJSONRequestOperation *operation = [AFJSONRequestOperation
                                         JSONRequestOperationWithRequest:request
                                         success:^(NSURLRequest *request
                                         , NSHTTPURLResponse *response
                                         , id JSON) {
    
        self.tasks = [JSON objectForKey:@"results"];
        [self.activityIndicatorView stopAnimating];
        [self.tableView setHidden:NO];
        [self.tableView reloadData];
    
        NSLog(@"JSON");
    
    } failure:^(NSURLRequest *request
                    , NSHTTPURLResponse *response
                    , NSError *error
                    , id JSON) {
        NSLog(@"Request Failed with Error: %@, %@", error, error.userInfo);
    }];
    
    [operation start];
    
  • Paul Sylling
    Paul Sylling over 11 years
    Wow, awesome code sample! I will try and implement this into my project today. You are certainly at a much higher level than I, so it might take a bit.
  • GeneralMike
    GeneralMike about 11 years
    Small note: in the code for SBAPIManager.m, you have - (void)setUsername:(NSString *)username andPassword:(NSString *)password;, I think you need to remove that semicolon from the end.
  • FluffulousChimp
    FluffulousChimp about 11 years
    In Objective-C, the semicolon before the method implementation's opening brace is superfluous; but it compiles. Sometimes it's an artifact of cutting-and-pasting between header and implementation. No harm.
  • gilletty
    gilletty about 11 years
    Thanks guys. It was a copy/paste error and I have removed the semicolon.
  • Legoless
    Legoless over 10 years
    What is in v2.x method different from calling setCredentials on AFHTTPRequestOperationManager ?