📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

7 Концепций Аутентификации, которые должен знать каждый разработчик

JAVA GYM RAT | Катя Кондратьева 53:59

Transcription

Схемы перед тем, как попасть во внутренний контур, должны пройти через сервис аутентификации. И вне зависимости от того, от кого в принципе этот запрос отправлен: от пользователя, которые используют десктоп приложения, либо от пользователя, который используют мобил, браузер. Вне зависимости от этого, даже если внешний сервис пытается интегрироваться с нами в Аме, всё равно все в итоге запросы будут проходить через этот сервис аутентификации, задача которого верифицировать, а имеет ли в принципе данный пользователь доступ к нашей системе. Только верифицированные запросы в итоге будут перенаправлены во внутренний контур, где уже мы будем с ними реализовывать какую-то бизнес-логику. Если же верификация не пройдена, мы будем возвращать пользователю 401 ошибку, потому что у него нету доступа.

Так вот, несмотря на то, что, казалось бы, задача обеспечения безопасности нашего сервиса, ну, это основная задача, которая стоит перед разработчиком каждой системы, несмотря на это, всё равно разработчики очень часто путаются в инструментах обеспечивающих секьюрити. А сегодня мы поговорим именно об аутентификации. Почему так происходит? Потому что чаще всего разработчики приходят на проект, чтобы закрывать бизнес-задачи. Им а не нужно реализовывать этот сервис аутентификации, он и так уже существует. Всё, что нужно сделать - это просто обращаться к существующему апе, чтобы валидировать входящие токены, проверять права и всё. Просто дёргать ручки. Однако не приходится взаимодействовать напрямую с этими инструментами, в связи с чем отсутствует практика. и в принципе понимание, что это за инструменты и как с ними работать. Конечно, ну, большая часть из нас знает основные определения GVT токены, да, бир токены, методы аутентификации. Однако это всё остаётся чисто на теоретическом уровне. И в связи с этим в понятиях люди плавают, не разбираются в них. А тем более самая, наверное, ужасная и распространённая ошибка, что они, в принципе, начинают путать методы аутентификации с методами авторизации. И здесь я перечислила топ популярных ошибок, которые обычно я вижу у разработчиков. А они относят к способам аутентификации, фреймворки, авторизации, что, естественно, вообще разные вещи и нельзя их друг к другу относить. Они выделяют GVT токены как отдельный способ аутентификации. Потора [фыркает] и GVT токе. Им кажется, что это одна и та же вещь. И называют подходы OUS 2 и SSO способами аутентификации, что, естественно, тоже неверно.

В этом видео мы разложим тему аутентификации по слоям. Сначала мы разберём методы аутентификации, как они работают, где применяются, какие у них преимущества и недостатки. В дальнейшем мы обсудим детальнее про токены, потому что аутентификация с помощью токенов - это самый распространённый тип решения. Сейчас обсудим, зачем нужные токены, доступы и рефреш-токены, а также разберём углублённы GVT токены. Почему это не отдельный способ аутентификации. В конце мы разберём высокоуровневые протоколы, которые чаще всего путают с методами аутентификации, хотя они совершенно не имеют никакого отношения к данной задаче. Это фреймворки, с помощью которых мы реализовываем именно авторизацию пользователей в системе. Мы разберём, в чём разница между ними, ну, и также подход работы. В данном видео наша задача распутать этот клубок связанных между собой терминов, определиться, да, с основными концепциями, которые должен знать разработчик про аутентификацию. И я подробно на диаграммах буду объяснять каждый метод аутентификации, каждый инструмент, чтобы у нас было вот это точное, чёткое понимание. И в базовых понятиях мы уже не путались. Я прямо подробно разбираю каждый метод. Я расскажу тебе, что такое HTP схема безопасности, почему не все методы аутентификации соответствуют этой схеме безопасности. И в итоге мы добьёмся этой цели, что больше понятия путаться не будем. У нас будет фундамент в теме аутентификации, и мы сможем уже на её основе идти дальше в глубину секюрити. Предлагаю пройти дальше. Я знаю, насколько важна практика, и поэтому в моём Telegram-канале ты можешь найти именно ссылку на репозитории с примерами кода, где я реализовываю каждый метод аутентификации и авторизации, в том числе. Ссылка будет в описании к видео.

А сейчас мы начнём с базы, что вообще такое аутентификация. Аутентификация - это процесс проверки. Является ли клиент, который отправляет запрос в нашу систему действительно тем, за кого он себя выдаёт. Чтобы выяснить, нужно ли давать доступ к запросу к нашему ресурсу, к нашей системе, мы должны проделать ряд действий. Первый этап, который - это идентификация входящего запроса. Нам нужно выяснить, а кто в принципе этот запрос нам отправил, а как мы это делаем, на основе каких данных. В запросе передаются учётные данные, на основе которых мы, в принципе, можем выяснить, кто нам этот запрос отправил, что это могут быть за учётные данные, но это может быть логин, пароль, идентификатор самого пользователя. Однако на данном этапе мы ещё не знаем, действительно ли пользователь является тем, за кого он себя выдаёт. Поэтому на следующем этапе, на этапе аутентификации, на основе также переданного запроса, переданных криеншел в запросе, это может быть пароль, может быть токен, мы и будем определять, данный запрос он верифицирован и пользователь действительно является тем, за кого себя выдаёт, либо нет. Самый последний этап - это именно авторизация пользователя, где мы выясняем, а у данного пользователя какая роль, какие у него, в принципе, есть доступы, что мы ему должны отображать, а что не должны. Суммировая идентификация отвечает на вопрос: кто ты? Кто этот клиент, который нам запрос отправил? Аутентификация говорит: "Докажи, что это ты, что это действительно ты". И авторизация отвечает на вопрос: "А какие у тебя доступы в нашей системе есть? Что мы тебе должны отображать?" В сумме пройдя весь этот этап, мы можем пользователя идентифицировать, верифицировать и обозначить, что он в нашей системе может делать, а что не может, и в дальнейшем этот запрос уже отправить в наш внутренний контур и обрабатывать. То есть мы либо прокидываем наш запрос далее в систему, либо отправляем 401 ошибку о том, что, к сожалению, нету доступа к нашей системе. Ну либо 403, если недостаточно прав. И дальше уже запрос попадает во внутренний контур, как мы говорили выше, где реализовывается бизнес-логика.

Теперь я хочу упомянуть важный момент, который поможет тебе не смешивать все методы аутентификации в одну кучу. В HTP есть стандартный механизм аутентификации. Он работает по принципу challenge response. Клиент делает запрос к защищённому ресурсу. Если сервер понимает, что запрос пришёл без криеншилов или эти криеншилы невалидны, он возвращает ответ. Ну, очевидно, 401 ошибку, а также прокидывает в заголовке этого ответа информацию по поводу того, какую схему аутентификации клиенту нужно использовать. То есть, буквально сервер говорит клиенту, чтобы получить доступ к этому ресурсу, повтори запрос и используй вот такую схему аутентификации. После этого клиент повторно отправляет запрос и уже в заголовке передаёт ту же самую схему и сами криеншилы для аутентификации. Ну и в случае, если всё валидно, сервер возвращает ответ 200 и выдаёт доступ к системе. На месте Basic может быть любой метод аутентификации, который как раз соответствует, а механизму аутентификации HTP запросов, вот этому стандарту. И вместо Basic это может быть, а digest аутентификация либо аутентификация с помощьюр токенов. Разница между ними только в том, какие кренлы передают в рамках данных методов для аутентификации пользователя. То есть в случае с Basзик аутентификации будет передан логин и пароль а в закодированном Base 64 формате. В случае с дайджестом клиент не отправляет пароль напрямую, а считает специальный digest responsв, которые прокидывают сервер. Ну и в случаер токенов клиент предъявляет токен. И этого достаточно. В принципе, мы считаем, что тот, кто владеет токеном, имеет доступ к нашей системе. Но вот дальше в разработке, помимо этих методов появились новые методы аутентификации, которые как раз и были созданы на практике. Они не соответствуют а стандартам HTP и схемы безопасности, однако решают ключевую задачу, а именно аутентифицируют пользователя. Поэтому их не относят к этим методам аутентификации. Однако задачу они всё равно решают. Были они созданы на практике, и мы можем их использовать. Почему данные методы не соответствуют стандарту HTP? Ну, а ключи, они могут быть переданы не только в заголовке аутентификации, но и также в заголовке XPки, где после будет идти токен. В дальнейшем появились и другие методы аутентификации, которые задачу как бы решают поставленную, однако не соответствуют стандартам HTP схемы безопасности. Это а ключи и сессии. Почему они не соответствуют данной схеме? А касательно апи ключей, дело в том, что у нас ключ, он может быть передан [фыркает] не только в заголовке под названием аутентификация. Также он может быть передан как отдельный заголовок XPки. Ну либо, в принципе, в теле запроса, либо в куке. Что касается сессии, то тут, в принципе, механизм работает иначе. У нас сервер после логина создаёт сессию, отправляет клиенту в куки эту сессию и после браузер автоматически прикладывает это в куки каждом запросу. Так что данные методы не реализуют данную схему безопасности, однако всё равно на практике используются. И в дальнейшем мы обсудим, как именно они реализовываются и как работают под капотом. Однако уже на этом этапе ты можешь увидеть, почему вся эта путаница возникает. Мы всё смешиваем в одну кучу и из-за этого получаем кашу, что у нас а все методы кладутся в один список, хотя технически это вообще сущности разного уровня.

Давай будем теперь разбираться с каждым методом аутентификации в детали и начнём с самого простого метода аутентификации, а именно Basic. Basic аутентификация - это самый простой способ аутентификации, при котором пользователь прокидывает в каждом запросе логин и пароль в Base 64 закодированном формате. Это не шифрование. То есть если какой-нибудь перехватчик перехватит наш запрос, он сможет наш криден расшифровать, ну и, соответственно, использовать для самостоятельного входа в систему. Как данный метод работает? Клиент отправляет запрос на получение всех пользователей в системе. Сервер замечает, что не переданные криеншелы данный пользователь не идентифицирован, отправляет ответ 401 и как раз в запросе указывает схему аутентификации, которую нужно использовать. У нас это basic. пользователь получает этот ответ и предоставляет креншела, логин и пароль, а после отправляет запрос уже с введёнными креншнами на наш сервер. Этот запрос будет выглядеть следующим образом. Схема аутентификации и сам, ну, можно сказать, что это токен. На самом деле это просто в таком формате закодированный запрос с нашими учётными данными. сервер данный запрос обрабатывает, проверяет логин и пароль. И в случае, если все криншилы валидны, то возвращает код 200. В случае, если невалидны 401, потому что доступа к нашему ресурсу нет. И данный подход он, ну, совершенно небезопасный. Вот. Потому что логин, пароль легко перехватить этот запрос и расшифровать их. S64 - это никакое не шифрование. Так что если какой-нибудь мошенник доступ к нашему запросу получит и сможешь оттуда достать вот эту строку, то он в дальнейшем сможет самостоятельно в нашу систему заходить и делать любые операции. Но если мы выбираем этот подход, то нам обязательно нужно использовать https. На практике такая схема аутентификации не встречается. И я предлагаю перейти к следующему методу аутентификации.

Это дайдст аутентификация. Она уже немного лучше предыдущей. Данный метод сильнее, чем basic аутентификация именно за счёт хэширования. Ну, в данном случае это 25 хэширование. И, в принципе, отсюда и следует название данного метода, потому что digest - это результат выполнения хэш-функции. Так вот, как он работает? Та же самая ситуация. Клиент отправляет на сервер запрос, чтобы получить доступ к какой-то ручке. Сервер видит, что клиент не аутентифицирован, отправляет 401, придаёт в своём ответе схему, которую клиенту нужно использовать, и также дополнительно прокидывает параметры для того, чтобы на их основе клиент вычислил хэш, вычислил код и тот самый digдст и отправил его на наш сервер. Для вычисления этого дайджеста нужно применить хэш-функцию, а именно к параметрам, которые мы ему передаём, ну и также к самому паролю пользователя, к его логину. Пользователь эти параметры получит, вычислит digest и в новом запросе передаст заголовки полученное значение. И данный запрос будет выглядеть таким образом. А вот в респонсе мы передаём полученный digдст. Здесь передаём параметры, которые мы использовали. И этот респонс и будет результатом этого хэширования набором данных, который уже сервер сможет проверить. Здесь мы не передаём, то есть напрямую логин и пароль нашего пользователя в сыром виде. А, то есть перехватчик, даже если наш запрос схватит, он не сможет из него пароли, учётные данные в принципе достать. Однако всё равно опасность есть некая. Такая схема подвержена атаке Main in the middle. Клиент отправляет запрос сервер на получение доступа кпоинту. Сервер возвращает ему ответ, указывает, что схема должна использоваться digest. И перехватчик перехватывает этот ответ и меняет схему. Он понижает уровень схемы на бей. Клиент получает этот ответ, думает, что нам нужно реализовывать данную схему, и отправляет вром в виде логин и пароль. Ну и перехватчик, когда эти данные получает, он получает доступ к нашим учётным данным и уже может самостоятельно обращаться на сервер, самостоятельно туда с этими учётными данными заходить. Поэтому, несмотря на то, что здесь есть кэш-функция, а учётные данные мы не передаём в сыром виде, всё равно данный подход не является безопасным. И вот здесь хорошо и очень наглядно видно, почему вкэнд-подготовке важно не только понимать углублённо каждый инструмент, с которым ты работаешь, а также понимать, как они, в принципе, взаимодействуют друг с другом и выстроить это системное понимание. С таким запросом я как раз и помогаю разработчикам. Ко мне приходят на менторство ребята, у которых есть подобные разрывы. Они вроде бы знают Java, Spring, базу данных, там, Secкрити, Кавку, но на собеседовании либо при решении реальных задач теряются и не понимают, как как изученные технологии в принципе использовать. Поэтому я работаю со своими подопечными, так что мы определяем текущий уровень разработчика, какие у него есть пробелы, выстраиваем индивидуальный план развития. в рамках которого прорабатываем и технику, и практику. Позже составляем резюме, где как раз и указываю вот эти задачи, которые он решал в рамках данного продакшн-инкубатора, который у меня выстроен. И после уже с сильными практическими, теоретическими знаниями и сильным призмы ходим на рынок. В течение 3х месяцев у разработчиков получается добиться результата, ну, то есть офера от 250.000 руб. на руки. Поэтому, если вам нужен не просто курс, а именно доведение до результата с поддержкой во время испытательного срока, то вы можете написать мне. Моя личка - это первая ссылка в описании к видео. Напишите туда ключевое слово трудоустройство, я ваши сообщение замечу, и мы договоримся о к встрече, где обсудим детали, как я могу конкретно с вашим запросом помочь.

А теперь предлагаю перейти к следующему методу аутентификации с помощью Bor tokens. Аутентификация с помощьюр токена называется так как раз потому что доступ к нашему серверу получает тот пользователь который владеет этимр токеном в отличие от схем где клиент доказывает знания пароля или владения ключом, здесь сам факт владения токеном считается достаточным поэтому главный риск бир подхода простой если токен путчок любой кто его получит будет также иметь доступ к нашей системе Меlу достаточно простой. Пользователь отправляет запрос и первый раз он логинится в нашей системе с помощью учётных данных, логина и пароля. Сервис авторизации проверяет эти криеншелы и если всё указано корректно, возвращает GVT токен. Впоследствии этот GVT токен клиент и будет нам прокидывать при каждом запросе. Фло достаточно простой. Первый запрос. Клиент отправляет в наш сервис аутентификации обычный логин с помощью юзернейма и пароля. Сервис аутентификации проверяет эти криенлы и возвращает GVT токен, если всё в порядке. И после клиент будет при каждом запросе отправлять этот же GVT токен. И тогда наш сервер должен будет проверить подпись у этого токена, не поддельный ли он. Если всё, возвращаем 200. Если поддельный, то возвращаем ошибку 401. И раньше, до появления GVT токена у нас отправлялась не вот эта структура, а просто рандомная строка. серверу приходилось принимать эту строку и идти в базу данных, чтобы найти её в этой БД либо в кэше и действительно убедиться в том, что строка валидная. Однако с появлением GVT токена а отпала эта необходимость сохранения состояния. И сейчас мы разберём, почему. GVT токен у нас самодостаточный. Он и так хранит себе уже всю необходимую информацию для аутентификации пользователя. Он состоит из заголовка, пйлоуда и подписи. И как раз payload и содержит все необходимые нам данные. Так что теперь нам не нужно при каждом запросе ходить в базу данных. Мы можем локально, без дополнительных вызовов проверить этот GVT токен и выяснить, корректный он либо нет. корректный ли пользователь вообще к нам приходит, верифицированный или нет. Разработчики часто путают token и gt token. Birer token autentification - это лишь паттерн, а, который как раз говорит о том, в каком и формате мы отправляем запросы, как мы их обрабатываем. Мы можем криеншлы отправлять в любом формате, просто как строку рандомную. А можем отправлять GVT token. То есть GVT токен - это просто конкретная реализация, с помощью которой мы можем отправлять наши данные о пользователе на сервер. Всё. Bir login autentification - это метод аутентификации. Pattern GVT - это реализация, которую он использует. Ну и так как мы с GVT токеном разобрались, дальше схема достаточно простая, точно такая же. Проверили подпись, убедились, что всё корректно, тогда отправляем ответ 200. Если не прошла у нас валидация, мы отправляем 401 ошибку.

Аутентификация с помощью токена - это суперпопулярная практика. Она используется практически везде. На моём проекте на Полиморфере мы тоже реализовывали этот паттерн. И я хочу сказать, что если мы выбираем его, то очевидно, что нам будет недостаточно одного типа токенов, и мы будем реализовывать и токены доступа, и рефреш-токены. И сейчас я предлагаю перейти к этой теме и обсудить подробнее детали. Зачем нужно два токена? Пользователи, когда в первый раз заходят в нашу систему, проходит регистрацию стандартно через формулу, введя какие-то учётные данные, а если успешно его логин прийдёт, то система отправит ему в ответе Access ToКen или fresh toкеen Access Token - это токен доступа. Он краткоживущий, обычно живёт до часу, и он нужен только для того, чтобы пользователь получил доступ к нашей системе. Впоследствии он будет отправлять этот токен постоянно, и верифицируя его, мы будем понимать, имеет доступ клиент к нашему серверу или не имеет. Рефреш токен - это, в свою очередь, долгоживущий токен, и он нужен только для того, чтобы переобновить accessток, когда у него истечёт срок давности. То есть access toкеen он живёт до часу, когда он будет считаться уже истёкшим expired. А при обработке запроса сам сервер пытается сгенерировать новый exessтокенen, получив корректный рефреш. Как видно на схеме, клиент отправляет запрос с истёкшим токеном. Сервер отвечает, что не авторизован данный пользователь, потому что, ну, токен невалидный. И тогда в следующем запросе клиент отправит запрос с рефреш токеном. Сервис аутентификации в ответ отправят новый accessтокен и новый рефреш. Следующие запросы уже будут с новым токеном доступа, и пользователи будут спокойно получать доступ к нашей системе. Здесь важный момент. Рефреш-токены нельзя хранить где попало. На бэкэнде, очевидно, да, мы храним эти токены на уровне ВД либо в том же самом кэше. Нам это необходимо, чтобы вообще эти токены можно было отзывать, можно было менять срок жизни, привязать к пользователю либо к устройству. Однако на фронтде нам нужно очень сумом подходить к выбору расположения данного токена. На клиенте нам же тоже нужно хранить значение этого рефрештокена, чтобы его передавать в запросе. Поэтому, а нам нужно помнить о том, что этот токен нельзя класть в local storage, потому что у нас есть вероятность возникновения XS уязвимости. Что это за уязвимость? Это уязвимость, при которой атакующий добивается выполнения своего джаваскрипта кода. внутри страницы пользователя. Если рефреш токен лежит влокал сторедже, то тогда скрипт может прочитать его и украсть. И всё. И в дальнейшем он просто будет ходить в нашу систему с этим рефреш-токеном, который достаточно долго живущий. Поэтому в браузерных приложениях обычно мы рефреш токена храним только в HTTP onlyках. В таком случае frontend код не может прочитать этот токен напрямую, а браузер сам отправляет его на refr point. Что произойдёт, когда у нас истечёт refфреш токен? Пользователя автоматически выкинет из системы. Ему просто нужно будет заново залогиниться с учётными данными и весь флоу повторится. Это супер частый подход. Он используется в современных микросервисах, поэтому я вам очень сильно рекомендую попробовать реализовать его самостоятельно руками. Тем более на интервью про секрити составляющую очень часто спрашивают, особенно на Senior или middle plus уровне. Поэтому советую вам перейти на мой Telegram-канал и посмотреть, подебажить этот код самостоятельно.

Итак, мы уже разобрали три способа аутентификации, и теперь я хочу показать вот этот пример, который наглядно демонстрирует путаницу в определениях инструментов безопасности. Это скриншот популярного инструмента, с помощью которого можно тестировать ручки, а restпик qень, без разницы. А с помощью него, его юая, мы можем выбрать метод аутентификации, который хотим реализовывать. И здесь вот мы можем увидеть наглядно, как все инструменты безопасности смешивают воедино. У нас здесь под методыфикации вписали не только сами методы, но и, в принципе, фреймворки, авторизации, о которых мы поговорим чуть позже. И это очень хорошо сигнализирует нам о том, что как бы проблема она существует на таких даже масштабах. А на один уровень вместе с бир токеном ставят GVT beре, хотя вообще они стопудово должны быть в разных областях. Ну то же самое касается и Пиключей. Достаточно забавный кейс. и показывает всю плачебность ситуации.

Дальше перейдём к опиключам. Это тоже популярное решение, особенно когда мы интегрируемся с каким-нибудь внешним сервисом, например, Гачатом либо ВКонтакте, Телеграмом, нам предоставляет этот внешний сервис IP ключ, который мы уже и прокидываем в каждом запросе. Так вот, в этом подходе у нас для клиента уникальный ключ генерируется сразу. То есть он не должен логиниться в нашей системе. У него этот ключ есть заранее, и он его просто прокидывают в запросах. Сервер этот ключ обрабатывает, проверяет, и если он корректный, то доступ к клиенту выдаётся. Этот подход очень сильно похож на подход с мир токеном. Однако между ними есть ключевая разница. В отличие отре подхода, а ключи заранее созданы, то есть не нужно логиниться, они просто, в принципе, существуют и будут жить всегда. Они не становятся expired. Этот просто ключ, который мы всегда прокидываем. И всё. Если этот ключ куда-то утечёт, нам останется с этим только смириться. Ну, если мы не узнаем об этом, а, скорее всего, мы не узнаем.

Теперь я предлагаю перейти ключам. Это тоже очень популярный подход. Часто его можно заметить, когда реализовываешь интеграцию с внешними сервисами. Они обычно нам и предоставляют эти IP ключи, а, которые мы используем и прокидываем при интеграции с ними. Пример, там точно все пробовали реализовать интеграцию с Телеграмом, и мы там этот ключ пробрасываем, либо с егочатом от Сбера, например. Так вот, а ключ - это заранее сгенерированная строка, которую мы даём нашему клиенту, и он этот ключ будет пробрасывать в каждом своём запросе. Сервер, когда будет принимать этот запрос, будет обращаться в хранилище, а где все эти ключи и лежат, а будут проверять этот IP ключ и говорить в итоге, есть ли у пользователя доступ к нашей системе либо нет. То есть ключевое отличие AP ключей от подхода с бер токеном заключается в том, что этот ключ, он генерируется заранее, он никак не обновляется, просто единожды его сгенерили и клиенту отдали. И всё. В случае, если какая-то утечка произойдёт, ошенник перехватит наш этот ключ, а он сможет им пользоваться столько времени, сколько угодно, да, пока мы просто не перегенерим новый ключ и этот не станет неактивным. Вот. Ну и формат тут запроса выглядит таким образом. Мы можем APK придать действительно как в заголовке authorization, так и в отдельном заголовке XP и вообще как угодно можем его а отправлять, как нам задумается. Дальше то же самое, как было во всех остальных запросах. Если доступ у клиента есть ключ валидный, код 200, в противном случае 401. Если в принципе не придаём этот код Апи ключ, точнее, то возвращаем четырёхсотую ошибку. Ещё одна проблема апи ключей заключается в том, что у них нет строенного срока жизни. То есть у нас нету вот этой expiration date, а ограничение доступа. Всё вот это нужно реализовывать самостоятельно. И на первый взгляд может показаться, что ключи, они также схожи с GVT токенов. Однако это совершенно неверно. А ключ - это просто строка случайная, рандомная, без стройная информация. Если мы используем этот подход, нам в любом случае нужно обращаться к хранилищу, чтобы проверить строку у нас соответствия. GVT токен у нас самодостаточный, как мы и разбирали ранее. Он внутри себя всю необходимую информацию про пользователя содержит. И при его обработке нам не нужно ни в какое хранилище идти. дополнительно наш БД нагружать. Это, конечно, большой плюс в сторону GVT, однако, ну, очевидно, что подобный подход намного сложнее реализовывать, поэтому AP ключи и используют, потому что внедрить их в проект намного проще, чем GT. Так что AP ключи используются на практике. Скорее всего, вы с ними тоже уже имели опыт работы. А нормальный подход.

А предлагаю перейти к следующему подходу, а именно к сессиям. Это старый проверенный способ аутентификации, который широко используется именно в веб-приложениях. Пользователь логинится в нашу систему, везя свои учётные данные, и при успешном логине

А сервис создаёт сессии под него, и информацию про эту сессию сохраняет в хранилище. В качестве хранилища, в принципе, подойдёт всё, что угодно. Это может быть просто на уровне кода. Мы можем сохранять эти сессии. Ну что, как бы не самый лучший подход, потому что у нас ограничены ресурсы у нашего приложения. Мы можем сохранять информацию о сессии в кэше, например, в Редисе. Тоже достаточно удобный способ. Либо, в принципе, в нашей базе данных. Ну, также, ну, бывает реализация, когда сохраняют информацию со сессии в файловой системе. Ну, это, наверное, совсем подход.

Работает этот подход так. Пользователь логинится своей учёткой в нашем сервисе, и наш сервер отправляет запрос Session Store на создание сессии. Информацию про эту сессию мы должны хранить в каком-то хранилище, в качестве которого мы можем на самом деле выбрать несколько вариантов решения. Мы можем хранить информацию про сессию на уровне кода, что не самый лучший подход, потому что у нас, в принципе, количество ресурсов по памяти наши приложения достаточно ограничены, и не хотелось бы упасть при высокой нагрузке с Out of Memory Exception. Плюс, если сервер перезапустится либо упадёт, то и у пользователя информация про эту сессию тоже исчезнет. Ну то есть его просто выкинет из нашего сервера.

Также хороший подход - это использовать Redis. Это как раз один из самых популярных вариантов для продакшена, потому что Redis быстрый и Redis сам поддерживает expiration, то есть он автоматически будет удалять записи, у которых истёк срок жизни. Ну, политики вытеснения данных, скорее всего, вы про них слышали. Мы можем их настроить так, как нам вздумается. И поэтому, если информация про сессию будет уже expired, автоматически Redis её вытеснет. Ну и также, как вариант, это хранить сессии в отдельной базе данных, например, в SQL какой-нибудь базе. Теоретически мы бы могли ещё хранить инфу про нашу сессию в файловой системе, но это очень редко встречается в современной продакшн-системе, потому что такой подход плохо масштабируется. И если у нас несколько инстанцев приложения, работать в данном формате будет совсем неудобно. Поэтому чаще всего в продакшене используется Redis. Он быстрый, удобный и как раз умеет автоматически удалять сессии по TTL.

Мы сохраняем нашу сессию в хранилище и отправляем пользователю session ID. Сервер отправляет этот session ID в cookie. Обычно он отправляет под заголовком Set-Cookie, а user эту куку читает и браузер его сохраняет. Всё, теперь он будет отправлять этот session ID в каждом запросе. Ну и наш просто сервис будет этот session ID проверять, сверять информации, которая хранится у нас в нашем хранилище. Если сессия будет действительно валидна, мы будем пользователю доступ к нашей системе давать. Ну, в противном случае также отправлять ошибку.

Главный плюс этого подхода - это контроль на сервере. То есть данные пользователей, состояние входа хранятся в нашем хранилище. Поэтому эту сессию можно быстро удалить, ограничить по времени жизни или завершить при логауте. И при правильной настройке куки через HTTPOnly такой подход хорошо работает для классических веб-приложений и на самом деле может до сих пор встречаться. Однако есть достаточно существенный минус, как раз то, что нам необходимо обращаться к вот этому стореджу, к хранилищу. То есть это обходной подход, который, ну, не очень хорошо, не очень хорошо это по нагрузке, что нам при каждом запросе нужно делать обращение ещё куда-то в какую-то хранилку. Из-за этого будет чуть-чуть подольше обрабатываться. Ну а главный минус этого подхода то, что он stateful. То есть вот эти сессии нам нужно хранить в хранилище. А это не очень хорошо, потому что, ну, при каждом запросе нужно делать дополнительный запрос в базу данных. Сама обработка по времени увеличивается и плюс дополнительная нагрузка на наши базу данных.

Поэтому преимущество есть, конечно, у токенов, и чаще всего встречаем мы их. Но при правильной настройке куков через HTTPOnly мы можем настроить данный подход корректно, и он будет хорошо работать для классических веб-приложений. Поэтому сессии могут использоваться для веб-приложений. Однако для распределённой архитектуры, для опишек мы будем использовать именно подход с токенами.

На этом, в принципе, мы закончили разбор основных методов аутентификации. И теперь я предлагаю перейти к последнему топику, наверное, самому интересному, а именно к разбору наших фреймворков авторизации. Чаще всего люди как раз именно в них и путаются. И начать я предлагаю с аутентификации с помощью OAuth, как я и сказала уже, это именно фреймворк авторизации, а не аутентификации. То есть он отвечает на вопрос, к каким ресурсам это приложение может получить доступ. Например, вы хотите дать доступ вашему приложению обращаться к вашему Google Drive диску. В таком случае вам нужно подключить Google Drive к внешнему приложению и дать этому приложению разрешение обращаться к вашим внешним данным.

Как это будет работать, как это будет реализовываться? Сначала вас пренаправят на саму форму авторизации в Google аккаунте. Работать это будет так. Сначала вас отправят на страницу подтверждения от Гугла, где он будет спрашивать, действительно ли вы готовы выдать права данному сервису на доступ к приложению. И в случае, если вы разрешите доступ, то аутентификация от Гугла отправит вам код авторизации. И этот код авторизации вы подтвердите, отправите и получите токен доступа, который уже в своём приложении сохраните, и будете этот токен доступа прокидывать в каждом запросе.

И вот здесь начинается путаница. Мы только что говорили про Token Authentication, что там аналогичный подход. Мы точно также отправляем токен для аутентификации. И здесь происходит абсолютно то же самое. Почему это метод авторизации, а не аутентификации? И здесь есть ключевая разница. Да, действительно, мы этот токен прокидываем, но мы его используем только для того, чтобы проверить, что пользователь доступ к нашей системе имеет. То есть мы по этому токену ничего о самом клиенте не знаем. Google Drive App просто видит этот факт, что токен отправлен, и для него это значит, что клиент доступ к этому ресурсу имеет. И всё. На основе этого токена он ничего не может узнать о нашем клиенте, то есть вот этой идентификации нет. Поэтому данный фреймворк предоставляет возможность только авторизации, а не аутентификации. Но если мы хотим, чтобы у нас был и функционал аутентификации, мы можем воспользоваться Open ID Connect, который как раз является надстройкой над данным фреймворком. И с помощью него мы будем нашего пользователя аутентифицировать.

Когда в форме логина вы выбираете опцию "войти в систему с помощью Google аккаунта", то вас автоматически редиректит на authorization endpoint, где и отображается вот эта страница, в рамках которой вы разрешаете приложению получить доступ к вашему Google аккаунту. Вводите свои учётные данные. Провайдер отправляет вам на мобильное устройство, допустим, код авторизации, и в этот код отправляете обратно в провайдер. В ответ получаете уже токен доступа и ID токен, которого, кстати, в OAuth в протоколе не было. Что это за ID токен? ID токен - это данные о клиенте в JWT формате. У нас в Гугле хранится информация про все наши учётные данные. И предоставив доступ к нему, он возвращает нам эти учётные данные, чтобы мы их уже могли использовать для интеграции с нашим сервисом. То есть здесь хранится всё необходимое, чтобы нашему бэкэнду пользователя идентифицировать, аутентифицировать, ну и авторизовать. Приложение получает этот токен, он валидирует его с помощью подписи и извлекает этот ID пользователя для проверки. Получив этот ID, бэкэнд понимает, что это вообще за пользователь, создаёт для него собственную сессию и выдаёт доступ уже внутри вашего приложения. Это современное решение, оно безопасное и очень хорошо масштабируется. Поэтому многие приложения сегодня используют именно такой тип входа. И вы, скорее всего, много где видели способы входа в систему через Google, через GitHub либо, например, через Яндекс.

И теперь я хочу подробнее разобрать механизм SSO. Вот. То есть это инструмент единого входа, который, конечно, тесно связан с фреймворками, которые обсуждали сейчас выше. SSO - это механизм, с помощью которого пользователь может единожды аутентифицироваться в нашей системе и обращаться повторно к другим внешним сервисам без дополнительного ввода credentials. То есть мы единожды логинимся и получаем доступ к кулу сервисов без повторного ввода каких-либо учётных данных.

Как это реализовывается? Это реализовывается как раз за счёт интеграции с Identity Provider, который как раз и предоставляет нам эту услугу аутентификатора. Конкретно в данном примере наш пользователь хочет получить доступ к почте, к Ютубу и к Google Драйву. А сначала он входит с помощью своих учётных данных, провайдер их проверяет и, если всё валидно, сохраняет информацию в хранилище сессии. В этой сессии и выдаёт пользователю cookie, которые пользователь уже будет пробрасывать в каждом запросе. Далее, при каждом запросе система будет проверять, есть ли вот эта сессия в нашем хранилище, не истекла ли она. Если она валидна, то автоматически мы будем давать доступ к этим внешним сервисам. Нет никакой необходимости нам заново просить пользователя credentials вводить. То есть, если я отправляю запрос для получения доступа к диску, то моя система проверяет сессию в хранилище, и если с ней всё ок, то вы автоматически получаете к диску доступ без ввода дополнительного учётных данных. В принципе, так будет работать не только с Гуглом и с Google Драйвом. Это просто конкретные примеры. Так будет и с Google календарём, и с Ютубом, в том числе. Ну и с многими другими сервисами.

И здесь, наверное, хочется чуть более углублённо разобрать Identity Provider, как они работают под капотом. А работают они на основе identity протоколов, самые известные из которых - это SAML, то есть Security Assertion Markup Language, и Open ID Connect, с которыми, в принципе, мы уже успели познакомиться. Они нужны, чтобы одно приложение могло доверять результату аутентификации, выполненной в другом месте, то есть у Identity Provider. То есть с помощью этих протоколов мы говорим, что если запрос передан с помощью этого протокола, мы можем верить, что действительно вот он был корректно верифицирован. То есть наше приложение благодаря этому не проверяет пароль самостоятельно, а дословно говорит: "Я доверяю этому провайдеру, потому что он передал запрос с помощью такого протокола. Если он подтвердил пользователя и прислал подписанное подтверждение, я создам пользователю доступ у себя."

Пользователь хочет получить доступ к нашему приложению. И само приложение отправляет запрос SAML на то, чтобы данного пользователя аутентифицировать. Его туда редиректит. SAML отображает пользователю свою форму ввода учётных данных, и после того, как пользователь их введёт, он верифицирует введённые данные и отправит в Bitrix ответ о том, что пользователь успешно либо неуспешно аутентифицирован. И здесь, наверное, ключевое, что хочется разобрать, как в принципе эти запросы и ответы выглядят. А выглядят они в достаточно нестандартном формате, ну, не самом актуальном на данный момент, то есть в XML формате. Это запрос, который Bitrix будет отправлять в SAML. Давай разберём конкретный флоу. Пользователь отправляет запрос на получение доступа к нашей системе. Пусть это будет Bitrix24. На самом деле именно протоколы, они как раз и используются в подобных корпоративных legacy системах, потому что спойлер тут используется XML. Так вот, а приложение понимает, что у пользователя нет локальной сессии, и Bitrix24 формирует запрос в формате, с которым может взаимодействовать сам протокол, это XML, и говорит о том, что вот у пользователя нет локальной сессии, аутентифицируй его за меня. Браузер, это Identity Provider редиректит пользователя на страницу логина, ну, которую Identity Provider предоставляет. Пользователь вводит учётные данные, Identity Provider эти данные проверяет и после успешного входа возвращает Bitrix 24 ответ, который содержит внутри себя assertion. Ну, ключевая сущность, по которой Bitrix 24 понимает результат. Успешно либо неуспешно эта аутентификация прошла. А приложение этот ответ получает и обратно возвращает пользователю информацию о том, что вот доступ к нему выдан. Как я и говорила, SAML использует XML. Выглядят запросы на аутентификацию и ответы таким образом, ну, не самый, так скажем, удобный и человекочитаемый формат. Однако данный подход всё равно остаётся актуальным, поскольку Legacy системы существуют, так что там XML продолжает жить.

Следующий вариант Identity протокола - это Open ID Connect, про который, в принципе, мы уже успели немного поговорить. Flow здесь аналогичный. Пользователь только теперь хочет получить доступ не к Bitrix 24, а к своей почте Gmail. Подход совершенно аналогичный. Здесь, на самом деле, только отличается формат запросов и ответов. А пользователь отправляет запрос в Gmail. Gmail видит, что данного пользователя нет активной сессии, и тогда он отправляет уже в Identity Provider запрос на аутентификацию пользователя. У нас происходит логин, провайдер редиректит на страницу для логина, где он вводит учётные данные, получает вот этот токен доступа, который впоследствии отправляет в Identity Provider. Провайдер убеждается, что действительно пользователь идентифицирован, верифицирован, и в ответ ему отправляет уже вот этот ID токен, который выше мы успели обсудить. Он содержит всю необходимую информацию про нашего пользователя. Мы прокидываем эту информацию в наше приложение, и приложение уже имеет всё необходимое, чтобы быть уверенным в том, что наш пользователь верифицирован. Главное отличие в том, что SAML - это более enterprise-ное решение, более Legacy, которое использует XML. Open ID Connect - это современный стек. Смысл у них общий. Приложение не хранит пароль пользователя у себя, а доверяет внешнему провайдеру вот эту идентификацию и аутентификацию пользователей.

Мы разобрали популярные методы аутентификации. Следующий этап - это разбор авторизации. Если вам было бы интересно, чтобы я выпустила подобный видеоролик именно на эту тему с разбором инструментов детально, а напишите, пожалуйста, об этом в комментах, и я обязательно сниму. Если после просмотра этого видео вы убедились в том, что действительно проблема зачастую стоит не в том, что разработчик не знает какой-то конкретный инструмент и ему просто нужно этот инструмент доучить, а в том, что отсутствует у разработчика вот это понимание системности, как инструменты взаимодействуют друг с другом, то вы можете обратиться ко мне, и я данный запрос вас закрою. У меня уже система настроена. В описании вы найдёте отзывы, кейсы о работе со мной. Также первая ссылка - это мой личный контакт. Напишите туда, и мы с вами свяжемся, договоримся о встрече, где я подробно разберу ваш кейс и расскажу, как конкретно с вашим запросом смогу помочь. Также вторая ссылка - это ссылка с разбором моего метода, как я работаю своими подопечными, за счёт чего они достигают результата за 3 месяца, получают офер от 250.000 руб. Их кейсы, отзывы вы можете прочитать в моём Telegram-канале. Ссылку я тоже оставлю в описании. Там есть контакты, вы можете с ними связаться напрямую, то есть самостоятельно отвалидировать, что это живые люди, которые получают реальную помощь.

Разработка становится проще, когда вместо разрозненных терминов мы используем систему и понимаем, как она, в принципе, устроена, из каких частей состоит. В таком случае и обучение строится достаточно интересно и комфортно. И с аутентификацией. Точно то же самое, но вы это сами заметили после просмотра данного видео. Надеюсь, оно вам было полезно. Пожалуйста, пишите в комментах свой фидбэк, а я буду рада увидеться с вами снова в следующем видео. Меня зовут Катя Кондратьева, я карьерный консультант. Ну и также стартап-основатель Полиморфера. Это платформа для настольно-ролевых игр, с которой вы можете ознакомиться также по ссылке в описании. До скорых встреч. M.