Трехсторонний OAuth и однократный поток кода с использованием google-auth-library- ruby с google-api- ruby -клиентом - PullRequest
0 голосов
/ 12 апреля 2020

Краткий обзор : у меня есть приложение ruby, которое работает ночью и что-то делает с пользовательским календарем Google. Пользователь уже предоставил доступ через отдельное приложение реакции. У меня проблемы с получением приложением ruby для доступа к календарю пользователя с кодом авторизации из приложения реагирования.

Подробно : у меня есть интерфейс React, который может войти в систему пользователь, использующий гэппи, и впоследствии подписывает его в Firebase. Вот как я настраиваю gapi obj:

this.auth2 = await loadAuth2WithProps({
  apiKey: config.apiKey,      // from firebase
  clientId: config.clientId,  // from gcp
  // ....
  access_type: "offline",     // so we get get authorization code
})

Здесь вход:

doSignInWithGoogle =  async () => {
  const googleUser = await this.auth2.signIn();
  const token = googleUser.getAuthResponse().id_token;
  const credential = app.auth.GoogleAuthProvider.credential(token);
  return this.auth.signInWithCredential(credential);
};

Следующий шаг пользователя - предоставить приложению автономный доступ к его календарю:

doConnectGoogleCalendar =  async () => {
  const params = {scope:scopes};
  const result = await this.auth2.grantOfflineAccess(params);
  console.log(result.code); // logs: "4/ygFsjdK....."
};

На этом этапе у внешнего интерфейса есть код авторизации, который можно передать приложению на стороне сервера для обмена на доступ и обновления токенов sh. Я не смог найти хороший способ использовать предоставленный пользователем код авторизации для звонков в доступные области. Вот как я настроил oauth-клиент:

auth_client = Google::APIClient::ClientSecrets.load(
  File.join(Rails.root,'config','client_secrets.json') // downloaded from GCP
).to_authorization

^ Я использую те же учетные данные GCP на бэкэнде, которые я использую для внешнего интерфейса. Это тип учетных данных «Идентификатор клиента OAuth 2.0». Я не уверен, является ли это хорошей практикой или нет. Кроме того, мне нужно определить ту же конфигурацию, которую я делаю на веб-интерфейсе (например, access_type и scope)? 1040 * токены (нажмите Ruby):

auth_client.code = authorization_code_from_frontend
auth_client.fetch_access_token!
---------
Signet::AuthorizationError (Authorization failed.  Server message:)
{
  "error": "invalid_grant",
  "error_description": "Bad Request"
}

Есть ли что-то, чего мне не хватает при настройке отдельного внутреннего приложения, которое может обрабатывать автономный доступ к области, предоставленной пользователем? В этих библиотеках так много разной информации, но я не смог отнести ее к тому, что работает.

ОБНОВЛЕНИЕ Я нашел эту страницу, описывающую " one- поток временного кода", который я больше нигде не нашел, - это все документы, через которые я прошел. Он отвечает на один из моих незначительных вопросов выше: Да, вы можете использовать те же секреты клиента, что и веб-приложение для бэкэнда. (см. Полный пример внизу, где они делают именно это). Я исследую это больше и посмотрю, можно ли решить мою большую проблему. Также собирается обновить заголовок, чтобы включить поток одноразового кода.

1 Ответ

0 голосов
/ 14 апреля 2020

После большого количества копаний примеров кода и исходного кода у меня есть чистое рабочее решение. Когда я обнаружил страницу в своем «обновлении», это привело меня к выводу, что ClientSecrets то, что я делал, было устарело в пользу google-auth-library- ruby проект. Я рад, что нашел его, потому что, кажется, это более полное решение, поскольку оно обрабатывает все управление токенами для вас. Вот код для настройки всего:

def authorizer
    client_secrets_path = File.join(Rails.root,'config','client_secrets.json')
    client_id = Google::Auth::ClientId.from_file(client_secrets_path)
    scope = [Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY]
    redis = Redis.new(url: Rails.application.secrets.redis_url)
    token_store = Google::Auth::Stores::RedisTokenStore.new(redis: redis)
    Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, "postmessage")
end

, и тогда вот как я использую код авторизации :

def exchange_for_token(user_id,auth_code) 
    credentials_opts = {user_id:user_id,code:auth_code}
    credentials = authorizer.get_and_store_credentials_from_code(credentials_opts)
end

после вызова этого метода, библиотека будет хранить обмениваемые токены в Redis (вы можете настроить, где их хранить) для последующего использования, например:

def run_job(user_id)
    credentials = authorizer.get_credentials(user_id)
    service = Google::Apis::CalendarV3::CalendarService.new
    service.authorization = credentials
    calendar_list = service.list_calendar_lists.items
    # ... do more things ...
end

Существует так много информации, что трудно выделить, что относится к каждому условию. Надеюсь, это поможет всем, кто застрял в «потоке одноразового кода», чтобы они не тратили дни, стуча головой по столу.

...