Аутентификация React и Rails с нуля с использованием JWT, часть III

Предпосылки:

Реакт установлен

Рельсы установлены

С возвращением, это третья и последняя часть сборки аутентификации React и Rails. Как вы помните из части II, мы добавили к нашей функции регистрации, также создав функцию входа, которая аутентифицирует наших пользователей. Если вы не следили за первой или второй частью, вы можете найти копию репозитория, который мы начнем с сегодняшнего дня, здесь.

Если вы только что скопировали репо, вам нужно будет запустить:

На бэкенде:

На фронтенде:

Если вы следовали частям I и II, вам нужно будет только запустить свои серверы, запустив последнюю строку кода для каждого из них.

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

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

Чтобы начать работу, нам нужно перейти к нашему бэкенду и открыть наш контроллер приложения. Здесь мы создадим наш метод is_authorized, который, как вы уже догадались, проверит, действительно ли наш пользователь авторизован. В этом случае, если наш пользователь авторизован, он будет иметь доступ к своей пользовательской информации. В противном случае им будет представлена ​​ошибка с просьбой войти в систему, чтобы получить доступ к информации о пользователе. Ваш метод авторизации должен выглядеть так:

Из кода видно, что наш пользователь получит сообщение об ошибке, если он не войдет в систему. Мы вызвали метод is_signed_in, и теперь нам нужно его создать. Для этого нам просто нужно проверить, использует ли пользователь в настоящее время наше приложение, установив для текущего пользователя логическое значение. Предлагая нам истинное или «ложное» значение для текущего состояния is_signed_in. Это, в свою очередь, означает, что нам также потребуется создать наш метод current_user, который будет проверять легитимность токена, предоставленного нашим пользователям. Мы можем извлечь токен наших пользователей из заголовка авторизации нашего бэкэнд-запроса. Ваши два новых метода должны выглядеть следующим образом:

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

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

Это несколько деликатный процесс из-за того, что если токен не существует, то при попытке его декодирования рельсы выдадут нам большую ошибку 500. Это остановит наше приложение, и это то, чего мы не хотим испытывать, не говоря уже о наших пользователях. Чтобы избежать этой проблемы, мы будем использовать начало и спасение, это позволит нам попытаться декодировать полученный токен. Если мы столкнемся с ошибкой, такой как 500, о которой я говорил ранее, спасение позволит нам избежать таких ошибок, которые в противном случае заблокировали бы наше приложение. Ваш оператор if должен быть обновлен как таковой.

Теперь, когда у нас есть готовая система безопасности, давайте начнем ее создавать и получим токен нашего пользователя. Это будет похоже на то, как мы закодировали наш токен в нашем методе входа, с некоторыми отличиями. Для этого мы вызовем JWT для декодирования нашего исходного токена, который содержит идентификатор нашего пользователя, а также наш секрет, поскольку это то, что мы закодировали от нашего пользователя в нашем методе входа. Крайне важно, чтобы вы кодировали и декодировали одну и ту же информацию, иначе вы не получите то, что было закодировано.

Нам будет возвращен массив, как только JWT расшифрует наш токен, и из нашего декодированного токена мы захотим извлечь их идентификатор. Мы можем просто сделать это, вызвав индекс объекта, который мы закодировали, идентификатор нашего пользователя, а затем вытащив его из его ключа, мы останемся с идентификатором пользователя. Мы также установим это в переменную экземпляра идентификатора пользователя, поскольку у нас останется числовой идентификатор пользователя, если все пройдет гладко.

В случае, если все пойдет не так гладко, наше спасение спасет нас от надвигающейся ошибки, которую мы вот-вот получим. Мы будем использовать наше спасение, чтобы остановить запуск ошибки декодирования JWT, и в этом случае вернет ноль или ничего. Ваше обновленное начало и восстановление должны выглядеть следующим образом.

Теперь, когда у нас должен быть идентификатор нашего пользователя, нам все еще нужно получить нашего пользователя, что мы и сделаем на основе его идентификатора. Для этого мы создадим еще один оператор if, следующий за последним, который мы только что закончили. Если у нас есть идентификатор пользователя, мы найдем этого пользователя и вернем его или вернем nil. В обоих случаях, когда мы возвращаем nil в этом методе, наша пользовательская ошибка будет отображаться из нашего авторизованного метода. Наш первый экземпляр остановит нашу ошибку декодирования JWT, и в этом случае он остановит ошибку активной записи, если этот идентификатор пользователя не существует в базе данных. Ваш завершенный метод текущего пользователя должен выглядеть следующим образом.

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

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

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

Теперь давайте перейдем к контроллеру нашего пользователя, и прямо вверху мы создадим пропуск перед тем, как действие будет авторизовано. Небольшая проблема заключается в том, что мы пропустили наш авторизованный метод, что делает его практически бесполезным, если мы не зададим ему некоторые параметры. По сути, что разрешать и что не разрешать кому-либо делать, если они не авторизованы. Два метода, к которым мы хотим, чтобы пользователь имел доступ до авторизации, — это либо регистрация, которая будет нашим методом создания, либо вход без метода создания. Пока я еще в разработке, я лично включу индексное действие для всех своих контроллеров, но не буду рекомендовать его для развернутых приложений. Это позволит мне увидеть, что хранится в моей базе данных rails, localhost:3000/your route, после того, как пользователям потребуется авторизация. Ваш пропуск перед действием должен выглядеть так.

Последняя часть этой головоломки заключается в том, что как только наш пользователь, наконец, будет авторизован, мы предоставим ему доступ к своим данным, именно то, что вы увидите в своем профиле. Для этого мы просто создадим новый метод под названием «пропустить перед действием» с именем user_profile. Если вы создали свой контроллер и таблицы с помощью скаффолда rails g, наш метод профиля пользователей, который мы собираемся создать, будет просто методом show. В нашем методе профиля пользователя мы просто хотим показать или отобразить нашего пользователя. Ваш обновленный контроллер пользователей должен выглядеть следующим образом.

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

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

Для этого мы будем использовать компонент смонтированный с оператором if, чтобы при обновлении страницы у нашего пользователя уже была авторизация для доступа к нашему приложению. Сначала нам понадобится наш токен из локального хранилища, который мы установим в переменную token. Если у нашего приложения есть токен, мы выполним выборку по нашему новому маршруту, который мы создали, profile. Он будет похож на его маршрут в том смысле, что это запрос на получение, но мы будем пытаться отправить заголовок авторизации с нашим токеном. Нам нужно будет отформатировать наш ответ так, как он должен быть получен, то есть в виде строки, содержащей носитель и токен. Ваша завершенная выборка должна выглядеть следующим образом.

Ответ на наш вызов fetch вернет нам либо нашего авторизованного пользователя, либо нашу ошибку. Это означает, что нам нужно будет выполнить некоторый условный рендеринг в форме оператора if для обработки каждого из возможных результатов. Для этого мы проверим, содержит ли наш результат что-то, что содержал бы пользовательский объект. Как вы видели ранее, я предпочитаю использовать идентификатор пользователя, когда имею дело с ним, так что это то, что мы будем проверять. Если в нашем результате присутствует идентификатор, мы затем установим состояние пользователя в наш результат, потому что результатом является пользовательский объект. Готовый компонент должен выглядеть следующим образом.

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

Поздравляем, вы сделали это! Если вы правильно выполнили эти шаги, теперь вы сможете создать пользователя, позволить ему войти в систему и оставить этого пользователя авторизованным для использования нашего приложения после входа в систему. Если вы клонировали репо только для этой части. из пошагового руководства, вам сначала нужно будет создать пользователя для входа. Вы также можете проверить свое сообщение об ошибке, введя ерунду в поля регистрации, а также попытавшись посетить любой из маршрутов, которые мы сделали закрытыми на бэкэнде. Любой пользователь, у которого есть токен, теперь будет авторизован для использования нашего приложения после входа в систему.

Если вы хотите посмотреть на готовое репо, вы можете найти его здесь.

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