Last active
December 16, 2015 20:49
-
-
Save shin1ogawa/5494912 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.shin1ogawa.controller; | |
import java.io.IOException; | |
import java.io.PrintWriter; | |
import java.io.UnsupportedEncodingException; | |
import java.net.HttpURLConnection; | |
import java.net.URL; | |
import java.net.URLEncoder; | |
import java.util.Map; | |
import javax.servlet.http.Cookie; | |
import javax.servlet.http.HttpServletRequest; | |
import org.codehaus.jackson.map.ObjectMapper; | |
import org.slim3.controller.Controller; | |
import org.slim3.controller.Navigation; | |
import org.slim3.util.StringUtil; | |
import com.google.common.io.ByteStreams; | |
public class IndexController extends Controller { | |
static final String CLIENT_ID = ""; // FIXME | |
static final String CLIENT_SECRET = ""; // FIXME | |
static final String PROJECT_ID = ""; // FIXME | |
static final String PATH = "/"; | |
static final String CHARCTER_ENCODING = "utf-8"; | |
static final String SCOPES = "https://www.googleapis.com/auth/glass.timeline" | |
+ " https://www.googleapis.com/auth/glass.location" | |
+ " https://www.googleapis.com/auth/userinfo.profile"; | |
@Override | |
protected Navigation run() throws Exception { | |
String refreshToken = loadRefreshTokenFromCookie(); | |
if (StringUtil.isEmpty(refreshToken) == false) { | |
return doSomething(refreshToken); | |
} else { | |
String authorizationCode = request.getParameter("code"); | |
if (StringUtil.isEmpty(authorizationCode)) { | |
return redirectToRetrieveAuthorizationCode(); | |
} else { | |
return retrieveToken(authorizationCode); | |
} | |
} | |
} | |
Navigation doSomething(String refreshToken) throws IOException { | |
String accessToken = Util.refreshAccessToken(CLIENT_ID, CLIENT_SECRET, | |
refreshToken); | |
// mirror API list timeline を実行する | |
// https://developers.google.com/glass/v1/reference/timeline/list | |
URL url = new URL("https://www.googleapis.com/mirror/v1/timeline"); | |
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); | |
connection.setRequestProperty("Authorization", "Bearer " + accessToken); | |
byte[] bytes = ByteStreams.toByteArray(connection.getInputStream()); | |
String responseAsString = new String(bytes, CHARCTER_ENCODING); | |
saveRefreshTokenAsCookie(refreshToken); | |
response.setContentType("text/plain"); | |
response.setCharacterEncoding(CHARCTER_ENCODING); | |
PrintWriter writer = response.getWriter(); | |
writer.println("refreshToken=" + refreshToken); | |
writer.println("refreshed accessToken=" + accessToken); | |
writer.println(); | |
writer.print(responseAsString); | |
writer.println(); | |
response.flushBuffer(); | |
return null; | |
} | |
Navigation retrieveToken(String authorizationCode) throws IOException { | |
Map<String, String> tokens = Util.getTokensWithAuthorizationCode( | |
request, authorizationCode); | |
String refreshToken = tokens.get("refresh_token"); | |
saveRefreshTokenAsCookie(refreshToken); | |
return new Navigation(PATH, true); | |
} | |
Navigation redirectToRetrieveAuthorizationCode() | |
throws UnsupportedEncodingException { | |
String redirectURI = Util.buildRedirectURIForOAuth2(request, | |
IndexController.PATH); | |
String redirectTo = new StringBuilder( | |
"https://accounts.google.com/o/oauth2/auth?") | |
.append("response_type=code").append("&client_id=") | |
.append(URLEncoder.encode(CLIENT_ID, CHARCTER_ENCODING)) | |
.append("&redirect_uri=").append(redirectURI).append("&scope=") | |
.append(URLEncoder.encode(SCOPES, CHARCTER_ENCODING)) | |
.append("&access_type=offline&approval_prompt=force") | |
.toString(); | |
return redirect(redirectTo); | |
} | |
String loadRefreshTokenFromCookie() { | |
String refreshToken = null; | |
Cookie[] cookies = request.getCookies(); | |
if (cookies != null) { | |
for (Cookie cookie : cookies) { | |
if ("refresh_token".equals(cookie.getName()) == false) { | |
continue; | |
} | |
refreshToken = cookie.getValue(); | |
} | |
} | |
return refreshToken; | |
} | |
void saveRefreshTokenAsCookie(String refreshToken) { | |
Cookie cookie = new Cookie("refresh_token", refreshToken); | |
response.addCookie(cookie); | |
} | |
static class Util { | |
static String refreshAccessToken(String clientId, String clientSecret, | |
String refreshToken) throws IOException { | |
// パラメータを組み立てる | |
StringBuilder b = new StringBuilder(); | |
b.append("&client_id=") | |
.append(URLEncoder.encode(clientId, "utf-8")); | |
b.append("&client_secret=").append( | |
URLEncoder.encode(clientSecret, "utf-8")); | |
b.append("&refresh_token=").append( | |
URLEncoder.encode(refreshToken, "utf-8")); | |
b.append("&grant_type=refresh_token"); | |
byte[] payload = b.toString().getBytes(); | |
// POST メソッドでリクエストする | |
HttpURLConnection c = (HttpURLConnection) new URL( | |
"https://accounts.google.com/o/oauth2/token") | |
.openConnection(); | |
c.setRequestMethod("POST"); | |
c.setDoOutput(true); | |
c.setRequestProperty("Content-Length", | |
String.valueOf(payload.length)); | |
c.getOutputStream().write(payload); | |
c.getOutputStream().flush(); | |
@SuppressWarnings("unchecked") | |
Map<String, Object> map = new ObjectMapper().readValue( | |
c.getInputStream(), Map.class); | |
return (String) map.get("access_token"); | |
} | |
static Map<String, String> getTokensWithAuthorizationCode( | |
HttpServletRequest request, String authorizationCode) | |
throws IOException { | |
String redirectURI = buildRedirectURIForOAuth2(request, | |
IndexController.PATH); | |
String queryString = new StringBuilder().append("&code=") | |
.append(URLEncoder.encode(authorizationCode, "utf-8")) | |
.append("&client_id=") | |
.append(URLEncoder.encode(CLIENT_ID, "utf-8")) | |
.append("&client_secret=") | |
.append(URLEncoder.encode(CLIENT_SECRET, "utf-8")) | |
.append("&redirect_uri=").append(redirectURI) | |
.append("&grant_type=authorization_code").toString(); | |
byte[] payload = queryString.getBytes("utf-8"); | |
URL url = new URL("https://accounts.google.com/o/oauth2/token"); | |
HttpURLConnection connection = (HttpURLConnection) url | |
.openConnection(); | |
connection.setRequestMethod("POST"); | |
connection.setRequestProperty("Content-Length", | |
String.valueOf(payload.length)); | |
connection.setDoOutput(true); | |
connection.getOutputStream().write(payload); | |
connection.getOutputStream().flush(); | |
@SuppressWarnings("unchecked") | |
Map<String, String> responseAsMap = new ObjectMapper().readValue( | |
connection.getInputStream(), Map.class); | |
return responseAsMap; | |
} | |
static String buildRedirectURIForOAuth2(HttpServletRequest request, | |
String path) throws UnsupportedEncodingException { | |
StringBuilder b = new StringBuilder(); | |
b.append(request.getScheme()).append("://") | |
.append(request.getServerName()); | |
if (request.getServerPort() != 443 && request.getServerPort() != 80) { | |
b.append(":").append(request.getServerPort()); | |
} | |
b.append(path); | |
String redirectURI = URLEncoder.encode(b.toString(), | |
CHARCTER_ENCODING); | |
return redirectURI; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Slim3用。Jacksonに依存。
API ConsoleのClientIDのRedirectURIの設定に http://{YOUR-APP-ID}.appspot.com/ を追加する。