Как защитить свой API, который был создан с использованием Google Cloud Endpoints?
API - это бэкэнд для мобильного приложения. Мне не нужна аутентификация пользователей. Мне просто нужен способ защитить доступ к этому API. В настоящее время мой бэкэнд выставлен.
документация, похоже, говорит только об аутентификации пользователей и авторизации, что здесь не так. Мне просто нужно обеспечить, чтобы только мое мобильное приложение могло разговаривать с этим бэкэнд и ни с кем другим.
Ответы
Ответ 1
Да, вы можете сделать это: использовать аутентификацию для защиты своих конечных точек без проверки подлинности пользователя.
Я обнаружил, что этот способ сделать это плохо документирован, и я на самом деле не сделал этого сам, но я намерен так, что я обратил внимание, когда увидел, что он обсуждается на некоторых видео IO13 (я думаю, что там, где я его видел):
Здесь мое понимание того, что связано:
- Создайте проект API Google (хотя на самом деле это не связано с их API, кроме собственно аутентификации).
- Создайте идентификатор клиента OATH, привязанный к вашему приложению с помощью его имени пакета и отпечатка пальца SHA1 сертификата, с которым вы подпишете приложение.
Этот идентификатор клиента будет добавлен в список допустимых идентификаторов для ваших конечных точек. Вы добавите параметр User в свои конечные точки, но он будет пустым, поскольку пользователь не указан.
@ApiMethod(
name = "sendInfo",
clientIds = { Config.WEB_CLIENT_ID, Config.MY_APP_CLIENT_ID, Config.MY_DEBUG_CLIENT_ID },
audiences = { Config.WEB_CLIENT_ID }
// Yes, you specify a 'web' ID even if this isn't a Web client.
)
public void sendInfo(User user, Info greeting) {
Существует достаточно приличная документация об этом выше:
https://developers.google.com/appengine/docs/java/endpoints/auth
Ваше клиентское приложение будет указывать эти идентификаторы клиента при формулировании вызова службы конечной точки. Все данные OATH будут позаботиться о месте вашего клиентского устройства за кадром, чтобы ваш идентификатор клиента был переведен на токены аутентификации.
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience( ctx, Config.WEB_CLIENT_ID );
//credential.setSelectedAccountName( user ); // not specify a user
Myendpoint.Builder builder = new Myendpoint.Builder( transport, jsonFactory, credential );
Этот код клиента - это только мое лучшее предположение - извините. Если у кого-то еще есть ссылка на то, что должен выглядеть клиентский код, то мне тоже будет интересно.
Ответ 2
Извините, что Google не предоставляет решение вашей проблемы (это тоже моя проблема).
Вы можете использовать их механизм ключей API (см. https://developers.google.com/console/help/new/#usingkeys), но есть огромная дыра в этой стратегии, предоставляемая Google собственным API-исследователем ( см. https://developers.google.com/apis-explorer/#p/), который является отличным инструментом для тестирования API, но предоставляет все API-интерфейсы Cloud Endpoint API, а не только API-интерфейсы служб Google. Это означает, что любой, кто имеет название вашего проекта, может просматривать и вызывать ваш API на досуге, так как API-интерфейс обходит защиту ключа API.
Я нашел обходное решение (на основе отличного ответа bossylobster на этот пост: API простого доступа (ключ разработчика) с облачной конечной точкой Google (Python)), который должен передать запрос поле, которое не является частью определения запроса сообщения в вашем клиентском API, а затем читайте его на сервере API. Если вы не нашли недокументированное поле, вы поднимаете несанкционированное исключение. Это закроет отверстие, созданное исследователем API.
В iOS (который я использую для своего приложения) вы добавляете свойство к каждому классу запросов (те, которые создаются с помощью инструмента генератора API Google API):
@property (copy) NSString *hiddenProperty;
и установите его значение на выбранный вами ключ. В коде сервера (python в моем случае) вы проверяете его существование и barf, если вы не видите его или его не настроили на значение, которое ваш сервер и клиент согласятся:
mykey,keytype = request.get_unrecognized_field_info('hiddenProperty')
if mykey != 'my_supersecret_key':
raise endpoints.UnauthorizedException('No, you dont!')
Надеюсь, это положит вас на правильный путь
Ответ 3
Документация предназначена только для клиента. Мне нужна документация о том, как обеспечить функциональность учетной записи службы на стороне сервера.
Это может означать пару разных вещей, но я хотел бы остановиться на том, что, по моему мнению, задает вопрос. Если вы хотите, чтобы ваша учетная запись службы имела доступ к вашему сервису, вы можете просто добавить клиентскую учетную запись службы в ваши аннотации @Api/@ApiMethod, создать GoogleCredential и вызвать свою службу, как обычно. В частности...
В консоли разработчика Google создайте новую учетную запись службы. Это создаст файл .p12, который будет автоматически загружен. Это используется клиентом в документации, к которой вы привязались. Если вы не можете защитить .p12, то это не намного безопаснее пароля. Я предполагаю, что это явно не указано в документации Cloud Endpoints.
Вы добавляете идентификатор CLIENT, отображаемый в консоли разработчика Google, в clientIds в аннотации @Api или @ApiMethod.
import com.google.appengine.api.users.User
@ApiMethod(name = "doIt", scopes = { Constants.EMAIL_SCOPE },
clientIds = { "12345678901-12acg1ez8lf51spfl06lznd1dsasdfj.apps.googleusercontent.com" })
public void doIt(User user){ //by convention, add User parameter to existing params
// if no client id is passed or the oauth2 token doesn't
// match your clientId then user will be null and the dev server
// will print a warning message like this:
// WARNING: getCurrentUser: clientId 1234654321.apps.googleusercontent.com not allowed
//..
}
Вы создаете клиента так же, как и с незащищенной версией, с той лишь разницей, что вы создаете объект GoogleCredential для передачи на ваш сервис MyService.Builder.
HttpTransport httpTransport = new NetHttpTransport(); // or build AndroidHttpClient on Android however you wish
JsonFactory jsonFactory = new JacksonFactory();
// assuming you put the .p12 for your service acccount
// (from the developer console) on the classpath;
// when you deploy you'll have to figure out where you are really
// going to put this and load it in the appropriate manner
URL url = getClass().class.getResource("/YOURAPP-b12345677654.p12");
File p12file = new File(url.toURI());
GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setTransport(httpTransport);
credentialBuilder.setJsonFactory(jsonFactory);
//NOTE: use service account EMAIL (not client id)
credentialBuilder.setServiceAccountId("[email protected]count.com"); credentialBuilder.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email"));
credentialBuilder.setServiceAccountPrivateKeyFromP12File(p12file);
GoogleCredential credential = credentialBuilder.build();
Теперь вызовите сгенерированный клиент таким же образом
вы будете иметь незащищенную версию, за исключением того, что строитель принимает
наши учетные данные google сверху как последний аргумент
MyService.Builder builder = new MyService.Builder(httpTransport, jsonFactory, credential);
builder.setApplicationName("APP NAME");
builder.setRootUrl("http://localhost:8080/_ah/api");
final MyService service = builder.build();
// invoke service same as unsecured version