使用GoogleCredential和服务帐户通过Google App Engine服务进行身份验证

时间:2015-08-04 17:52:40

标签: google-app-engine authentication google-oauth2 google-client-login

我有一个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>
      .....

谢谢!

0 个答案:

没有答案