5

我正在努力获取 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; }

任何帮助都非常感谢。

4

4 回答 4

2

OAuth2定义了 4 种获取访问令牌的方法。最安全和最复杂的是Quizlet 使用的授权码授予,如此所述。

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

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

你第一次打电话是对的。第二次调用的问题是您将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 是不安全的:如果您不做一些额外的工作,您的应用程序很容易受到跨站点请求伪造攻击,甚至在 OAuth2 RFC 中也提到过。为了防止这种情况,OAuth2 为您提供了state参数。您必须为您生成一个不可猜测的值state并将其包含在第一个请求中。state如果服务器返回的与您之前生成的不同,则不能触发第二个请求。

于 2013-08-30T11:00:37.593 回答
1

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

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

于 2013-08-17T16:14:04.163 回答
0

将您的 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
于 2013-08-27T19:21:07.810 回答
0

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

需要定义 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 
于 2021-03-02T08:10:22.043 回答