Я заметил, что добавить аутентификацию в существующую конечную точку AppEngine очень просто - вам просто нужно добавить параметр com.google.appengine.api.users.User в ваш метод.И вот наконец я обнаружил, что происходит под капотом и как таким же образом аутентифицировать произвольный сервлет.Поэтому для аутентификации на стороне Android вам необходимо: 1) выбрать учетную запись:
private void signIn()
{
startActivityForResult(GoogleAccountCredential.usingAudience(this, "server:client_id:{id}.apps.googleusercontent.com").newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case REQUEST_ACCOUNT_PICKER:
if (data != null && data.getExtras() != null)
{
String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null)
{
// TODO save accountName
}
}
break;
}
}
2) получить объект Credential:
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, "server:client_id:{id}.apps.googleusercontent.com");
credential.setSelectedAccountName(accountName);
3) создать объект Google HttpRequest и сделать запрос:
HttpTransport transport = new NetHttpTransport();
HttpRequestFactory requestFactory = transport.createRequestFactory(credential);
GenericUrl url = new GenericUrl(UPLOAD_SERVICE_URL);
HttpRequest request = requestFactory.buildGetRequest(url);
HttpResponse resp = request.execute();
// TODO check response
Для аутентификации запроса на стороне AppEngine вы можете использовать внутренний класс WebApisUserService, объявленный в библиотеке "appengine-endpoints.jar".Это просто класс, используемый внутри AppEngine в конечных точках.К сожалению, этот конструктор класса и другие необходимые методы защищены от внешнего использования, поэтому нам нужно использовать отражение для доступа к нему.Полный класс помощников следующий:
public class WebApisUserServiceHelper
{
public static WebApisUserService createInstance(boolean isClientIdWhitelistEnabled)
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException
{
Constructor<WebApisUserService> constructor;
constructor = WebApisUserService.class.getDeclaredConstructor(Boolean.TYPE);
constructor.setAccessible(true);
WebApisUserService ret = constructor.newInstance(isClientIdWhitelistEnabled);
return ret;
}
public static User getCurrentUser(WebApisUserService service, HttpServletRequest req, String appName, List<String> audiences, List<String> clientIds)
throws NoSuchMethodException, SecurityException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
String token = getAuthToken(service, req);
if (token != null)
{
List<String> allowedScopes = new ArrayList<String>();
allowedScopes.add("https://www.googleapis.com/auth/userinfo.email");
return getCurrentUser(service, token, allowedScopes, audiences, clientIds);
}
return null;
}
private static User getCurrentUser(WebApisUserService service, String token, List<String> allowedScopes, List<String> allowedAudiences, List<String> allowedClientIds)
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Method method = WebApisUserService.class.getDeclaredMethod("getCurrentUser", String.class, List.class, List.class, List.class);
method.setAccessible(true);
Object ret = method.invoke(service, token, allowedScopes, allowedAudiences, allowedClientIds);
if (ret instanceof User) return (User) ret;
return null;
}
private static String getAuthToken(WebApisUserService service, HttpServletRequest request)
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Method method = WebApisUserService.class.getDeclaredMethod("getAuthToken", HttpServletRequest.class);
method.setAccessible(true);
Object ret = method.invoke(service, request);
if (ret instanceof String) return (String) ret;
return null;
}
}
, и вот как использовать этот помощник:
public class MyServlet extends HttpServlet
{
private final WebApisUserService auth = createAuthService();
private static WebApisUserService createAuthService()
{
try
{
return WebApisUserServiceHelper.createInstance(false);
}
catch (Exception e)
{
log.log(Level.WARNING, "Failed to create WebApisUserServiceFactory instance. Exception: %s", e.toString());
}
return null;
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
try
{
User user = authenticateUserSafe(req);
if (user == null)
{
resp.sendError(401, "auth required");
return;
}
String str = String.format("User id: %s, nick: %s, email: %s", user.getUserId(), user.getNickname(), user.getEmail());
resp.getWriter().write(str);
}
catch (Throwable e)
{
resp.getWriter().write("Exception: " + e);
}
}
private User authenticateUserSafe(HttpServletRequest req)
{
try
{
return authenticateUser(req);
}
catch (Exception e)
{
log.log(Level.WARNING, "Failed to authenticate user. Exception: %s", e.toString());
}
return null;
}
private User authenticateUser(HttpServletRequest req)
throws NoSuchMethodException, SecurityException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
List<String> audiences = new ArrayList<String>();
audiences.add(Ids.ANDROID_AUDIENCE);
List<String> clientIds = new ArrayList<String>();
clientIds.add(Ids.WEB_CLIENT_ID);
clientIds.add(Ids.ANDROID_CLIENT_ID);
return WebApisUserServiceHelper.getCurrentUser(auth, req, "{id}", audiences, clientIds);
}
}
Этот подход проверен с помощью AppEngine 1.8.6.Я надеюсь, что Google откроет класс WebApisUserService публично, поэтому рефлексия не потребуется.