В большинстве приложений у вас, вероятно, будут учетные записи пользователей. И если вы это сделаете, вы, безусловно, захотите ограничить то, к чему имеет доступ конкретный пользователь. JSON Web Tokens — это популярный метод авторизации пользователей на ресурсах внутри вашего приложения на стороне клиента.
Когда вы отправляете обычный запрос на выборку серверу, вы обычно отправляете method
запроса (GET, POST и т. д.) вместе с объектом header
. Что-то типа:
Это прекрасно работает, но в этом запросе недостаточно информации для авторизации пользователя после того, как запрос попадет на серверную часть. Дополнительная информация, которая нам нужна, — это веб-токен JSON. Как только пользователь войдет в приложение, все последующие запросы будут отправляться вместе с уникальным токеном, который предоставляет пользователю доступ к любым маршрутам и ресурсам, разрешенным с помощью этого токена.
Маркер должен быть отправлен как другая пара ключ/значение объекта headers
. key
будет «Авторизация», а value
будет «Носитель token
», например:
Этот запрос попадет на соответствующий контроллер в вашем бэкенде Rails. В этом контроллере у вас будет несколько методов, которые представляют actions
для вашего routes
. Обычный способ разрешить доступ к этим методам/действиям — использовать макрос before_action
, который Rails предоставляет в верхней части класса вашего контроллера.
Выше мы выполняем метод require_login
перед запуском любого действия в файле ConversationsController
. Откуда require_login
и authorize
? Хорошо видно сверху, что ConversationsController
наследуется от ApplicationController
. Итак, ApplicationController
— это место, где живут эти два метода. А поскольку ApplicationController
наследуется от ActionController
, любой метод в ApplicationController
будет доступен во всех других наших контроллерах.
В конечном счете, наш запрос направляется к действию index
внутри ConversationsController
:
Ниже показано, как выглядит ApplicationController
. Здесь мы рассмотрим весь код, чтобы увидеть, что происходит по мере выполнения нашего запроса.
Итак, вспомним, что методы require_login
и authorize
выполняются первыми, когда мы вызываем их с помощью макроса before_action
. Метод require_login
отобразит объект ошибки JSON, если пользователь НЕ вошел в систему. Метод authorize
отобразит объект ошибки JSON, если вошедший в систему пользователь НЕ является пользователем, идентификатор пользователя которого передан в URL-адресе. Это означает, что действие index
фактически не будет выполнено, если существует какой-либо из этих объектов ошибки, поэтому авторизация работает. Но как?
Как мы узнаем, вошел ли пользователь в систему? Мы видим, что ApplicationController имеет метод logged_in?
, который возвращает оператор двойного удара для метода current_user
. Таким образом, пользователь считается вошедшим в систему, если метод logged_in?
возвращает значение true, а это означает, что метод current_user
должен вернуть фактический объект (пользователя), чтобы оператор двойного удара выдал true
.
Чтобы метод current_user
возвращал объект (пользователя), метод decode_token
должен возвращать значение true. В методе decode_token
действительно происходит волшебство. Токен, который мы отправили в нашем запросе на выборку с «Авторизацией» headers
, декодируется здесь с помощью «JWT.decode» с переданным нашим токеном. Из декодированного результата мы извлекаем идентификатор пользователя внутри метода current_user
. Затем мы используем метод find_by
Active Record, чтобы найти пользователя с этим идентификатором пользователя. Оттуда мы можем не только проверить, вошел ли пользователь в систему, но и убедиться, что пользователь авторизован для просмотра этого контента.
Что хорошего в макросе before_action
Rails, так это то, что мы можем ограничить любое из наших действий/контроллеров одной строкой кода. Я могу так же легко использовать метод require_login в моем UsersController
:
У вас может возникнуть вопрос: откуда на самом деле token
во внешнем интерфейсе при отправке запроса? Я использовал вариант localStorage
, который может быть или не быть лучшим способом. Вы можете сохранить токен в localStorage
со следующей строкой в ответе об успешном входе в систему: localStorage.setItem(‘token’, jwt)
Вот и все!