Уроки, которые я извлек из недавнего проекта, который я делал, который включал создание аутентификации на основе токенов с использованием passport-jwt.

До сих пор я всегда думал, что могу решить любой код, добавив в него кучу операторов `console.log`. На всякий случай мне приходилось применять отладчик или устанавливать точки останова, в основном это было для проверки переменных и в основном всегда для меньшего кода. Или код, с которым я был хорошо знаком (будь то написанный мной или кем-то другим).

Мой код аутентификации на основе токенов, который использовал passport-jwt, не работал.

Вчера я очень долго застрял в куске кода. Намного дольше, чем я хотел бы признать.

Как работает аутентификация на основе токенов

  • Пользователь регистрируется (его данные сохраняются в базе данных, и браузер получает токен)
  • Этот токен должен быть включен браузером для доступа ко всем «защищенным» маршрутам (его можно включить в заголовок или тело запроса). Я консультировался с парой руководств, и все они использовали заголовок для передачи токена, поэтому я решил следовать тому же подходу.

Регистрация пользователя и отправка токена обратно в браузер работали нормально. Вчера я застрял, когда пользователь пытался получить доступ к защищенному маршруту.

Поскольку я еще не создал внешний интерфейс приложения, я собирался протестировать его с помощью Postman.

Все это фиаско началось с того, что я попытался отладить свой код, и закончилось тем, что я обнаружил, что имена заголовков не чувствительны к регистру: [SO](https://stackoverflow.com/questions/5258977/are-http-headers-case-sensitive /5259004#5259004)

Конец истории я уже озвучил. Но в данном случае гораздо интереснее уроки, которые я усвоил на пути к открытию этого утверждения.

Метод декодирования токена, отправленного по запросу (это экспресс промежуточное ПО)

  • Расшифруйте токен, чтобы получить полезные данные, которые использовались для создания токена. Для этого есть библиотеки и я решил использовать для этого паспорт-jwt
  • Как только токен декодирован, вы получаете полезную нагрузку (userId или уникальное имя пользователя и т. д., которое в первую очередь используется для создания токена) и запрашиваете базу данных, чтобы найти пользователя, соответствующего токену. Если пользователь существует, у нас есть правильный токен, поэтому переходим к следующему обратному вызову. Если нет пользователя, соответствующего токену, мы не переходим к защищенному маршруту и ​​отображаем «неавторизованный» (опять же это делает паспорт)

Код для защиты маршрута с помощью токена приведен ниже.

Я тестировал свой код с помощью Postman, где я отправлял свой веб-токен json (созданный при регистрации нового пользователя) в качестве заголовка авторизации.

Приведенный выше код выглядит довольно прямолинейно.

Когда я отправил запрос GET без заголовка, я не получил сообщения об ошибке, и ни один из операторов console.log в моей функции обратного вызова new JwtStrategy(jwtOptions, callback) не сработал. Я был немного сбит с толку, но понял, что все в порядке, пока маршрут защищен.

Затем я сделал запрос GET от Postman на этот раз в своих заголовках, я добавил Authorization в качестве ключа и свое значение как token, которое я получил при регистрации пользователя.

Я был уверен, что смогу просмотреть защищенный маршрут. Я отправил токен, и моя реализация аутентификации токена была правильной (проверено из разных источников).

Но, к сожалению, я не увидел защищенный маршрут и не смог снова увидеть какие-либо операторы console.log в функции обратного вызова.

Я был озадачен. Мои имена заголовков были такими же, конечно, я должен быть в состоянии аутентифицироваться. И даже если я не был аутентифицирован, я должен увидеть ошибку в операторе обратного вызова.

Мне потребовалось некоторое время, чтобы понять, что моя программа не выполняет обратный вызов и завершается сразу после jwtOptions . Я пытался добавить кучу операторов console.log во многих местах.

После этого я попытался решить проблему, изменив код наугад. Я добавил больше промежуточных программ (тот, что был до requireAuth, я все еще оставил в коде, чтобы показать, что я пытался отладить проблему в худшем случае).

Я даже запустил отладчик с помощью VS Code (но подключил отладчик Chrome вместо Node.)

Наконец, в одной из итераций изменения кода, добавления дополнительных операторов отладчика и добавления дополнительных операторов console.log я изменил следующий фрагмент кода:

const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('authorization'),
secretOrKey: process.env.SECRET_KEY
};

Я сделал ExtractJwt.fromHeader('authorization')

Просто изменил регистр ключа заголовка запроса, и код заработал.

До этого момента я часами пытался понять, что происходит с кодом, как использовать отладчик в VSCode (наконец-то мне удалось подключить Node как среду, но я не использовал отладку должным образом) и был просто рад, что это наконец-то заработало. .

Я закрыл ноутбук и положил этому конец.

Однако, когда я встал сегодня, несколько вещей не давали мне покоя.

Почему «авторизация» должна работать, а не «Авторизация» было первым делом.

Во-вторых, мои навыки отладки. Наконец-то мне удалось начать отладку в VS Code, но я не использовал его должным образом.

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

Как запустить отладчик в VS Code

  • Чтобы запустить отладчик для узла, выберите значок отладки слева.
  • Он открывает панель отладки.
  • Затем вверху есть небольшая кнопка «начать отладку», когда вы нажимаете ее, нас спрашивают, в каком контексте мы хотим отлаживать.
  • Я выбираю Node, потому что хочу отлаживать экспресс-приложение.
  • Он запускает код и прерывается в первой точке останова.

В моем случае я просто хочу сломаться, когда запускаю маршрут через Postman. Поэтому я просто продолжаю нажимать «Продолжить» на панели инструментов отладки.

Как только приложение больше не приостановлено, я запускаю защищенный маршрут через Postman. (А дальше начинается основная отладка)

Обратите внимание на отладчик VS Code: если мы изменим какую-либо переменную в моем коде, как я сделал "авторизацию" на "авторизацию", мы должны остановить отладчик и запустить его снова. (Может быть, я мог бы внести некоторые изменения в файл конфигурации, чтобы справиться с этим, но на данный момент я не знаю, как это сделать)

С помощью отладки узла я могу прервать маршрут GET или маршрут POST, а затем изучить и проверить, что происходит (это не происходило, когда я подключал отладчик Chrome).

С правильным кодом (то есть «авторизацией» в `jwtFromRequest: ExtractJwt.fromHeader('authorization')` ) я продолжал входить в соответствующий код после того, как наткнулся на точку останова для маршрута «/protected» (потому что это подходящее место, которое нам нужно чек.)

После долгих поисков кода я нашел место в коде паспорта, где извлекался «токен». Бинго, это то, что я хотел. Поэтому я добавил точку останова.

Затем я изменил «авторизацию», которая является правильным названием заголовка, на «Авторизация». К сожалению, пришлось перезапустить отладчик.

Но на этот раз я знал, какой раздел кода является важным, где мне нужно было проверить мой код дальше, потому что там у меня была точка останова. И бинго. Нет токена, когда мы называем заголовок авторизации Authorization

Я зашел в документацию passport-jwt, прочитал еще немного и понял, что имена заголовков аутентификации могут быть любыми (это не было моим опытом. В конце концов, когда я использовал «Авторизация» вместо «авторизация», приложение не работало)

Итак, затем я изменил имя заголовка на Random как в своем коде, так и в своем запросе почтальона, а затем перезапустил отладку. На этот раз, поскольку у меня была точка останова внутри кода passport, где я знал, что должен был сломаться, мне не нужно было проходить весь этот код, и я мог просто нажимать кнопку continue, пока не достигну точки останова в паспорте.

Затем, когда я достиг точки, где переменная token извлекалась ExtractJwt, я добавил переменные для наблюдения. Именно здесь я понял, что хотя имя моего заголовка было Random (в моем коде, в моем запросе почтальона и даже в коде паспорта), request.headers не имеет атрибута с именем Random, но имеет атрибут с именем random.

Таким образом, паспорт пытался извлечь токен из request.headers с именем Random, потому что это было имя, которое я указал для токена в своем коде, но не было атрибута с именем Random.

В этот момент я понял, что что-то происходит, когда Почтальон устанавливал заголовки, и я погуглил и нашел ссылку, которую я дал в начале.

Таким образом, в основном заголовки были преобразованы в нижний регистр Почтальоном. Таким образом, ExtractJwt не смог извлечь токен, потому что искал Random, а не random.

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

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