Комментарии 10
А зачем в JWT токене отдавать пароль, даже закодированный?
authUserMap.put("password", ((AuthUser) auth.getPrincipal()).getPassword());
По хорошему должен быть еще сервис авторизации
https://curity.io/resources/learn/jwt-best-practices/
Строчка #5: По технике безопасности нам необходимо хранить пароль пользователя в зашифрованном виде, мой passwordEncoder - это бин, который возвращает BCryptPasswordEncoder.
По технике безопасности, нам ни в коем случае нельзя хранить пароль ни в каком виде. Мы храним хэш, что и делает 5 строчка. А не то, что написано.
Уверен, это не худшая статья, за которую люди получали приглашение на Хабр, ибо вопросов вызывает очень много (в целом, необходимо упомянуть: код действительно получился относительно чистым) – это и уже упомянутый факт включения хэша пароля внутрь JWT-токена, и то что автор называет хэшированный пароль зашифрованным (хэширование необратимо), зачем-то подчеркнута необходимость хэширования (кажется, аудитория Хабра и не мыслила иначе), очень много уделено внимания презентации JWT (он появился не в этой декаде), ну и конечно же правильно было бы «ключом», не «ключем». Возможно, что-то пропустил, но да, удачи автору в написании новых статей.
По-взрослому – это с KeyPass/WebAuthn
Хранить name, email, roles и любые другие изменяемые данные внутри токена не стоит: они могут устаревать, а токен - это даже не кеш. Допустим, пользователь сменил email, а затем заходит со старым токеном - старую почту из него использовать нельзя. Или еще хуже: ему запретили доступ, лишив роли, а пока токен не истек и пользователь его использует, эта роль ему будет доступна. Следовательно, понадобится необходим механизм отзыва токена, по uuid или времени, только из-за устаревания каких-то сторонних данных, а пользователю придется чаще логиниться - определенно проще не смешивать обязанности и не навешивать хранение данных на токен. Обычно достаточно только лишь ID пользователя.
Еще в коде не показано, но на всякий случай: если и хранить хэши паролей пользователей, то очень желательно не в чистом виде, а с "солью" и в идеале уникальной для каждого пользователя, чтобы при компрометации базы пароли не оказались сразу и массово раскрыты по уже известным хешам. Статья на тему: https://habr.com/ru/articles/145648/.
И по упомянутым проблемам:
Допустим я зарегистрировался в хроме, потом вышел. Если я захочу зайти в аккаунт через сафари, то возникнут проблемы (насколько я знаю jwt хранится в браузере, как хранить его к кэшэ, например, пока не знаю, предположительно можно класть в redis и доставать, если в запросе нет токена и проверять на его наличие в кэше
Кажется, вы не до конца поняли идею JWT. Этот протокол был разработан, чтобы пользователь мог получить токен на руки, а затем предъявлять с каждым запросом как подтверждение личности. Таких токенов можно выпустить множество для одного пользователя. Токен необязательно хранится в браузере - его, конечно, можно положить, например, в localStorage, но вообще это полностью в руках разработчика клиента, хоть через curl/telnet в консоли запросы шлите. Хранить токен на стороне сервера при этом нет необходимости: подпись обеспечивает достоверность записанных в нем данных. А если вы получили запрос без токена, то как вы пользователя-то опознаете, если в этом и заключается главное назначение JWT?
Если же вы хотите зачем-то хранить токен на своей стороне, то именно JWT вам и не нужен, можете хранить что угодно и как угодно. Но тогда и механизм становится больше похож на классическую сессию, когда пользователю после логина выдается случайная уникальная строка-метка для такой же отправки с каждым запросом, а сервер имеет во временном хранилище сопоставление этих меток с пользователями.
Не удалось протестировать, что будем, если токен протухнет
Надо бы протестировать, прежде чем публиковать решение, тем более, что это довольно просто же сделать: выпустить заведомо истекший токен (или выставить срок поменьше и подождать) и выполнить с ним запрос. Тут зависит от библиотеки: добавили ли там проверку с выбросом исключения или оставили на усмотрение разработчика.
Насколько я понял, автор возвращает токен в теле ответа, а frontend передаёт токен в header.
Вопрос: насколько безопасно отключать CSRF .csrf(AbstractHttpConfigurer::disable)
при том что кука не используется?
За JwtConstants голову бы оторвал
Имхо, сама идентификация по телефону или email - это крайне порочная и дурная практика. Во-первых, лучший логин - это уникальная строка (не совпадающая ни с именем или ником на веб-ресурсе, ни с email, ни с номером телефона). Во-вторых, номер и email не принадлежат пользователю, а скорее арендуются: они могут быть изменены или изъяты поставщиком услуг, либо пользователь может сам удалить ящик или расторгнуть договор - всё это редко, но происходит. В-третьих, если уж используется мыло или телефон - имеет смысл их также хэшировать на клиенте (зачем они в чистом виде в БД? а если утечёт?).
Мой опыт создания регистрации: @AuthenticationalPrinciple, JWT, UserDetails