У меня есть приложение GAE на Python 2.7 (пожалуйста, не спрашивайте, почему) с двумя сервисами: UI & API (ie Я использую dispatch.yaml
для развертывания нескольких сервисов, каждый в своих вложенных папках со своими собственными app.yaml
). У меня есть конечная точка API для создания подписанных URL-адресов для интерфейса пользователя, который используется для загрузки файлов в GCS. В качестве уровня безопасности я хочу проверять пользователей API, используя ту же систему, в которой используется пользовательский интерфейс: Firebase.
И в пользовательском интерфейсе, и в API у меня есть вспомогательная функция, которая:
- Загружает сессионный повар Firebase ie для документации по настройке администратора Firebase
- Проверяет его и извлекает «утверждения» (информация о проверенном пользователе)
- UI / API затем использовать заявки для обработки остальной части веб-запроса / ответа
Однако даже с одинаковым кодом в пользовательском интерфейсе и API (и одинаковыми настройками в app.yaml
), которые являются частью одного и того же проекта GAE, Firebase выдает ошибку в API при вызове auth.verify_session_cookie(session_cookie, check_revoked=True)
, но работает как чемпион в коде пользовательского интерфейса.
Настройка:
Вот соответствующие части каждого файла, найденные как в пользовательском интерфейсе, так и в API Подпапки кода служб
app.yaml
# The Service names are set as appropriate in respective service app.yaml's:
# service: api
# service: default
...
env_variables:
# Replace with your Firebase project ID.
FIREBASE_PROJECT_ID: 'my-rad-project'
GCLOUD_PROJECT: 'my-rad-project' # this env var doesn't seem to be necessary to set to make Firebase work on UI
main.py
Интерфейс пользователя устанавливает повара ie в коде, показанном ниже. Этот код здесь проверяет повара ie и извлекает утверждения, если это возможно:
import requests_toolbelt.adapters.appengine
...
from firebase_admin import auth, initialize_app # This must go after the monkeypatch()
default_app = initialize_app() # "[DEFAULT]"
...
def get_claims():
session_cookie = request.cookies.get(COOKIE_NAME)
# Verify the session cookie. In this case an additional check is added to detect
# if the user's Firebase session was revoked, user deleted/disabled, etc.
decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True)
return decoded_claims
Существует также конечная точка flask для установки повара ie COOKIE_NAME
из idToken
, предоставленного firebase. Это существует только в службе пользовательского интерфейса, но оно размещается на том же поддомене, что и API (конечные точки API просто имеют /api
, начинающие свои URL-адреса)
@app.route('/sessionLogin', methods=['POST'])
def session_login():
id_token = request.json['idToken']
# To ensure that cookies are set only on recently signed in users, check auth_time in
# ID token before creating a cookie.
try:
decoded_claims = auth.verify_id_token(id_token, check_revoked=True)
# Only process if the user signed in within the last 5 days.
if time.time() - decoded_claims['auth_time'] < 5 * 24 * 60 * 60:
expires_in = datetime.timedelta(days=5)
expires = datetime.datetime.now() + expires_in
session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in)
response = jsonify({COOKIE_NAME: session_cookie})
response.set_cookie(
COOKIE_NAME, session_cookie, expires=expires, httponly=True, secure=True, domain='.my.domain')
return response
# User did not sign in recently. To guard against ID token theft, require
# re-authentication.
err = 'Recent sign in required'
log.error(err)
return abort(401, err)
except ValueError:
err = 'Invalid ID token'
log.error(err)
return abort(401, err)
except Exception as e:
# Session revoked. Force user to login.
err = "Firebase exception getting claims: {}".format(e)
log.error(err)
return abort(401, err)
Ошибки
Когда я отправьте веб-запрос конечной точке API, которая обрабатывает подпись GCS, сначала она вызывает get_claims()
, а затем выдает эту ошибку:
The credential used to initialize the SDK has insufficient permissions to perform the requested operation. See https://firebase.google.com/docs/admin/setup for details on how to initialize the Admin SDK with appropriate permissions (INSUFFICIENT_PERMISSION).
Исправления I Tried
Я следовал Firebase документы для настройки его для нескольких приложений , считая, что, поскольку мой пользовательский интерфейс является службой "по умолчанию" в моем приложении GAE, возможно, мне нужно было инициализировать приложение API, которое называется службой "api" в моем app.yaml
. Это не помогло:
# In API's main.py
default_app = initialize_app()
api_app = initialize_app(name='api')
Затем я использовал собственный слой авторизации Google , который должен работать с Firebase:
# API's main.py
from google.oauth2.id_token import verify_firebase_token
from google.auth.transport.requests import Request
HTTP_REQUEST = Request()
...
# Change 1 line in `get_claims()` like so:
decoded_claims = verify_firebase_token(session_cookie, HTTP_REQUEST)
Это привело к новому ошибка: Certificate for key id asdf1234 not found.
Я нашел , казалось бы, связанный вопрос SO , но его решение не сработало (у меня есть веб-страница, а не приложение Android, и даже если я пытаюсь в другом браузере, вынуждает меня войдите с Google в новый сеанс, сервер по-прежнему выдает ту же ошибку)
Все это время пользовательский интерфейс работает отлично, чтобы запустить get_claims()
. Что мне нужно сделать, чтобы использовать проверку подлинности Firebase в моей службе API с использованием значения cook ie, установленного моей службой пользовательского интерфейса, оба из которых находятся на одном поддомене и имеют одинаковые переменные среды, установленные в их файлах app.yaml
?