Создание REST API с использованием Spring WebFlux и Security
Вставка
- Опубліковано 15 чер 2024
- В данном видео рассмотрен пример создания REST API с использованием следующих технологий:
- Spring Boot 3
- Spring Security (JWT)
- Spring WebFlux
- Spring Data R2DBC
- MapStruct
- PostgreSQL
- Flyway
Ссылка на Github репозиторий:
github.com/proselytear/webflu...
Наше дружное сообщество:
t.me/pse_club
Материалы для разработчиков:
proselyte.net/
00:00:00 Введение
00:00:20 Создание проекта
00:11:36 Создание миграций БД
00:15:40 Создание базовых классов
00:23:20 Реализация логики генерации JWT токена
00:46:30 Реализация логики валидации JWT токена
00:53:05 Построения цепочки аутентификации
01:04:22 Финальная конфигурация с использованием SecurityWebFilterChain
01:12:11 Реализация REST контроллеров
01:23:15 Проверка REST API средствами Postman
01:24:21 Добавление и конфигурация обработчика ошибок
01:25:40 Заключение
Евгений, спасибо за качественный и постоянный контент!
Спасибо за отзыв!
Отличная подача материала. Благодарю за урок и потраченное на его создание время.
Большое спасибо за отзыв!
Большой респект за ваши видео, пожалуйста, продолжайте
Большое спасибо за отзыв!
Ураааа спасибо огромное ))))) Как и просил вас про спринг секьюрити. Вы лучший!)
Спасибо за отзыв!
Посмотрел чуть ли не на одном дыхании, спасибо! Узнал много нового для себя
Спасибо за отзыв, рад, что материал оказался полезен!
Очередное полезное видео, спасибо Евгений!
Спасибо за отзыв, Семён!
Отличный, полезный понятный урок благодарен вам коллега!
Спасибо за отзыв!
Здоровья тебе! Большое спасибо!
Спасибо за комментарий и пожелания! Взаимно!
Евгений, огромное спасибо за труды, было очень приятно и полезно смотреть, очень крутой уровень донесения информации! Не сразу все понятно, надо пару раз вдумчиво пересмотреть, но это круто, снимаю шляпу.
Спасибо вам за отзыв!
Отличный урок, большое вам спасибо!
Спасибо за отзыв!
Спасибо за материал! Свежо и актуально (особенно на фоне видео с 3+ летней давности по спрингу), подписка.
Спасибо за отзыв!
Урок супер ! Подача материала класс !
Спасибо за отзыв :)
Супер, не только реактивщина, но и еще куча полезных мелочей. Однозначно топ контент.
Спасибо за отзыв!
Наконец-то актуальное видео на эту тему! Спасибо большое!
Спасибо за комментарий!
Спасибо Евгений! Отличная подача и содержание. недавно делал авторизацию на реактивщине, но все равно посмотрел видос.
Большое спасибо за отзыв!
Большое спасибо за видео, Евгений! Однозначно must have для всех людей, изучающие Java! Что в ютубе, что в телеграмм канале максимально собранная и четкая речь! Очень приятно читать и слушать.
Спасибо за отзыв!
Огромное спасибо! Урок супер!
Спасибо за отзыв, Петя!
пушка. Очень ждал чего-нибудь реактивненького)
Спасибо за комментарий!
💣💣💣
Спасибо огромное за такой видеоурок!
Спасибо за отзыв!
Огромнейшее спасибо!
Что бы я без вас делал!)
Спасибо за отзыв :)
ооо видео по реактивности!афигенно. спасибо! а можно видео по реактивности именно по теории. что это такое, что дает, в общих чертах как устроено
Спасибо за отзыв!
По видео - попробую поставить в очередь :)
Евгений, 100 тысяч спасибо!!! Именно то, что искала и еще и в Вашей великолепной подаче😁 ну просто 100 из 100!
Большое спасибо за отзыв!
все время удивляюсь вам, спасибо за лучший бесплатный контент по Java и не только!
Большое спасибо за отзыв!
Большое спасибо за урок! Очень порадовало увеличение размера шрифта, никто обычно об этом не заботится
Спасибо за отзыв!
Суперское видео! Столько информации полезной. Есть несколько вопросов:
1) зачем в ДТО id? Ведь мы работаем с этими id только в нашей системе. И зачем в ДТО enum? Почему не строка? Ведь чем проще типы данных в ДТО, тем проще с ними работать во внешних системах и на клиенте.
2) почему в целом не сделал ДТО иммутабельным? По логике любой ДТО не должен изменяться, а служит лишь для передачи данных.
3) почему в UserEntity hashcode() не по полю username? это поле уникально и обязательно, поэтому было бы логично избежать таким образом возможных проблем рассчета хэша при добавлении полей в будущем(например в случае зацикливания и т.п.), тут такого не предвиделось, но в целом в качестве хорошей практики.
4) почему секретные проперти(пароли, секреты) задаются напрямую, а не через переменные окружения?
Спасибо за отзыв и вопросы!
1. ID часто отдают в DTO, enum позволит сразу отсечь некорректные значения.
2. Не всегда удобно для тестирования
3. корректное замечание, можно было сделать и так.
4. Учебный проект, поэтому для удобства работы хардкод.
Уже бьюсь в экстазе от используемых технологий в начале видео) спасибо за прекрасный вечер)
Спасибо за отзыв :)
лучшее видео из актуального по данной теме! лайк, подписка
Спасибо за отзыв!
Видео очень интересное, спасибо!
Спасибо за отзыв!
Евгений, спасибо отличный материал!!
Спасибо за отзыв, Роман!
@@EugeneSuleimanov Очень хотелось бы увидеть как тестировать такие ресты, создание, валидация токена. Если сделаете такое видео, то будет супер классно, а так отличная работа - моё почтение ))
@@user-nh7tp8xj8y добавлю в очередь, спасибо за идею!
Контент ТОП, ждем продолжения.
Спасибо за отзыв!
Спасибо, очень полезное видео. Чтобы не писать скрипты для базы справа вкладка, в ней удобней и быстрее все делать. Если это скрипт стартовый для создания с нуля, то так же проще через вкладку создать всё таблицы, потом делаем дамп скелета и вставляем куда нужно
Спасибо за отзыв! Flyway надёжнее, ИМХО 😊
От души❤❤❤ Это прям супер топ🎉🎉🎉🎉
Спасибо за отзыв :)
Привет. Спасибо, было очень полезно. Я у тебя уже не первый раз вижу как ты старательно проверяешь время истечения токена, но это вроде не так работает. там Jwts.parser() упадет с JwtException если токен протух и твоя логика не сработает. А в остальном очень круто!
Спасибо за комментарий!
Обязательно проверю этот момент, спасибо.
Спасибо, полезное очень видео
Спасибо за отзыв!
Крутой ты мужик , спасибо 🎉
Спасибо за отзыв :)
Долгожданное видео!!! Спасибо, Евгений за КАЧЕСТВЕННЫЙ контент👍👍👍
Спасибо за отзыв, Максим!
@@EugeneSuleimanov 0:43
@@EugeneSuleimanov 😊
@@EugeneSuleimanov 😊
@@EugeneSuleimanov 1:19 1:19
Евгений, спасибо за работу, у Вас очень хорошее объяснение и интересный подход. Хотелось бы посмотреть, как построить систему безопасности на spring cloud webflux jwt, потому что на монолитные приложения можно найти примеры, а вот на микросервисные к сожалению нет, да и в принципе на микросервисы почему-то меньше информации.
Спасибо за отзыв!
Большой цикл по микросервисам в работе. К сожалению, по срокам не могу сориентировать из-за высокой рабочей загруженности.
как всегда 🔥🔥🔥🔥🔥
Спасибо за отзыв :)
Спасибо за видео 👍
Спасибо за комментарий!
Лучший на ютубе!)
Спасибо за отзыв :)
Женя, на высоте,как обычно! Рахмет,сенсей за труды,видно,что потратил время!
Большое спасибо за отзыв!
Не хватает только refresh token логики, хорошая идея для нового видосика на след год))
Спасибо за комментарий и предложение :)
Золото просто!)
Спасибо за отзыв :)
Очень круто!!!!
Спасибо за отзыв!
Супер) Спасибо
Спасибо за отзыв!
Спасибо, очень интересно получилось, сделал вместе с тобой!=) Может теперь напилим контроллеров на эту секьюрность?
Спасибо за отзыв :)
Это уже не интересно - всегда можно поиграть муже готовым движком :)
Следующий этап - прокрутить другие сервисы к этому проекту.
@@EugeneSuleimanov новые сервисы это отлично, будешь видео делать?
@@mirnijalexey2765 планирую.
Топ как всегда !
Спасибо за отзыв!
Как всегда топ контент без воды спасибо! Только вопрос возник, а что там на продакшене с паролем, хоть и рест метод пост приходит разве это будет считаться безопасным? или может на фронте должен кодироваться?
Спасибо за отзыв!
https обеспечивает безопасность передачи данных.
Спасибо, супер!
Спасибо за отзыв!
Спасибо большое за качетвенный контент без "воды".
Как много реактивного программирования используеться в реальных проектах?
Спасибо за отзыв!
В моём опыте - крайне много. За последние 3 года все проекты были на «реактивщине».
@@EugeneSuleimanov Спасибо, ого не неожиданно.
@@vadympylypchenko5801 но это точно мой опыт.
Давай прикрутим кафку и ELK =) А то спрашивают много, а понимания мало)
Можно попробовать :)
Спасибо.
Спасибо за комментарий!
Прикольно
Хотелось бы поинтересоваться зачем 3 перегруженных generateToken? можно же все пихнуть в один метод? Вижу объяснение только в single responsability principle, гипотетически можно сделать развилку на втором методе если реализовывать рефреш логику
Спасибо за предоставленную информацию. У меня возник вопрос относительно класса AuthenticationManager. Я не понимаю, для чего он нужен, если в коде он нигде не используется, кроме как в качестве параметра для фильтра. Можете объяснить, зачем нужно передавать этот класс туда, если мы проверяем только токен клиента в фильтре, учитывая, что метод AuthenticationManager обращается к базе данных?
Евгений, супер, спасиьо огромное! Несколько вопросов, если позволите.
1. Сервис, где вы размещаете статьи, доступен под vpn? У меня из РФ не открываются ваши статьи.
2. По проекту. Как с наименьшими усилиями прикрутить к проекту ui или swagger?
3. Если использовать не postgres в качестве БД, а другую реляционную, не должно быть принципиальных изменений?
Спасибо за отзыв!
1. Да, под VPN доступен - ограничения провайдера
2. Написать любой клиент под этот АПИ (ангуляр или реакт).
Четко
Спасибо за отзыв!
Для того чтобы хорошо уметь тестировать авторизацию/регистрацию юзера , ее нужно написать ))) сегодня этим и займусь пожалуй )) спасибо Евгений )
Спасибо за отзыв и удачи :)
А что такое секреты (secret), которые мы используем для кодирования пароля и генерации токена, и где их брать/генерировать, чтобы они были валидные. Спасибо большое за видео!
Зависит от формата, на этом сайте есть ряд форматов:
randomkeygen.com/
Спасибо за отзыв!
А webflux и boot это разное получается ?) Или спринг секьюрити и там и там работает одинаково ?
Просил вас видео про спринг буут и спринг секьюрити в новом формате показать, видео старое переделать )
Да, spring boot может не использовать реактивщину. Это просто удобный Фреймворк для быстрого старта приложения с рядом преимуществ.
Концепция немного другая, если мы говорим про reactive, но суть та же.
Я делал по этому гайду приложение,сначала у меня не завелось, потому, что важно при использвоании lombok и mapstruct, чтобы зависимости ломбока стояли первыми
Спасибо за видео. Вопрос такой, можно в двух словах объяснить для чего здесь реактивность применена и вообще какой у нее практический смысл?
Спасибо за отзыв!
Производительность и стиль разработки.
Класс! Спасибо за видео, хорошо структурирует знания, а так же много нового и интересного подчерпнул. Есть кейс: хочу настроить securityWebFilterChain таким образом, чтобы все пути было открыты, а на один конкретный путь срабатывал фильтр. Я могу заменить publicRoutes на “/**” и где-то указать тот путь, который надо прогонять через фильтр?
Большое спасибо за отзыв!
Да, должно отработать по документации.
👍👍👍
Gradle мне кажется лучше поднимать обращаясь к объекту wrapper и в клоужер уже указать gradleVersion='8.0.1' .
Спасибо за комментарий!
Да, конечно через задачу является рекомендуемой практикой, но ручной вариант описан в документации.
docs.gradle.org/current/userguide/gradle_wrapper.html#:~:text=One%20way%20to%20upgrade%20the,in%20Adding%20the%20Gradle%20Wrapper.
@@EugeneSuleimanov забыл добавить - видео как всегда на высоте
@@jollyroger2757 спасибо :)
Неймовірно😮
Докую за відгук!
Евгений, спасибо за такой контент на русском!
Спасибо за отзыв!
Запустите курс по обучению, я полагаю будет очень востребованный от вашего авторства
По моему опыту - все курсы заканчиваются одинаково - скатывание в «г#%#нокурсы» для заработка.
Поэтому работаю только через менторинг.
На данный момент, я не нашёл способа масштабирования без существенного падения качества, к сожалению.
И спасибо за комментарий!
Большое спасибо за видео! Очень полезно! Подскажите пожалуйста, как запустить это приложение в docker-compose? Собрал бд в отдельном контейнере, все прописал, все запустилось, но не могу перейти ни по одному из эндпоинтов..
Спасибо за отзыв!
Можете уточнить по ошибкам или логам контейнеров?
@@EugeneSuleimanov В логах ничего нет, пробовал дебажить, при обращении к эндпоинтам вообще не доходит до контроллера.. При всем этом тот же код, запущенный без контейнеров, с локальной бд работает без проблем.
Postman выдает ошибку Error: connect ECONNREFUSED 127.0.0.1:8089.
Из за того, что один и тот же код работает при локальном запуске и не работает в контейнерах, напрашивается вывод, что проблема во взаимодействии с этими контейнерами..
Буду дальше копать, просто хотел уточнить, может быть такое, что к контейнеру сервиса закрыт доступ с внешних адресов? Или может быть есть особенности работы webflux, security, r2dbc, или netty в целом в контейнизированом приложении?
Аннотация @Table как-то валидирует совместимость типов с базой хотя бы в рантайме? Со Spring не работал, просто как-то странно, в том же Django и SQLAlchemy, например, оно генерирует и управляется с SQL само
Генерация SQL происходит под капотом. Но если будет несовпадение со структурой данных или типами данных - вылетит исключение.
Экспирация)
Не подобрал сходу другого слова :)
27:09 кстати, есть момент с yaml. При его использовании среда разработки не предлагает варианты во время набора ключа, при работе с property файлом такого нет. Может знаете как заставить идею так же работать с yaml?
Интересное наблюдение, попробую изучить вопрос. И спасибо за комментарий!
Подскажите плиз, почему во вложенном классе VerificationResults поля публичные, и мы к ним обращаемся без геттеров, напрямую? 56:25
Для удобства работы. Такой подход часто применяется для вложенных классов. Особенно на уровне DTO.
@@EugeneSuleimanov спасибо!
Евгений, здравствуйте! Скажите, пожалуйста, можно ли с реализацией Security, приведенной вами, использовать аннотацию @PreAuthorize("hasAnyRole('ADMIN')") для управления доступом к методам контролеров на основании роли пользователя?
Добрый день!
Да, этот подход рабочий.
@@EugeneSuleimanov Не работает с коробки(
Евгений, а вы не планируете сделать курс на юдеми часов на 20 с созданием какого-нибудь мини проекта на джаве и спринге? Я бы купил.
Все курсы планирую делать публичными, бесплатными и на ютубе. По крайней мере, на данный момент :)
@@EugeneSuleimanov хорошо, буду ждать)
подскажите, откуда взялся секрет? Сказали, что его заранее подготовили и он валидный. Что это значит? Где его взяли и где валидировали?)
Спасибо за видео. Есть вопросы:
Зачем были добавлены роли, если фактически они не используются?
ИМХО, работу с генерацией, валидацией токена, думаю, лучше не разносить в отдельные классы(solid же).
Не понял, зачем проверять токен своим велосипедом, если либа сама может это сделать?
Спасибо за отзыв!
1. По ролям - просто заготовка для расширения.
2. Здесь есть несколько вариантов. Тот же S из SOLID здесь можно трактовать по-разному. Вряд ли будет однозначный ответ.
@@EugeneSuleimanov ещё третий вопрос. Проверить токен можно одной строкой
@@EugeneSuleimanov + как раз про второй вопрос. Из-за того что работа с токеном разнесена, в нескольких классах тащиться secret из пропертей
@@maximelmanov6719 конечно можно - это учебный пример - нужно показать более детально и понятно.
@@maximelmanov6719 в проперти не вижу проблемы, если есть аргументы - было бы отлично. Могу упускать детали.
Евгений можно использовать пример кода с security без реактившины?
Спасибо за комментарий!
Нет, этот подход заточен под реактивщину.
Подскажите, пожалуйста, как сюда прикрутить Role based control с аноташками по типу @PreAuthorized, или как-то по другому?
Второй день мучаюсь(
Помогите, плиз, хоть каким-то способом сюда Role based control внедрить
Немного не понял про перехват ошибок, можете пояснить зачем такой кастомный класс? Я использую @ControllerAdvice
Если я верно понял ваш вопрос, то с ним проще работать при создании гибкого механизма обработки. Например - свое DTO + получения деталей по ошибкам из БД по ключу.
Спасибо за урок! Но у меня возник вопрос. Вот в yaml мы красиво пишем все эти секретные данные с паролями и ссылками на БД и генерации пароля для jwt, в Гит хаб пушается этот файл и тогда все те танци с конфигурациями идут на смарку, ведь файл будут видеть все кому не лень(только если репозиторий не приватный). Сам вопрос: в не учебном(комерционном) проекте yaml не пушается в гит? И еще на засипку, SECRET_KEY_INSTANCE по идее тоже должен быть в yaml, ведь класс Encoder 100% будет запушеным в гит.
Спасибо за отзыв!
Обычно, эти переменные передаются как переменные среды и подтягиваются на этапе запуска.
Общий смысл - создается локальная копия application.yml с кредами - application-local.yml, который "затирает" application.yml
application-local.yml добавляем в .gitignore, теперь он не покидает локального репозитория и нужен только для локального тестирования
Необходимые действия:
1) создать копию application.yml - application-local.yml указать в новом файле креды
2) Важно! - добавляем в .gitignore файл application-local.yml
3) в application добавляем
spring:
config:
import: optional:application-local.yml
для локального тестирования используется application-local.yml
указываем креды не боясь, что они утекут вместе с коммитом
в import: optional:application-local.yml optional - указывает что это опциональный параметр, если такого файла нет, то используется application.yml
Подскажите пж где токен взять для авторизации в Postman?
Создать самому через ендпоинт логина
Здравствуйте, что за тема у вас в IDEA?
Добрый вечер!
Dracula
@@EugeneSuleimanov Спасибо)
У меня глупый вопрос как создать POSTGRES-LOCAL? Через DG idea? Или что-то другое, я этого никогда не делал. Не понимаю как быть.
www.jetbrains.com/help/datagrip/postgresql.html
Здесь есть делателе описание.
@@EugeneSuleimanov Сделал так: удалил все, скачал заново, установил драйвер нажал test connection ([08004] The server requested SCRAM-based authentication, but no password was provided.) ввел пароль. [28P01] �����: ������������ "dkloc" �� ������ �������� ����������� (�� ������). пришло такое.
Правильно ли я понимаю, что многое вырезали в новой spring security?
Спасибо за вопрос.
Я бы сказал, что заменили.
Да, скорее так. От того и вопросы появились при
создании SecurityWebFilterChain))@@EugeneSuleimanov
У entity зря не переопредели equals и hashCode.
Если я верно вас понял, то аннотация Data включает в себя:
@ToString, @EqualsAndHashCode, @RequiredArgsConstructorи @Getter + @Setter для всех не финальных полей.
у Евгения Lombok, @Data включает переопределение методов для классов энтитей
@@erkin7138 , та же JpaBuddy не рекомендует использовать аннотацию @Data в Entity. Если схема БД чуть сложнее и в Entity присутствуют "ленивые" поля, то ломбоковское видение методов toString, equals, hashCode может привести к ухудшению производительности приложения в связи с появлением множественных запросов к БД.
Is Spring Webflux gaining popularity ?
Definitely
@@EugeneSuleimanov Thanks
+
Как всегда, спасибо за поддержку!
Чтото смотрю не спешат интегрировать hibernate reactive в спринг
Да, вы правы, не встречал такого еще.
почему не kotlin в 2023 году?
Первая любовь не ржавеет :)
Курс мне понравился. Я попробовал его реализовать в netbeans 15 (maven). При вводе регистрационных данных, postman выдает An expected CSRF token cannot be found при 403 ошибке. Не могли бы вы подсказать в чем дело ? В секюрити конфиге .csrf().disable(). Заранее благодарен.
Сложно сказать, скорее всего ошибка в коде, а не в IDE или Maven.
И спасибо за комментарий!
Спасибо за ответ, на этот раз все получилось, причина была в том , что секюрити конфиг у меня был отдельным пакетом на одном левеле с проектом.
@@user-vvvm рад, что все получилось!
При клонировании и запуске проекта получаю сразу ошибку. Тем не менее спасибо за урок.
Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1770
Caused by: org.flywaydb.core.internal.exception.FlywaySqlException at JdbcUtils.java:60
Caused by: org.postgresql.util.PSQLException at ConnectionFactoryImpl.java:844
тоже застрял на этом моменте на ~ 15 минуте :), делал ручками как в видео
из сообщений в консоли - что-то не так c авторизацией flyway, в итоге дописал user и password:
flyway:
url: jdbc:postgresql://localhost:5432/webflux_security
locations: classpath:db/migration
password: xxxxxx
user: postgres
после чего заработало и таблица в БД создалась,
пока нет времени посмотреть дальше, может там будет объяснение (выше указ.проблемы),
если нет - просьба экспертов подсказать, в чем причина и как ее решать (без дублирования как я сделал)
Автору - спасибо большое, таких тем еще не видел + понятным языком. респект.
Проверьте, что Postgres запущен если да - проверьте, что БД создана и креды корректны.
@@EugeneSuleimanov Postges был запущен, БД создана, а что такое "креды"?
как указал ранее, сработало при добавлении 2х последних строк ниже:
spring:
r2dbc:
url: r2dbc:pool:postgres://localhost:5432/webflux_security
username: postgres
password: xxxxxxx
flyway:
url: jdbc:postgresql://localhost:5432/webflux_security
locations: classpath:db/migration
password: xxxxxxx
user: postgres
@@adeskmath должно отработать и без них, перепроверю, спасибо!
Какие-то проблемы у меня со сборкой с этим flyway
contextLoads() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:142
Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1770
Caused by: org.flywaydb.core.internal.exception.FlywaySqlException at JdbcUtils.java:60
Caused by: org.postgresql.util.PSQLException at QueryExecutorImpl.java:2713
Вы можете проверить, что БД создана и username + password корректны?
@@EugeneSuleimanov проверил это подключением с идеи
@@raynur256 попробуйте подтянуть свежую версию проекта - внёс небольшую правку.
@@EugeneSuleimanov Сработало, спасибо. Стоило догадаться, но я так и не понимаю как у вас без этого получилось
@@raynur256 сам в недоумении ))
Добрый день возникли такие ошибки не знаю как исправить
org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1770
org.flywaydb.core.internal.exception.FlywaySqlException at JdbcUtils.java:60
org.postgresql.util.PSQLException at ConnectionFactoryImpl.java:693
There were failing tests. See the report at: file:///home/erin/IdeaProjects/webfluxsecurity/build/reports/tests/test/index.html
буду рад любому ответу спасибо !
Добрый день!
Подтяните свежую версию проекта - внёс небольшую правку.
@@EugeneSuleimanov Спасибо !
+
Спасибо за комментарий!
@@EugeneSuleimanov это вам благодарность!!!!!!!!!!!!