我有一个GAE应用程序,其端点需要身份验证,我从应用程序(而不是在浏览器中)调用。
以下是来自web.xml的端点的GAE规范
<!-- Secure sensitive URLs -->
<security-constraint>
<web-resource-collection>
<url-pattern>/gcm/home</url-pattern>
<url-pattern>/gcm/send</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
以前,在客户端应用程序中,我在调用端点之前使用ClientLogin对Google进行身份验证。这是我正在使用的代码,它提取“Auth”令牌,然后将其用作HTTP GET上的Cookie到上述端点。
public static String loginToGoogle(String userid, String password,
String appUrl) throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(
"https://www.google.com/accounts/ClientLogin");
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("accountType", new StringBody("HOSTED_OR_GOOGLE",
"text/plain", Charset.forName("UTF-8")));
reqEntity.addPart("Email", new StringBody(userid));
reqEntity.addPart("Passwd", new StringBody(password));
reqEntity.addPart("service", new StringBody("ah"));
reqEntity.addPart("source", new StringBody("WWWWmyappname"));
post.setEntity(reqEntity);
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == 200) {
InputStream input = response.getEntity().getContent();
String result = IOUtils.toString(input);
String authToken = getAuthToken(result);
post = new HttpPost(appUrl + "/_ah/login?auth=" + authToken);
response = client.execute(post);
Header[] cookies = response.getHeaders("SET-COOKIE");
for (Header cookie : cookies) {
if (cookie.getValue().startsWith("ACSID=")) {
return cookie.getValue();
}
}
throw new Exception("ACSID cookie cannot be found");
} else
throw new Exception("Error obtaining ACSID");
}
private static String getAuthToken(String responseText) throws Exception {
LineNumberReader reader = new LineNumberReader(new StringReader(
responseText));
String line = reader.readLine();
while (line != null) {
line = line.trim();
if (line.startsWith("Auth=")) {
return line.substring(5);
}
line = reader.readLine();
}
throw new Exception("Could not find Auth token");
}
由于ClientLogin已弃用然后被删除,我相信我不得不切换到OAuth2。阅读文档让我相信我需要一个服务帐户来实现这个目的,我在Google控制台中为GAE正式设置了这个帐户。 虽然GoogleCredential构建器成功返回授权令牌,但如果我在对端点的HTTP get调用中使用该令牌,则响应始终是Google Login页面。
为什么,如果我使用令牌,GAE不会认为我已登录并获得授权?我这样做是错误还是错过了一步?
以下是尝试通过Google进行身份验证然后调用GAE端点的代码:
String emailAddress = "XXXXXXXX@developer.gserviceaccount.com";
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
String emailScope = "https://www.googleapis.com/auth/userinfo.email";
String keyFileName = "YYYYY.p12";
String baseURL = "http://ZZZZZ.appspot.com";
HttpTransport httpTransport;
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
File keyFile = new File(keyFileName);
if(!keyFile.exists()) {
System.err.println("Key file "+keyFileName+" missing");
System.exit(0);
}
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(emailAddress)
.setServiceAccountScopes(Collections.singleton(emailScope))
.setServiceAccountPrivateKeyFromP12File(keyFile)
.build();
boolean success = credential.refreshToken();
System.out.println("Access token refresh "+ success);
String token = credential.getAccessToken();
System.out.println("Token "+token);
String uri = "http://ZZZZZ.appspot.com/gcm/home";
System.out.println("uri: " + uri);
HttpGet get = new HttpGet(uri);
get.setHeader("Cookie", token);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
response.getEntity().writeTo(System.out);
典型输出:
Access token refresh true
Token ya29.xQGG1kxxxxxxxxxxxxxxxxxxx
uri: http://ZZZZZ.appspot.com/gcm/home
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=300, initial-scale=1" name="viewport">
<meta name="google-site-verification" content="LrdTUW9psUAMbh4Ia074-BPEVmcpBxF6Gwf0MSgQXZs">
<title>Sign in - Google Accounts</title>
.....
谢谢!