【问题标题】:Invalid grant_type parameter or parameter missing on POST for requesting access token用于请求访问令牌的 POST 上的 grant_type 参数或参数无效
【发布时间】:2013-08-19 15:22:42
【问题描述】:

我正在努力获取 Quizlet (oauth2) 上的访问令牌。到目前为止一切正常,我可以让用户在 Quizlet 上接受我的应用程序,得到重定向,但是当通过 NSURLConnection 请求访问令牌时,我总是收到以下错误:

2013-08-17 09:39:33.422 Abiliator[49549:c07] 以字符串格式返回数据:{"http_code":400,"error":"invalid_request","error_title":"Not Allowed"," error_description":"grant_type 参数无效或缺少参数"}

这里是用户认证的代码(根据规范必须通过浏览器):

- (void) authenticateQuizletUser
{

NSString *quizletRandomString = [abiliatorAppDelegate GetUUID];
NSString *authURLString = [@"https://quizlet.com/authorize/?response_type=code&client_id=" stringByAppendingString:@"<myID>&scope=read"];
authURLString = [authURLString stringByAppendingString:@"&state="];
authURLString = [authURLString stringByAppendingString:quizletRandomString];
authURLString = [authURLString stringByAppendingString:@"&redirect_uri=Abiliator://after_oauth"];

NSLog(@"Authentication URL sent: %@", authURLString);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: authURLString]];

}

正如我所提到的,这很好用。应用程序启动 Safari,用户必须确认输入用户 ID 和密码的请求,服务器重定向到我的应用程序,我在下面的方法中捕获,然后抛出描述的错误。

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
if (!url) {  return NO; }
NSString *URLString = [url absoluteString];
NSLog(@"Received URL: %@", URLString);
NSString *myURLQuery = [url query];
NSString *myAuthCode = [self getAuthorizationCodeFromURL:myURLQuery];
NSLog(@"Component1: %@", myAuthCode);
NSString *authPasswd = @"myPasswd";
NSString *username=@"myUserName";

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.quizlet.com/oauth/token"]];

request.HTTPMethod = @"POST";

[request setValue:@"application/x-www-form-urlencoded; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"Abiliator://after_oauth" forHTTPHeaderField:@"redirect_uri"];

// According to Quizlet API doc: You must set this (grant_type) to the string "authorization_code". 
[request setValue:@"authorization_code" forHTTPHeaderField:@"grant_type"];
[request setValue:myAuthCode forHTTPHeaderField:@"code"];

NSString *authStr = [NSString stringWithFormat:@"%@:%@", username, authPasswd];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodedString]];
[request setValue:authValue forHTTPHeaderField:@"Authorization"];

NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];


return YES; }

非常感谢任何帮助。

【问题讨论】:

    标签: iphone objective-c oauth-2.0 nsurlconnection


    【解决方案1】:

    OAuth2 defines 4 ways 获取访问令牌。最安全和最复杂的是 Quizlet 使用的Authorization Code Grant,如here 所述。

    授权码授予包括两个步骤:

    • 获取授权码(在流程通过重定向传回给您之前,用户在您的应用外部进行身份验证)
    • 将授权码更改为访问令牌

    你第一次打电话是对的。第二次调用的问题是您将grant_type 参数放在请求的错误位置。 在这一行中,您将其视为 HTTP 标头:

    [request setValue:@"authorization_code" forHTTPHeaderField:@"grant_type"];
    

    在这里你也把授权码当作一个 HTTP 头:

    [request setValue:myAuthCode forHTTPHeaderField:@"code"];
    

    但 OAuth2 要求您将两者都放入请求正文中。以下是正确请求的示例:

    POST /oauth/token/ HTTP/1.1
    Content-Type: application/x-www-form-urlencoded;charset=UTF-8
    Content-Length: 999
    Authorization: Basic xxx
    
    grant_type=authorization_code&code=theCodeYouGotInTheFirstStep&
    scope=somescope&redirect_uri=theSameUriYouIncludedEarlier
    

    (空行下方的内容是您的请求正文)
    (我在正文中添加了换行符只是为了便于阅读——你不能在请求中包含它)

    奖励答案:请记住 OAuth2 默认情况下是不安全的:如果您不做一些额外的工作,您的应用程序很容易受到Cross-Site Request Forgery 攻击,甚至mentioned in the OAuth2 RFC。为了防止这种情况,OAuth2 为您提供了state 参数。您必须为您的 state 生成一个不可猜测的值,并将其包含在第一个请求中。如果服务器返回的 state 与您之前生成的不同,则不能触发第二个请求。

    【讨论】:

    • 非常感谢。至于安全性,我确实传递了 state 参数,请参阅我的问题中的第一个代码。我只是还没有实施验证检查。至于身体,我也试过这个,同样的结果。我用我已经实现的 body sn-p 更新了我的帖子。
    • @renesteg 没有其他人可以看到您的剪辑,因为编辑被拒绝了,但是您也忽略了 grant_type ,而是插入了属于标题的内容,例如内容类型和基本授权。请用我放在答案中的字符串再试一次。
    • 奇怪的是编辑被拒绝了,无论如何,这里是我用于正文方法的片段:[bodyData appendData:[postMethodString dataUsingEncoding:NSUTF8StringEncoding]]; [bodyData appendData:[authCodeString dataUsingEncoding:NSUTF8StringEncoding]]; [bodyData appendData:[contentTypeString dataUsingEncoding:NSUTF8StringEncoding]]; [bodyData appendData:[basicAuthorizationString dataUsingEncoding:NSUTF8StringEncoding]];然后我使用 [request setHTTPBody:bodyData];应该没问题吧?
    【解决方案2】:

    可能有助于查看您的其余实施。您如何获得code?另外,您使用的是什么凭据(authPasswd & username)?这些应该是您的应用程序(而不是最终用户的)。您可以在 Quizlet 的开发仪表板中获得这些信息。

    注意:不建议设备使用此 OAuth 流程,因为它需要将机密存储在设备中。使用 implicit 流程是可行的,但我不确定 Quizlet 是否支持它。

    【讨论】:

    • 感谢 Eugenio 的反馈。我正在使用 Quizlet 指定的应用程序凭据:我编辑了我的帖子以显示 oauth 2 流程的第一步。完全没有问题。我唯一还没有做的就是比较发送的随机字符串的状态。但这根本不应该是一个问题,因为这只是应用程序端的额外安全性。至于您的注释:隐式流是什么意思?
    • 表面上看起来一切都很好...您可以放置​​网络跟踪以查看请求令牌时实际发送的内容吗? “隐式”只是另一个流程,您可以在其中直接请求令牌(无代码交换)。看到这个:stackoverflow.com/questions/16321455/…
    • 这是三足流。当客户端受信任时使用隐式授权。隐式减少了将身份验证代码发送回客户端的流程,否则,客户端必须提供其凭据和参数以及身份验证代码以生成访问令牌,一个主要原因是验证是否提供身份验证代码购买相同的客户端它是为它生成的,(redirect_uri 在这里是强制性的)。
    • 如果您必须在设备上存储凭据,请务必使用钥匙串 API
    • @nielsbot OAuth2 授权代码授予的全部意义在于,用户的凭据不会存储在您的设备上,甚至不会交给客户端应用程序。
    【解决方案3】:

    将您的 oauth 参数作为有效负载发送。您不应该将它们作为标题发送。例如,您的请求应如下所示

    POST /token 
    
    Headers:
    
    Authorization: Basic R0cxSWJdHpINDVhang5Y0VlSUxxalBSOW5SU0NBWA==
    
    Content-Type: application/x-www-form-urlencoded
    
    Payload:
    
    grant_type=authorization_code&code=Wirr951e&scope=READ&redirect_uri=www.google.com
    

    【讨论】:

      【解决方案4】:

      我也遇到过类似的问题,这对我有用。

      需要正确定义Header(如果我解释它是空手道脚本方式),

       * def keycloak_extension = "keycloak authorization to generate the access token put here"
      
       * configure headers = {'Content-Type':"application/x-www-form-urlencoded",'Authorization':#("Basic " +keycloakAuthSecret)}
          
       Given path keycloak_extension
       And form field grant_type = 'client_credentials'
       And request '{}'
       When method post
       And status 200
       * def accessToken = response.access_token ```
      
      
      How to encode using Base64 can use this link:
      https://www.base64decode.org/ 
      
      Can also refer to this video, to understand it better:
      https://www.youtube.com/watch?v=k-Q-Kywk1O4 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-23
        • 1970-01-01
        相关资源
        最近更新 更多