问题
当使用Google Plus登录Api和Play Framework时,你必须以不同的方式设置标题吗?我是不是做错了什么?
背景
我使用Play Framework(Java)在Api中使用Google Plus登录
我在OAuth身份验证的第二阶段遇到了问题,将Authorization Code
交换为Token
。
基本OAuth流
漂亮图片
- 将用户重定向到
User login/Consent screen
- 这会询问用户是否要授予您对请求作用域的应用程序权限
- 网址:
https://accounts.google.com/o/oauth2/auth
- 用
Authorization Code
交换Token
- 如果用户授予您的应用程序权限,那么他们将被重定向到您指定的URL,在该URL中(作为
GET
参数)将是Authorization Code
- 然后,您的应用程序可以使用此
Authoriztion Code
从服务器获取Token
- 您的应用程序通过向Google服务器(或您正在使用的任何服务)上的端点发出HTTP请求来实现这一点
- 网址:
https://accounts.google.com/o/oauth2/token
- 网址:
- 如果用户授予您的应用程序权限,那么他们将被重定向到您指定的URL,在该URL中(作为
- 在API请求中使用
Token
问题
要使用Google Plus登录Api将Authorization Code
交换为Token
,您必须使用以下周长向https://accounts.google.com/o/oauth2/token
发出POST
请求
{
"code": "Security Code Returned from Step 1",
"client_id": "Client Id that was given to you in GApi Console",
"client_secret": "Client Secret that was given to you in the GApi Console",
"redirect_uri": "Redirect Uri you specified in the GApi Console",
"grant_type": "authorization_code"
}
然而,当我用所有正确的参数提出这个请求时,我得到了这个错误
{
"error" : "invalid_request",
"error_description" : "Required parameter is missing: grant_type"
}
从Google Plus登录Api
要在Play Framework中发出HTTP请求,请使用WS Library
。我提出这样的要求
public static F.Promise<Result> OAuthCallback(String state, String code){
/*
Note:
- The GoogleStrategy class is just a class that holds all my GApi credentials
- The parameters (String state, String code) are just GET params from Step 1, returned by the GApi
*/
//Make URL builder
WSRequestHolder requestHolder = WS.url(GoogleStrategy.getTokenUrl);
//Set headers
requestHolder.setHeader("code", code);
requestHolder.setHeader("client_id", GoogleStrategy.clientId);
requestHolder.setHeader("client_secret", GoogleStrategy.clientSecret);
requestHolder.setHeader("redirect_uri", GoogleStrategy.redirectUri);
requestHolder.setHeader("grant_type", GoogleStrategy.grantType);//GoogleStrategy.grantType = "authorization_code"
//Make HTTP request and tell program what to do once the HTTP request is finished
F.Promise<Result> getTokenPromise = requestHolder.post("").map(
new F.Function<WSResponse, Result>() {
public Result apply(WSResponse response){
return ok(response.asJson());//Returning result for debugging
}
}
);
return getTokenPromise;//Return promise, Play Framework will handle the Asynchronous stuff
}
如您所见,我设置了标题grant_type
。为了确保设置头有效,我制作了一个程序,在NodeJS(Source)中吐出请求的头,这就是的结果
{
"HEADERS": {
"host": "127.0.0.1:3000",
"code": "4/qazYoReIJZAYO9izlTjjJA.gihwUJ6zgoERgtL038sCVnsvSfAJkgI",
"grant_type": "authorization_code",
"client_secret": "XXXX-CENSORED FOR SECURITY PURPOSES-XXX",
"redirect_uri": "http://127.0.0.1:9000/api/users/auth/google/callback",
"client_id": "XXXX-CENSORED FOR SECURITY PURPOSES-XXX",
"content-type": "text/plain; charset=utf-8",
"connection": "keep-alive",
"accept": "*/*",
"user-agent": "NING/1.0",
"content-length": "14"
}
}
我认为这些不是作为标题发送的,而是作为正文发送的。在您提供的链接中有一个示例:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
所以把它们传给你的post
呼叫:
StringBuilder sb = new StringBuilder();
sb.append("code=").append(code)
.append("&client_id=").append(GoogleStrategy.clientId)
.append("&client_secret=").append( GoogleStrategy.clientSecret)
.append("&redirect_uri=").append(GoogleStrategy.redirectUri)
.append("&grant_type=").append(GoogleStrategy.grantType)
requestHolder.setContentType("application/x-www-form-urlencoded")
.post(sb.toString());