在 Objective-C 中使用身份验证获取 JSON 令牌

Posted

技术标签:

【中文标题】在 Objective-C 中使用身份验证获取 JSON 令牌【英文标题】:Obtaining an JSON Token using Authentication in Objective-C 【发布时间】:2018-02-08 13:28:15 【问题描述】:

您好,ios 新手只是尝试将应用程序连接到 API 并使用身份验证获取我的令牌。我尝试了很多不同的选择,但似乎无法理解它。我要做的就是获得我的令牌。谁能看到我哪里出错了? API 文档在这里:https://simplybook.me/en/api/developer-api

NSURL *url = [NSURL URLWithString:@"http://user-api.simplybook.me/login/"];
NSURLSession *session = [NSURLSession sharedSession];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:@"myloginname" forHTTPHeaderField:@"X-Company-Login"];
[request setValue:@"mytokenhere" forHTTPHeaderField:@"X-Token"];

NSURLSessionDataTask *downloadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    if (!error) 

        id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSArray * resultDict =[json objectForKey:@"name"];
        NSLog(@"%@", resultDict);

     else 
        NSLog(@"%@", error);
    
];

[downloadTask resume];

【问题讨论】:

您是否尝试过在 api url 中使用 https 而不是 http?此外,downloadTask 是否已执行,或者您在触发请求时是否收到任何错误? 现在使用 https 还是同样的问题。 downloadTask 没有错误 【参考方案1】:

不要像这样声明NSURLSession

NSURLSession *session = [NSURLSession sharedSession];

试试这个:

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    NSURL *url = [NSURL URLWithString:@"https://user-api.simplybook.me/login/"];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:60.0];

此外,请确保您已在头文件中声明了 NSURLSessionDelegate 协议。

【讨论】:

我试过这个没有运气。会议工作正常。它只是使用标题来尝试获取我卡住的访问令牌。 @user7322261 好的,抱歉,我认为这可能是与sharedSession 相关的问题;您可以尝试的最后一件事,将自定义标题切换到 addValue 而不是 setValue 还是不行,谢谢!你知道 API 文档中我的 HTTP 标头字段应该是什么吗? @user7322261 我快速浏览了文档,您设置的 2 个标题似乎是正确的。您也可以尝试将这个添加到请求中:[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 啊,我刚刚注意到上面我写的 mytokenhere 行实际上是 API 密钥。我只是想获得我实际上还没有的令牌。在他们使用的文档中 var token = loginClient.getToken(YOUR_COMPANY_LOGIN, YOUR_API_KEY);【参考方案2】:

我会给你获取令牌的示例代码,但这是关于访问和刷新令牌的。你现在可以很清楚地理解它了。

ViewController.m

- (void)viewDidLoad 
     [super viewDidLoad];


- (IBAction)actionLogin:(id)sender 
     [self loginForGettingAccessandRefreshToken];


-(void)loginForGettingAccessandRefreshToken

  @try 

         NSString *strUserName = [textUsername.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
         NSString *strPassword = [textPassword.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

         NSString *strParameters = [NSString stringWithFormat:@"client_id=roclient&client_secret=secret&grant_type=password&username=%@&password=%@&scope=dataEventRecords offline_access", strUserName, strPassword];

        id param = strParameters;
        NSLog(@"The param is - %@",param);

       [GlobalShareClass postLoginDataToServer:BASEURL_LOGIN passParameters:param success:^(id res)
       
           if([res isKindOfClass:[NSDictionary class]])

            NSDictionary *dictRes = [res copy];
            NSString *strErrDesc = [NSString stringWithFormat:@"%@",[dictRes objectForKey:@"error_description"]];

            if([[dictRes allKeys] containsObject:@"error_description"])
             dispatch_async(dispatch_get_main_queue(), ^

                  //Dispaly UI
             );
         
         else
              NSString *strAccessToken = [dictRes objectForKey:@"access_token"];
             NSString *strRefreshToken = [dictRes objectForKey:@"refresh_token"];
             NSString *strTokenType = [dictRes objectForKey:@"token_type"];
             NSString *sstrExpiresIn = [dictRes objectForKey:@"expires_in"];

             [[NSUserDefaults standardUserDefaults] setObject:globalShare.strRefreshToken forKey:@"refresh_token"];
             [[NSUserDefaults standardUserDefaults] setObject:globalShare.strAccessToken forKey:@"access_token"];
             [[NSUserDefaults standardUserDefaults] synchronize];

             NSDictionary *responseDict = [GlobalShareClass getDataFromToken:globalShare.strAccessToken];


             NSString *strFetchedSub = [[NSUserDefaults standardUserDefaults] stringForKey:@"loginIdSub"];


             globalShare.loginId = [responseDict objectForKey:@"sub"];

        
      
      else
         NSLog(@"The res starts with array");
      


  failure:^(NSError *error) 
     // error handling here ...
     NSLog(@"%@", [error localizedDescription]);
     dispatch_async(dispatch_get_main_queue(), ^
        //Showing Error
     );
  passViewController:self];

@catch(NSException *exception)
    NSLog(@"%@",[exception description]);

@finally




GlobalShareClass.h

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@interface GlobalShareClass : NSObject
   NSMutableArray  *arr;


@property (strong, nonatomic) NSMutableArray  *arr;
+ (GlobalShareClass *)sharedInstance;
+ (void)postLoginDataToServer:(NSString *)url passParameters:(id)parameter success:(void (^)(id res))successPost failure:(void(^)(NSError* error))failurePost passViewController:(UIViewController *)vc;
+ (NSDictionary *)getDataFromToken:(NSString *)strToken;
+ (NSDictionary *)urlBase64Decode:(NSString *)strToParse;

@end

GlobalShareClass.m

#import "GlobalShareClass.h"

@implementation GlobalShareClass
@synthesize arr;

+ (GlobalShareClass *)sharedInstance 
   static GlobalShareClass* _shareInstane = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        _shareInstane = [[GlobalShareClass alloc] init];
        //Incase array of initialization
        _shareInstane.arr = [[NSMutableArray alloc] init];
    );

    return _shareInstane;



 + (void)postLoginDataToServer:(NSString *)url passParameters:(id)parameter success:(void (^)(id res))successPost failure:(void(^)(NSError* error))failurePost passViewController:(UIViewController *)vc
    GlobalShareClass *globalShare = [GlobalShareClass sharedInstance];
    __block id jsonResp;
    NSData *data = [parameter dataUsingEncoding:NSUTF8StringEncoding];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"content-type"];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    NSURLSessionUploadTask *dataTask = [session uploadTaskWithRequest: request
                                                             fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
                                                                 if(data == nil && error)
                                                                     NSLog(@"uploadTaskWithRequest error: %@", error);


                                                                     failurePost(error);
                                                                 
                                                                 else
                                                                     jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

                                                                     NSString *strStatusCode = [NSString stringWithFormat:@"%ld",(long)[((NSHTTPURLResponse *)response) statusCode]];
                                                                     if([strStatusCode isEqualToString:@"400"])

                                                                         successPost(jsonResp);
                                                                     
                                                                     NSString *strStatusCodeResponse = [self strGetStatusResponseCode:strStatusCode];
                                                                     if([strStatusCodeResponse length] > 0)
                                                                         dispatch_async(dispatch_get_main_queue(), ^
                                                                     // Showing error                                                                            

                                                                         );
                                                                         else
                                                                         jsonResp = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                                                                         if([jsonResp objectForKey:@"error"] || jsonResp == nil)
                                                                             dispatch_async(dispatch_get_main_queue(), ^

                                                                       [self showAlertController:@"Error" :[jsonResp objectForKey:@"error_description"] passViewController:vc];
                                                                             );
                                                                         
                                                                         else
                                                                             successPost(jsonResp);
                                                                     
                                                                 
                                                             ];
    [dataTask resume];



+ (NSDictionary *)getDataFromToken:(NSString *)strToken 
    NSDictionary *data;
    NSString *encoded = [strToken componentsSeparatedByString:@"."][1];
    data = [GlobalShareClass urlBase64Decode:encoded];
    return data;




 + (NSDictionary *)urlBase64Decode:(NSString *)strToParse 
    @try 
        NSDictionary *returnDict;
        NSString *output = [strToParse stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
        output = [output stringByReplacingOccurrencesOfString:@"_" withString:@"/"];

        switch (output.length % 4) 
            case 0:
            case 1:
                break;
            case 2:
                output = [output stringByAppendingString:@"=="];
                break;
            case 3:
                output = [output stringByAppendingString:@"="];
                break;
            default:
                break;
        

        NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:output options:0];
        NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
        NSLog(@"%@", decodedString);

        NSData *data = [decodedString dataUsingEncoding:NSUTF8StringEncoding];
        returnDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

        return returnDict;
    
    @catch (NSException *exception) 
        NSLog(@"%@", [exception description]);
    


@end

【讨论】:

以上是关于在 Objective-C 中使用身份验证获取 JSON 令牌的主要内容,如果未能解决你的问题,请参考以下文章

使用 Objective-C 和 C++ 实现 X-FACEBOOK-PLATFORM 身份验证的身份验证失败

从 Objective-C 向 IIS 发送请求时需要身份验证

使用 j_security_check 在 Java EE / JSF 中执行用户身份验证

使用 AFNetworking 的基本身份验证

从 android 设备生成的 Linkedin 身份验证令牌在 Web 服务器上不起作用

如何使用 j_security_check 在 React.JS 应用程序上对用户进行身份验证