ios - AFOAuth2Client 无法访问资源

标签 ios oauth-2.0 afnetworking

在 iOS 6 上使用 AFOAuth2Client 和 AFNetworking 我能够获得访问 token ,但无法访问资源,服务器响应 401 未授权状态代码。这是针对使用 doorkeeper 作为 OAuth 提供程序的自定义 Rails 3 API 后端。以下客户端 ruby​​ 代码,使用 OAuth2 gem,工作正常:

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

iOS 代码如下,在登录按钮处理程序中,我使用用户名和密码进行身份验证,并存储凭据:

- (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:@""];
                               }];
}

我为我的端点创建了 AFHTTPClient 的子类,在 initWithBaseURL 中它检索凭据并使用访问 token 设置授权 header :

- (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;
}

这是使用 AFOAuth2Client 和 AFNetworking 的正确方法吗?知道为什么这不起作用吗?

最佳答案

设法通过更改使其工作:

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

到:

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

更新

我没有注意到的是 AFOAuth2Client 本身是 AFHTTPClient 的子类,因此可以用作 API 类的基类,例如:

@interface YFExampleAPIClient : AFOAuth2Client

    + (YFExampleAPIClient *)sharedClient;

    /**

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

    @end

实现变成:

@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

请注意,initWithBaseURL 被覆盖以设置 HTTP 接受 header 。

GitHub 上提供了完整的源代码 - https://github.com/yellowfeather/rails-saas-ios

关于ios - AFOAuth2Client 无法访问资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14177739/

相关文章:

ios - 如何处理 %s 格式说明符

ios 所有 UIButton 的全局触觉反馈

azure - 如何使用 OAuth2 和 microsoft 登录以及 HTTP 请求通过用户名/密码登录

java - 服务器端访问/刷新 token 中的 Oauth2

ios - 客户端凭据 AFNetworking

ios - 卡在请求中并带有响应205

ios - 如何将 AFNetworking AFJSONRequestOperation 包装到单独的数据管理器类中

ios - 数字格式化程序不允许显示小数

ios - Firebase Deeplink 不调用应用程序 :continueUserActivity:restorationHandler function of AppDelegate in Swift 3

api - 2013 年的两足认证标准——我们应该使用 oAuth2 吗?