Как использовать аутентификацию на основе браузера OAuth2, а затем проверить запись на сервере

#php #angularjs #oauth-2.0

#php #angularjs #oauth-2.0

Вопрос:

У меня есть приложение на основе браузера (одностраничный, AngularJS), и я использую hello для использования стороннего входа, такого как Google, FB, Soundcloud и т. Д.

Мое приложение использует сервер PHP API.

Какой хороший способ дать пользователю возможность войти в систему с помощью Google, а также проверить пользователя на стороне сервера?

Я рассматривал:

  • Приложение браузера выполняет неявное предоставление с помощью google / fb / etc
  • Затем я переношу access_token с клиента на сервер, затем использую, например, google-api-php-client с my app id , secret и пользователем access_token ? Используя их API, например /me ? (какой тип гранта это будет?)
  • Получить некоторый ключ от стороннего (facebook_id, email и т. Д.), Сопоставить его с пользователем в моей базе данных, А затем считать пользователя аутентифицированным?

Кроме того, должен ли я выполнять это при каждом запросе API? Или я должен просто немного спрятать access_token и предположить, что пользователь все еще действителен до истечения срока действия ключа?

Ответ №1:

Одна из проблем заключается в том, что не все эти поставщики поддерживают неявный поток. Но, предполагая, что они это сделают, access_token вы получите для каждого из них доказательство того, что пользователь прошел аутентификацию в этой системе, не обязательно, что у них есть доступ к вызову вашего API. Вам все еще нужно что-то, что утверждает, что «someone@gmail.com может «прочитать» ресурс X в вашей системе»

Вероятно, вам нужно что-то, что переводит все, что вы получаете от Google, Soundcloud и т. Д., В токен, который понимает ваше приложение. Простой формат (r) — использовать JWT. (веб-токены Json).


App -> Intermmediary -> Soundcloud/Google
<-JWT-- <---whavetever-

и затем:


App - (JWT) -> API

JWT легко манипулировать, проверять и проверять. Смотрите jwt.io

Возможно, вы захотите просмотреть это сообщение в блоге также для получения дополнительной информации (в частности, о интерфейсах AngularJS)

Комментарии:

1. Итак, если я понимаю, я мог бы поместить в JWT достаточно, чтобы доказать, что пользователь аутентифицирован? т.е. Он будет содержать, скажем, электронное письмо с токеном, который мог быть создан только службой X; и если JWT является законным, система будет знать, что он содержит истинную информацию? Тогда моей системе не нужно было бы самостоятельно вызывать Google / FB / etc? (сейчас читаю сообщение в блоге)

2. ДА. JWT — это автономный объект с информацией о пользователе: (например, имя, адрес электронной почты) или пользователь, связанный с вашим API (например, пользователь является «администратором»). Она имеет цифровую подпись, поэтому вы можете проверить целостность. Вы можете проверить подпись в своем бэкэнде без дополнительного запроса к серверу, это будет просто криптографическая функция.

3. Я до сих пор не понимаю, как это может быть абсолютно безопасно. Я последовал совету в вашем сообщении в блоге (действительно полезно!) Я думаю, что единственный способ сделать это безопасным — заставить сервер использовать access_token, который он получает, и запрашивать его у службы (google / fb / …). Самый безопасный способ, о котором я могу думать, — это сформировать JWT (как вы предлагаете), используя один ключ (например, email) в качестве ‘sub’в заявках и идентификатор пользователя как секретный. Но даже это может быть подделано.

Ответ №2:

Сообщение в блоге, упомянутое @eugenio-pace, было действительно полезным для настройки клиентской части.

Однако на стороне сервера access_token она должна быть проверена.

SDK (в composer) (код ниже):

  • Facebook: "facebook/php-sdk-v4" : "4.0.*"
  • Google: cURL запрос (не заботился о "google/apiclient" )
  • SoundCloud: "ise/php-soundcloud": "3.*"

(Конечно, есть и другие, только эти три были теми, которые я выбрал, и кажутся приличными.)

В прошлый раз, когда я делал что-то подобное, я допустил ошибку, проверяя access_token при каждом запросе, что оказало огромное (явно негативное) влияние на производительность. Теперь я просто проверяю его при входе в систему и использую его для получения идентификатора пользователя из этой службы. Итак, браузер отправляет мне access_token A и сообщает, что он с Facebook, я использую sdk выше access_token с Facebook, и я получаю обратно их идентификатор, чтобы я знал, что они те, за кого себя выдают.

Я бы предложил сохранить access_token на сервере с expires_in помощью .

(Я еще не имел дело с токенами обновления)

Код для проверки токенов с использованием вышеуказанных библиотек:

 function validateTokenFacebook($token, $id=null) {
    // Performed above
    // FacebookSession::setDefaultApplication($config->fb->app_id, $config->fb->secret);

    $session = new FacebookSession($token);

    // Fetch user info
    $request = new FacebookRequest($session, 'GET', '/me');
    try {
        $response = $request->execute();
    } catch (FacebookFacebookServerException $e) {
        $this->mlog->err($e . "n" . $e->getTraceAsString());
        throw new AuthTokenInvalidException();
    }

    $graphObject = $response->getGraphObject();

    $user_id = $graphObject->getProperty('id');
    return array(access_token, $user_id);
}
function validateTokenGoogle($token, $id=null) {
    $resp=array();

    // This key isn't included in the token from hello.js, but
    // google needs it
    if (!array_key_exists('created', $token)) $token['created'] = $token['expires'] - $token['expires_in'];

    $client = new Google_Client();
    $client->setClientId($this->systemConfig->google->app_id);
    $client->setClientSecret($this->systemConfig->google->secret);
    $client->setRedirectUri($this->systemConfig->google->redirectUri);
    $client->setScopes('email');
    $client->setAccessToken(json_encode($token));

    try {
        // Send Client Request
        $objOAuthService = new Google_Service_Oauth2($client);
        $userData = $objOAuthService->userinfo->get();
        return array($token['access_token'], $userData['id']);
    } catch (Google_Auth_Exception $e) {
        throw new AuthException('Google returned ' . get_class($e));
    }
}
function validateTokenSoundcloud($token, $id=null) {
    $soundcloud = new SoundcloudService(
        $this->systemConfig->soundcloud->app_id,
        $this->systemConfig->soundcloud->secret,
        $this->systemConfig->soundcloud->redirect);
    $soundcloud->setAccessToken($access_token);
    try {
        $response = json_decode($soundcloud->get('me'), true);
        if (array_key_exists('id', $response))
            return array($access_token, $response['id']);
    } catch (SoundcloudExceptionInvalidHttpResponseCodeException $e) {
        $this->mlog->err($e->getMessage());
    }
    throw new AuthTokenInvalidException();
}
  

У меня есть несколько пользовательских классов выше, таких как исключения и systemConfig, но я думаю, что это достаточно подробно, чтобы сообщить, что они делают.