我正在努力获取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; }
任何帮助都很高兴。
答案 0 :(得分:1)
可能有助于查看其余的实施。你是如何获得code
的?此外,您使用的凭据(authPasswd
&amp; username
)是什么?这些应该是你的应用程序(而不是最终用户)。你可以在Quizlet的Dev Dashboard中获得这些。
注意:建议不要将此OAuth流用于设备,因为它需要将密钥存储在设备中。使用
implicit
流是,但我不确定Quizlet是否支持它。
答案 1 :(得分: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
与您之前生成的{{1}}不同,则不得触发第二个请求。
答案 2 :(得分: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
答案 3 :(得分: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