Ошибка 401 — базовая аутентификация с помощью AFNetworking AFHTTPClient и Tastypie

Я использую AFHTTPClient из AFNetworking, чтобы сделать вызов из моего приложения IOS на мой сервер, который использует Django с TastyPie. Он отлично работает, когда я отключаю аутентификацию на стороне сервера; однако, когда я требую аутентификации и вставляю правильное имя пользователя и пароль в свой код, я получаю следующую ошибку аутентификации 401:

\2012-09-16 00:24:37.877 RESTtest[76909:f803] 
Complex AF: Error Domain=AFNetworkingErrorDomain Code=-1011 
"Expected status code in (200-299), got 401" 
UserInfo=0x686ba00 {AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x686f130>, 
NSErrorFailingURLKey=http://127.0.0.1:8000/api/v1/shoppinglist, 
NSLocalizedDescription=Expected status code in (200-299), got 401, 
AFNetworkingOperationFailingURLRequestErrorKey=<NSMutableURLRequest http://127.0.0.1:8000/api/v1/shoppinglist>}

Вот мой код:

AFAPIClient.h #import "AFHTTPClient.h"

@interface AFAPIClient : AFHTTPClient

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

+ (AFAPIClient *)sharedClient;

@end

AFAPIClient.m:

#import "AFAPIClient.h"
#import "AFJSONRequestOperation.h"


static NSString * const baseURL = @"http://@127.0.0.1:8000/api/v1";


@implementation AFAPIClient

+ (AFAPIClient *)sharedClient {
    static AFAPIClient *_sharedClient = nil;
    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        _sharedClient = [[AFAPIClient alloc] initWithBaseURL:[NSURL URLWithString:baseURL]];
        //[_sharedClient setAuthorizationHeaderWithUsername:@"myusername" password:@"mypassword"]; I tried putting the authorization command here
    });

    return _sharedClient;
};

#pragma mark - Methods

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

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

    [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
    [self setParameterEncoding:AFJSONParameterEncoding];


    //[self setAuthorizationHeaderWithUsername:@"myusername" password:@"mypassword"]; I also tried putting the authorization command here

    // Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
    [self setDefaultHeader:@"Accept" value:@"application/json"];

    return self;
}


@end

TQViewController.h:

[...]
- (IBAction)sendAFClientRequest:(id)sender {
    //[[AFAPIClient sharedClient] setUsername:@"myusername" andPassword:@"mypassword"];
    [[AFAPIClient sharedClient] getPath:@"shoppinglist" parameters:nil success:^(AFHTTPRequestOperation *operation, id response) {
        NSLog(@"Complex AF: %@", [response valueForKeyPath:@"objects"]);
    } failure:^(AFHTTPRequestOperation *operation, id response) {
        NSLog(@"Complex AF: %@", response);
    }
     ];

}
[...]

Я знаю, что это не проблема с моим сервером или моим именем пользователя/паролем, так как я могу просто пройти аутентификацию, вставив имя пользователя/пароль в URL-адрес:

@"http://myusername:[email protected]:8000/api/v1/shoppinglist"

Любая помощь в этом была бы отличной. Было бы замечательно иметь возможность использовать AFHTTPClient без вставки информации аутентификации непосредственно в статический базовый URL-адрес, что кажется совершенно неправильным. Заранее спасибо!


person aryland    schedule 16.09.2012    source источник


Ответы (1)


На основании этого: https://github.com/AFNetworking/AFNetworking/issues/426

Я переопределяю метод - (void)getPath:(NSString *)path parameters... в подклассе AFHTTPClient, чтобы он выглядел примерно так:

- (void)getPath:(NSString *)path parameters:(NSDictionary *)parameters
    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
    [operation setAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
        NSURLCredential *newCredential = [NSURLCredential credentialWithUser:self.username password:self.password persistence:NSURLCredentialPersistenceForSession];
        [challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
    }];
    [self enqueueHTTPRequestOperation:operation];
}

Он только добавляет блок проверки подлинности в AFHTTPRequestOpertaion, остальное такое же, как и в исходной реализации https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFHTTPClient.m

person user1375355    schedule 20.10.2012