Аутентификация с помощью GAPI
Published: 2019-10-04 15:21:04

В [предыдущей статье](https://dev.to/yababay/how-to-use-msal-for-signup-in-a-web-application-5g0p) я рассказал о том, как организовать логин на сайт с помощью js-библиотеки  от Microsoft. Идея в том, чтобы не создавать собственный модуль регистрации (он, скорее всего, получится уязвимым к хакерским атакам), а воспользоваться возможностями крупных корпораций, которые атак, в общем-то, не боятся. 

IT-монстров с собственными API аутентификации и авторизации множество (Google, Microsoft, Facebook, Twitter, Яндекс), и хочется воспользоваться как можно большим количеством таких возможностей. Мешает то, что у каждой из них свой уникальный API для этих целей, и с каждым нужно разбираться. Я осилил лишь 3. Про первую технологию (MSAL) уже написал, этот материал будет про аутентификацию от Google, и еще про Яндекс планирую. Больше мне и не надо, поскольку потенциальные потребители моих услуг пользуются именно этими сервисами. 

Кто-то может сказать, что незачем изобретать велосипед: есть готовые интегрированные инструменты для подобных целей. Прежде всего, это [hello.js](https://adodson.com/hello.js/). В этом модуле собрано несколько вариантов аутентификации, и все они приведены к изящному "единому знаменателю". Хорошая разработка, но я от нее отказался: во-первых, некоторые примененные в ней технологии уже успели устареть, хотя пока еще и не окончательно отвергнуты (ADAL вместо MSAL). Во-вторых, я хотел бы полностью контролировать клиент-серверное взаимодействие. В-третьих, интересно сравнить технологии, используемые корпорациями.

Приступим, наконец, к разбору работы Google API (GAPI) применительно к аутентификации пользователей. GAPI - библиотека, интегрирующая различные технологии Google, которые могут быть выполнены в рамках веб-страницы. Есть среди них и модуль auth2, которым мы и воспользуемся. Но сначала в html нужно добавить такой код:

``` html
<script src="/js/invite-with-gapi.js"></script>
<script src="https://apis.google.com/js/platform.js?onload=init" async defer></script>
```
Внимательный читатель уже видит отличие от MSAL: там мы сначала загружали скрипт от Microsoft, а затем собственный. Здесь же последовательность обратная. Это объясняется тем, что библиотека от Google вызывает функцию `init` (url заканчивается параметрами - `?onload=init`). Это значит, что на момент, когда скрипт загрузится, эта самописная функция уже должна "поджидать" его на странице. В противном случае `platform.js` не найдет ее и не произойдет никакой аутентификации. 

Что содержит `invite-with-gapi.js`? Как и в предыдущем примере с MSAL, этот файл используется многократно, точнее говоря, 2 раза: первый - в момент начала аутентификации, второй - после того, как сервера Google проверят регистрацию пользователя у себя, а также убедятся в том, что он согласен предоставить вашему приложению права на получение его персональных данных. Приведу содержимое этого файла. Как и предыдущий, он написан на CoffeeScript (почему - объяснено в статье о MSAL):

```coffeescript
@.init = ()->
    switch @.location.pathname
        when '/signup-gapi.html'
            setTimeout ()->
                    gapi.load 'auth2', ()->
                        gauth2 = gapi.auth2.init
                            client_id: '640986499797-blah-blah.apps.googleusercontent.com'
                            ux_mode: 'redirect'
                            redirect_uri: 'https://js-invite.ru/json/invite-with-gapi'
                            scope: 'profile email'
                        gauth2.signIn()
                , 1000
        when '/json/invite-with-gapi'
            gapi.load 'auth2', ()->
                gauth2 = gapi.auth2.init
                        client_id: '640986499797-blah-blah.apps.googleusercontent.com'
                        scope: 'profile email'
                    .then (res)->
                        prof = res.currentUser.get().getBasicProfile()
                        url = '/json/invite-with-email?'
                        url += "name=#{encodeURIComponent(prof.getName())}&"
                        url += "to=#{encodeURIComponent(prof.getEmail())}"
                        window.location = url

```

Как видим, в отличие от MSAL, эта технология не нуждается в возврате к первоначальной странице, а организует логин всего за два шага: токен доступа выдается уже при переадресации на  ваш сервер. Кстати, хранит информацию об аутентификации Google API не в `sessionStorage`, а в `localStorage`. 

Работающий пример можно посмотреть [здесь](https://js-invite.ru).

В общем, что ни компания, то свои правила. И это вы еще Яндекс не видели :). Про его вариант аутентификации я собираюсь рассказать в следующей статье.