Есть ли способ защитить прототип хранилища конечных точек Google?

моя настройка:

  • Python, движок Google, используя endpoints_proto_datastore
  • iOS, конечные точки Генератор клиентской библиотеки Obj-C

Фон

Я установил тестовые точки конечных точек Google для api и работал довольно быстро. Он отлично работает, используя тестовое приложение в симуляторе iOS и используя Google API Explorer. API в настоящее время открыт для всех без аутентификации.

Я бы хотел: установить API-ключ или системные учетные данные, которые могут быть использованы приложением, чтобы убедиться, что он один может получить доступ к api, при этом все остальные будут отклонены.

Метод в Документах Google Endpoints Auth (1) заключается в создании идентификатора клиента OAuth 2.0 с помощью Google Developers Console (2). Поэтому я создал идентификатор для установленного приложения типа iOS. Пока все хорошо.

В приложении объект GTLService выглядит так:

-(GTLServiceDemogaeapi *)myApiService {
    GTMOAuth2Authentication *auth = [[GTMOAuth2Authentication alloc] init];
    auth.clientID = @"10???????????????????ie.apps.googleusercontent.com";
    auth.clientSecret = @"z????????????3";
    auth.scope = @"https://www.googleapis.com/auth/userinfo.email";

    static GTLServiceDemogaeapi *service = nil;
    if (!service) {
        service = [[GTLServiceDemogaeapi alloc] init];
        service.authorizer = auth;
        service.retryEnabled = YES;
        [GTMHTTPFetcher setLoggingEnabled:YES];
    }
    return service;
 }

В GAE я указал (allowed_client_ids и добавил проверку пользователя методам...

@endpoints.api(name='demogaeapi', version='v1',
               allowed_client_ids=['10?????????????ie.apps.googleusercontent.com',
               endpoints.API_EXPLORER_CLIENT_ID],
               scopes=[endpoints.EMAIL_SCOPE],
               description='My Demo API')
class MyApi(remote.Service):

    @TestModel.method(path='testmodel/{id}', name='testmodel.insert', http_method='POST')
    def testModelInsert(self, test_model):

        current_user = endpoints.get_current_user()
        if current_user is None:
            raise endpoints.UnauthorizedException('Invalid token.')

Проблема

current_user всегда отсутствует, поэтому метод всегда вызывает исключение. Похоже, что это известная проблема. Проблема 8848: API Google Cloud Enpoints API get_current_user не заполняет user_id (3) без перспективы исправления в ближайшее время.

Опции

  • Подождите, пока исправление Google Issue 8848. Не может быть, у нас есть продукт для выпуска!

РЕДАКТИРОВАТЬ: 15 мая 2015 г. - Google выпустил статус 8848 статуса WontFix.

  1. Я видел, что возможно использовать ключ API, но, хотя я смог его создать, я не нашел способ включить его на бэкэнд. Я также отмечаю, что этот метод имеет большую дыру, где Google API Explorer может победить его, см. Вопрос SO (4).

  2. Предоставляет ли ответ @endpoints.api Аргумент: auth_level, описанный здесь (5)? Я попытался использовать:

    @endpoints.api(name='demogaeapi', version='v1',
           auth_level=endpoints.AUTH_LEVEL.REQUIRED,
           scopes=[endpoints.EMAIL_SCOPE],
           description='My Demo API')
    

    Но он смог использовать api из клиентского приложения без использования учетных данных. Поэтому он явно не добавлял никакой аутентификации.

  3. Добавьте скрытый объект в клиентский запрос с общим секретным ключом. Как описано bossylobster здесь (6) и Карлосом здесь (7). Я пробовал это, но не могу понять, как добраться до объекта запроса (тема другого вопроса Как получить объект запроса при использовании endpoints_proto_datastore.ndb?).

    @TestModel.method(path='testmodel/{id}', name='testmodel.insert', http_method='POST')
    def testModelInsert(self, test_model):
    
        mykey,keytype = request.get_unrecognized_field_info('hiddenProperty')
        if mykey != 'my_supersecret_key':
            raise endpoints.UnauthorizedException('No, you dont!')
    

EDIT: Появилась еще одна опция:

  1. Создайте учетную запись службы с помощью Google Developers Console (2). Используйте эту учетную запись, чтобы получить доступ к API без необходимости согласия пользователя (через пользовательский интерфейс). Однако Google, как представляется, ограничивает количество приложений, которые могут быть добавлены таким образом, до 15 или 20. См. Документ Google OAuth2 (8). Вероятнее всего, мы превысим лимит.

Вопрос

Кто-нибудь знает, как я могу заставить любой из этих параметров работать? Или я должен подойти к этому по-другому?

Как вы можете видеть, мне нужны рекомендации, помощь, идеи...


Как мне нужно 10 репутации, чтобы разместить более двух ссылок: вот ссылки, которые мне нужно было извлечь и добавить в качестве ссылок. Похоже на то, что на самом деле разрушил поток вопроса.

  • cloud.google.com/appengine/docs/python/endpoints/auth
  • console.developers.google.com/
  • code.google.com/p/googleappengine/issues/detail?id=8848
  • stackoverflow.com/a/26133926/4102061
  • cloud.google.com/appengine/docs/python/endpoints/create_api
  • stackoverflow.com/a/16803274/4102061
  • stackoverflow.com/a/26133926/4102061
  • developers.google.com/accounts/docs/OAuth2

Ответ 1

Отличный вопрос и настоящая проблема. Я решил это, имея свою собственную таблицу данных пользователя. Ключ Long (я использую Java) автоматически генерируется при записи, и это значение, которое я использую для уникальной идентификации пользователя с этого момента. Также к этой таблице добавляются идентификатор Google (предоставляется при вызове через веб-страницу), адрес электронной почты и идентификатор iOS (при использовании приложения iOS, не входящего в аккаунт Google).

Когда вызывается моя конечная точка AppEngine, я использую информацию, которая присутствует в параметре User (только аутентифицированный адрес электронной почты для подписанных клиентов) или отдельный необязательный параметр iosid, чтобы получить мой внутренний идентификатор пользователя номер из указанной таблицы и использовать это с того момента, чтобы однозначно идентифицировать моего пользователя.

Я использую ту же таблицу для хранения другой информации, относящейся к конкретному пользователю, так что это действительно не что иное, как попытка использовать current_user в качестве первичного ключа, кроме того, что мне пришлось создавать три поля (googleid, email, iosid), индексированный для поиска.