Spring Security: Spring Security + REST + JWT 00:00 Введение • Видео объясняет, как использовать джи-ти-токины в спринг секьюрити для защиты приложений. • Рассматриваются примеры использования и настройки безопасности в рамках работы спринга. 01:52 Создание проекта • Создание проекта с использованием спринга, GPS, H2 базы данных, ломбака и флай эмиграйшн. • Настройка проекта и добавление зависимостей. 06:37 Настройка контроллеров и сущностей • Создание контроллеров и сущностей для работы с пользователями и ролями. • Настройка гет-мапингов и сущностей для доступа к данным. 14:29 Репозитории и интерфейсы • Создание репозиториев для работы с ролями и пользователями. • Создание интерфейсов для работы с ролями и пользователями. 15:29 Создание сущностей и репозиториев • Создание сущностей и репозиториев для работы с пользователями и ролями. • Использование аннотаций для создания сущностей и репозиториев. 19:29 Создание сервиса и методов • Создание юзер-сервиса для работы с пользователями и ролями. • Реализация методов для поиска пользователей, создания новых пользователей и преобразования пользователей к виду, понимаемому Spring Security. 26:25 Конфигурация безопасности • Создание пакета конфиг-конфигурации и настройка конфигурации безопасности. • Использование аннотаций и бинов для настройки правил безопасности, хранения паролей и использования юзер-сервиса. • Создание бина для настройки анти-кейшн провайдера и юзер-сервиса. 31:21 Безопасность в REST • В REST нет сессий, поэтому безопасность основана на токенах. • Токен содержит информацию о пользователе, его роли и подписывается секретным ключом. • Токен подшивается к каждому запросу и проверяется на бэкенде. 42:13 Токен и его структура • Токен состоит из заголовка, полезной нагрузки и подписи. • Заголовок кодируется с помощью алгоритма, полезная нагрузка кодируется с помощью другого алгоритма, а подпись формируется с использованием секретного ключа. • Токен может быть расшифрован, но не подменен. 46:13 Создание утилиты для работы с токенами • Создание класса, который будет отвечать за работу с токенами, и инжектирование значений в его поля. • Создание методов для формирования токена из пользователя, получения списка ролей из токена и проверки его на корректность. 58:05 Аутентификация пользователя и выдача токена • Создание контроллера для аутентификации и регистрации пользователей, инжектирование юзер-сервиса и других необходимых компонентов. • Создание дтошек для передачи данных о пользователе и получения токена. • Использование аутенти-менеджера для проверки логина и пароля и возврата успешного результата или ошибки аутентификации. • Создание дтошки для обработки ошибок аутентификации. 01:03:01 Получение токена • Создание конструктора для получения токена с указанием статуса, сообщения и текущего времени. • Использование конструктора для формирования токена и его возврата в качестве ответа. 01:09:42 Проверка токена • Защита токена с помощью подписи, которая не может быть изменена без знания секрета. • Если подпись изменена, то бэк получает ошибку о том, что токен недействителен. 01:12:27 Создание фильтра безопасности • Создание фильтра безопасности, который проверяет наличие токена и его корректность. • Использование утилиты для получения токена из заголовка авторизации. • Проверка корректности заголовка авторизации и получение имени пользователя из токена. 01:18:23 Работа с токенами и контекстом • В видео рассказывается о том, как с помощью утилит можно сделать гет-юзернейм и проверить пользователя. • Если время жизни токена истекло, то в контексте пользователя не будет. • Если имя пользователя найдено, то проверяется, что в контексте нет других пользователей. • Если все хорошо, то имя пользователя и список ролей из токена добавляются в контекст. 01:29:15 Регистрация и фильтрация • В видео демонстрируется регистрация пользователя и фильтрация данных в токене. • Если пароли не совпадают, то возвращается ошибка. • Если пользователь уже существует, то запрос отклоняется. • В общем, автор рекомендует спрятать обработку исключений в аутсервис и использовать глобальный перехват исключений для обработки ошибок. 01:34:15 Создание и использование токена • Обсуждение использования инкодера для шифрования пароля и его хранения в базе данных. • Создание и использование токена для аутентификации пользователя. 01:46:22 Регистрация пользователя и использование токена • Регистрация пользователя с использованием пароля и инкодера. • Создание токена для пользователя и его использование для аутентификации. 01:50:22 Итоги и обсуждение • Обсуждение принципов работы с токенами и их использования в проектах на Spring. • Ответы на вопросы зрителей и приглашение к обсуждению в комментариях.
@EnableGlobalMethodSecurity уже устарел, вместо него нужно воспользоваться аннотацией @EnableMethodSecurity, csrf тоже стал deprecated, поэтому заменим его лямбда выражение. Потом еще устарели методы authorizeRequests() и antMatchers() и and(). Итоговый код выглядит вот так : public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http .csrf(AbstractHttpConfigurer::disable) .cors(AbstractHttpConfigurer::disable) .authorizeHttpRequests(authz -> authz .requestMatchers("/secured").authenticated() .requestMatchers("/info").authenticated() .requestMatchers("/admin").hasRole("ADMIN") .anyRequest().permitAll()) .sessionManagement((sessionManagement) -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .exceptionHandling((exceptionHandling) -> exceptionHandling.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))); //addFilterBefore() return http.build();
Циклическая зависимость возникает из-за того, что UserService зависит от PasswordEncoder, а SecurityConfig зависит от UserService. Проще всего делегировать создание Bean Definition на ioc контейнер и создать отдельную конфигурацию для PasswordEncoder, вынести PasswordEncoder-bean в отдельный класс PasswordEncoderConfiguration.
Спасибо за урок! Было бы интересно рассмотреть случай с несколькими методами аутентификации, например - для пользователей через Google учетку, а для администраторов - по паролю. Ну и refreshToken для реализма)
Почему нельзя было снять сразу с Spring Boot 3? Объяснение логики это хорошо конечно, но практическое применение только на устаревших проектах, т.к. с 6 версии Security подход изменился
да все объясняют через жопу, данный автор один из немногих у кого получилось сделать по другому(хорошо). Но я бы рекомендовал начать с этого видео и подобных th-cam.com/video/p6MXb0GtXwg/w-d-xo.html
Мне помогло понять, что такое SpringSecurity, знание трех основных фактов о нем. 1. Предоставляет Аутенфикацию 2. Предоставляет Авторизацию 3. Работает с Servlet'ами
thank you for your provided content, it is very helpful and useful, but please change IDE theme to dark mode, I really struggle to understand what' going on there.
1:07:07 А зачем мы идем в базу за пользователем, если мы через authenticationManager сделали authenticate и получили Principal, внутри которого сидит то, что нам нужно?
Большое спасибо конечно за твои 2 трансляции. Но представь, я просто угробил половину дня на поиск причины почему у меня выходила ошибка 403. В итоге оказалось, что я не прописывал префикс ROLE_ в бд и из-за этого аутентификация проходила, но с надписью ошибка 403. Я пролазил точкой остановы половину классов, которые добавил в конфиг. Вот такие моменты самые бесячие. Понял только когда в точке останова увидел строчку return hasAuthority(ROLE_PREFIX + role); А ну и естественно csrf().disabled().cors().disabled() обязательно ставить.
на новых версиях спринга private final AuthenticationManager authenticationManager; - почему-то больше не является бином или еще что-то(не получается внедрить) Подскажите,что можно сделать
Здравствуйте. 2 день не пойму как сделать токен просроченным, чтобы он не работал для скажем заблокированного юзера. Можно ли как то подменить в существующем токене дату истечения срока жизни?
А в чем суть наличия и работы через Principle или UserDetails интерфейсы, если у нас есть свой класс (условный User тот же или Customer, Employee и т.д), у которого мы можем получать все необходимое для авторизации и аутентификации? PS. это вопрос из разряда "хочу понять Principle и UserDetails(Service)".
Интерфейс Principal представляет аутентифицированного пользователя. У него есть только метод getName().Principal не дает подробной информации о пользователях, таких как пароль, роли или разрешения. Интерфейс UserDetails представляет полные детали пользователя, необходимые для аутентификации и авторизации. У него есть разные методы по получению информации о пользователе ( getUsername(), getAuthorities(), getPassword() и т.п.)
Всё круто, спасибо, очень классное объяснение. Но JwtRequestFilter срабатывает на каждый запрос и из-за этого возвращается пустой 200 стоатус по всем запросам. Тут что-то надо поменять в конфигах или логику добавить в JwtRequestFilter
Объяснение хорошее. Но реализация хромает. Не показано как настраивать h2, flyway. Без которых проект не запускается или не работает как показано на видео
Я просто смотрю и в шоке сколько я не знаю и как это вообще уложить в своей бошке😢 Я пытаюсь устроиться хотя бы на трейни или джуна. Но спринг со всеми своими библиотеками вообще тяжело идёт. Все эти аннотации и под классы 🥴
Когда я делал авторизацию и аутентификацию на Python DRF удалось довольно быстро всё настроить и ещё logout сделать, но там токены были обычные не JWT и хранились в БД привязанные к пользователю и из можно было посмотреть и удалить или изменить через админку (которая кстати из коробки в Django, только настроить надо было что там будет). Я так понимаю JWT токены не обязательно сохранять в БД, т.к. в них закодированы username, roles и lifetime. Но как тогда сделать logout? Хранить список недействительных токенов или просто сохранять токены в бд? Какой подход надо лучше использовать?
Технически токен хранит приложение или браузер, если его удалить оттуда, то оно не сможет отправить запрос, потребуется авторизация, а на стороне бека просто время жизни токена истечет
А что делать если мы пользователю поменяли право или например удалили его? Получается что другой сервис, пока lifetime не истек, все равно прочитает токен и посчитает его корректным? Какое решение тут выбрать? Или JWT не про это и лучше тогда использовать сессии?
Как вариант - хранить токены (например в SQL или более быстрой памяти). Условно генеришь токен и отправляешь его как пользователю так и в таблицу. Что-то подобное есть тут watch?v=R4LwwJVjVP0 Но не совсем. Пользователь стучится к тебе по токену, ты проверяешь валиден ли токен по признаку "активен" и только тогда пускаешь. А при смене роли - принудительно сбрасываешь на "неактивен" и пусть новый токен получает через логин. Ну или может быть ставить некий флаг "изменена роль" при котором в логаут не выкинет, но доступ по токену останется только для замены токена на более актуальный. А ко всем иным эндпоинтам доступ не давать. Учитывая что таких обращений будет много, то токены наверное стоит не в SQL, а в чём-то более быстром хранить.
У меня user может заходить куда угодно и получать корректные ответы, а вот admin нет, в /secured возвращается пустой текст, хотя user-у отдавалась строка secured-data, была у кого-нибудь схожая ситуация?
@Bean public DaoAuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); daoAuthenticationProvider.setUserDetailsService(userService); return daoAuthenticationProvider; } Создание этого бина лишнее
Под конец немного путанная подача, но тема сложная и даже автор немного подвисал или слабовато подготовился. Очень не хватает: 1. тайм-лайна 2. Ссылок после видео
Слушайте, вопрос такой. С какой-то версии спринга поменяли принцип описания SecurityFilterChain. Теперь тот метод через .cors().disable() и .csrf().disable() не совсем валиден. Подскажите, как выкрутиться?
Почему когда я кладу в claims List, потом достаю его, idea не может успокоиться и пишет что метод должен возвращать не List, а прост List, если я так сделаю это начнутся другие предупреждения, к решению я так и не пришёл, кроме как игнорировать, но почему же у меня так происходит, у вас такого не было когда вы писали код?
так же светилось желтым предупреждение. как вариант можно сделать так: public List getRoles(String token) { List roles = getAllClaimsFromToken(token).get("roles", List.class); return roles.stream().map(Object::toString).toList(); } или просто повесить аннотацию @SuppressWarnings("unchecked")
Для разрешения циклической зависимости можно либо создать конструктор явно и указать в нём @Lazy, либо добавить после @RequiredArgsConstructor (onConstructor_={@Lazy})
Отличнное обьяснение работы!😊 а можно ли из principal.getname() его имя таким образом сохранять например как автора сообщения что он создает например. Если Principal будет в аигументе метода. Или лучше для таких случаев использовать @AutentificationPrincipal User user и из него получать детали?
Spring Security: Spring Security + REST + JWT
00:00 Введение
• Видео объясняет, как использовать джи-ти-токины в спринг секьюрити для защиты приложений.
• Рассматриваются примеры использования и настройки безопасности в рамках работы спринга.
01:52 Создание проекта
• Создание проекта с использованием спринга, GPS, H2 базы данных, ломбака и флай эмиграйшн.
• Настройка проекта и добавление зависимостей.
06:37 Настройка контроллеров и сущностей
• Создание контроллеров и сущностей для работы с пользователями и ролями.
• Настройка гет-мапингов и сущностей для доступа к данным.
14:29 Репозитории и интерфейсы
• Создание репозиториев для работы с ролями и пользователями.
• Создание интерфейсов для работы с ролями и пользователями.
15:29 Создание сущностей и репозиториев
• Создание сущностей и репозиториев для работы с пользователями и ролями.
• Использование аннотаций для создания сущностей и репозиториев.
19:29 Создание сервиса и методов
• Создание юзер-сервиса для работы с пользователями и ролями.
• Реализация методов для поиска пользователей, создания новых пользователей и преобразования пользователей к виду, понимаемому Spring Security.
26:25 Конфигурация безопасности
• Создание пакета конфиг-конфигурации и настройка конфигурации безопасности.
• Использование аннотаций и бинов для настройки правил безопасности, хранения паролей и использования юзер-сервиса.
• Создание бина для настройки анти-кейшн провайдера и юзер-сервиса.
31:21 Безопасность в REST
• В REST нет сессий, поэтому безопасность основана на токенах.
• Токен содержит информацию о пользователе, его роли и подписывается секретным ключом.
• Токен подшивается к каждому запросу и проверяется на бэкенде.
42:13 Токен и его структура
• Токен состоит из заголовка, полезной нагрузки и подписи.
• Заголовок кодируется с помощью алгоритма, полезная нагрузка кодируется с помощью другого алгоритма, а подпись формируется с использованием секретного ключа.
• Токен может быть расшифрован, но не подменен.
46:13 Создание утилиты для работы с токенами
• Создание класса, который будет отвечать за работу с токенами, и инжектирование значений в его поля.
• Создание методов для формирования токена из пользователя, получения списка ролей из токена и проверки его на корректность.
58:05 Аутентификация пользователя и выдача токена
• Создание контроллера для аутентификации и регистрации пользователей, инжектирование юзер-сервиса и других необходимых компонентов.
• Создание дтошек для передачи данных о пользователе и получения токена.
• Использование аутенти-менеджера для проверки логина и пароля и возврата успешного результата или ошибки аутентификации.
• Создание дтошки для обработки ошибок аутентификации.
01:03:01 Получение токена
• Создание конструктора для получения токена с указанием статуса, сообщения и текущего времени.
• Использование конструктора для формирования токена и его возврата в качестве ответа.
01:09:42 Проверка токена
• Защита токена с помощью подписи, которая не может быть изменена без знания секрета.
• Если подпись изменена, то бэк получает ошибку о том, что токен недействителен.
01:12:27 Создание фильтра безопасности
• Создание фильтра безопасности, который проверяет наличие токена и его корректность.
• Использование утилиты для получения токена из заголовка авторизации.
• Проверка корректности заголовка авторизации и получение имени пользователя из токена.
01:18:23 Работа с токенами и контекстом
• В видео рассказывается о том, как с помощью утилит можно сделать гет-юзернейм и проверить пользователя.
• Если время жизни токена истекло, то в контексте пользователя не будет.
• Если имя пользователя найдено, то проверяется, что в контексте нет других пользователей.
• Если все хорошо, то имя пользователя и список ролей из токена добавляются в контекст.
01:29:15 Регистрация и фильтрация
• В видео демонстрируется регистрация пользователя и фильтрация данных в токене.
• Если пароли не совпадают, то возвращается ошибка.
• Если пользователь уже существует, то запрос отклоняется.
• В общем, автор рекомендует спрятать обработку исключений в аутсервис и использовать глобальный перехват исключений для обработки ошибок.
01:34:15 Создание и использование токена
• Обсуждение использования инкодера для шифрования пароля и его хранения в базе данных.
• Создание и использование токена для аутентификации пользователя.
01:46:22 Регистрация пользователя и использование токена
• Регистрация пользователя с использованием пароля и инкодера.
• Создание токена для пользователя и его использование для аутентификации.
01:50:22 Итоги и обсуждение
• Обсуждение принципов работы с токенами и их использования в проектах на Spring.
• Ответы на вопросы зрителей и приглашение к обсуждению в комментариях.
Нейросети имба
что за нейросеть?
от яндекса, которая пересказывает видео@@lusterluster6403
Встроенная в браузер Яндекс
Лучший. Грамотная речь, без слов паразитов, выверенный план лекции. И даже заминка помогает проследить, а как профи ищет ошибку. Спасибо!
Как же у вас речь поставлена - разбирался сам с JWT и голова болела, а тут такой подарок! Спасибо за лекцию!
@EnableGlobalMethodSecurity уже устарел, вместо него нужно воспользоваться аннотацией @EnableMethodSecurity, csrf тоже стал deprecated, поэтому заменим его лямбда выражение. Потом еще устарели методы authorizeRequests() и antMatchers() и and(). Итоговый код выглядит вот так :
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authz -> authz
.requestMatchers("/secured").authenticated()
.requestMatchers("/info").authenticated()
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().permitAll())
.sessionManagement((sessionManagement) -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling((exceptionHandling) -> exceptionHandling.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)));
//addFilterBefore()
return http.build();
человек, ты лучший!
очень сильно прарился но по итогу сделал сам и вроде как работает а потом увидел это сообщение и такой ндаааа
Там еще приколюхи с jwt тоже помечены как @Deprecated, вместо условного getClaims() нужно теперь писать claims и тд
Грамотная речь и дикция, без лишних слов. Всё доходчиво! Очень уважаю Ваш труд. Хотелось бы по больше видео уроков от Вас.
Ссылка на исходники: github.com/FlameXander/security-jwt
Циклическая зависимость возникает из-за того, что UserService зависит от PasswordEncoder, а SecurityConfig зависит от UserService.
Проще всего делегировать создание Bean Definition на ioc контейнер и создать отдельную конфигурацию для PasswordEncoder, вынести PasswordEncoder-bean в отдельный класс PasswordEncoderConfiguration.
Спасибо тебе мил человек за подсказку
@@ГосподинИнквизитор удачи вам!
покажи пожалуйста эту реализацию на гитхабе =)
@@dmaberlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
public class PasswordEncoderConfiguration {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
Очень доступно и все понятно 👌 Было бы здорово еще видео про микросервисы в сочетании spring security и spring gateway 😊
согласен
вы лучший в аспекте объяснений, продолжайте, пожалуйста и спасибо огромное за ваш труд
Спасибо большое вам за ваши лекции, все очень доходчиво и понятно. Узнал про вас в ГБ, жаль не удалось побывать у вас на онлайн занятиях.
Прекрасное объяснение для русской аудитории! Внятно и по делу! Спасибо автору за труд👍👍👍
Спасибо Вам за видео с подробной информацией)
Спасибо огромное, четко и понятно! Таким людям памятники на вокзале ставить надо)))
Огромное спасибо! Самый актуальный мануал по spring security + jwt)
спасибо большое! очень доступно для понимания !
Лучшее объяснение по теме на русском! Большое спасибо!
Спасибо за урок!
Было бы интересно рассмотреть случай с несколькими методами аутентификации, например - для пользователей через Google учетку, а для администраторов - по паролю. Ну и refreshToken для реализма)
Топ. Вот бы видос по микросервисам
Благодарю , за видео. Ждем разбор по микросервисам.
Почему нельзя было снять сразу с Spring Boot 3? Объяснение логики это хорошо конечно, но практическое применение только на устаревших проектах, т.к. с 6 версии Security подход изменился
Благодарность 🙏 Лайк - подписка! Как я долго искал этот контент на доступном языке.
Спасибо большое!!!! Очень ждал!! ❤
Классный урок, тепеперь всё понятно.
Спасибо за видео!) Жду продолжения по спрингу😄
185 раз смотрю, так и не могу разобраться, что к чему в этом security)))
да все объясняют через жопу, данный автор один из немногих у кого получилось сделать по другому(хорошо). Но я бы рекомендовал начать с этого видео и подобных th-cam.com/video/p6MXb0GtXwg/w-d-xo.html
Мне помогло понять, что такое SpringSecurity, знание трех основных фактов о нем.
1. Предоставляет Аутенфикацию
2. Предоставляет Авторизацию
3. Работает с Servlet'ами
Большое спасибо за видео. Приятно слушать.
super-puper ждем еще видосы
Спасибо! Сделал закладочку на будущее.Мне до этого далековато. Жду продолжения по основам.
thank you for your provided content, it is very helpful and useful, but please change IDE theme to dark mode, I really struggle to understand what' going on there.
Ура! Александр, спасибо! очень долгожданная тема ))
Спасибо за данный гайд, лучший просто!
1:07:07 А зачем мы идем в базу за пользователем, если мы через authenticationManager сделали authenticate и получили Principal, внутри которого сидит то, что нам нужно?
Не совсем понятно на 1:20:25, что значит, что в контексте может лежать что-то "поверх токенов или под токенами"?
I do not understand the language well but the course is very well done thank you for sharing from french
не хотите снять видео какой-то проект типа магазина
Спасибо большое, вы лучший
Исходники чуть попозже залью на GitHub
@@anyone7783 прикрепил ссылку в описании и в комментариях
Спасибо автору за видео, очень информативно.
Автор сделайте видос по микросервисах
Большое спасибо конечно за твои 2 трансляции. Но представь, я просто угробил половину дня на поиск причины почему у меня выходила ошибка 403. В итоге оказалось, что я не прописывал префикс ROLE_ в бд и из-за этого аутентификация проходила, но с надписью ошибка 403. Я пролазил точкой остановы половину классов, которые добавил в конфиг. Вот такие моменты самые бесячие. Понял только когда в точке останова увидел строчку return hasAuthority(ROLE_PREFIX + role);
А ну и естественно csrf().disabled().cors().disabled() обязательно ставить.
Все супер! Можно еще улучшить, увеличив немного размер шрифта и всего остального.
25:40 Тут наверное следует проверить сначала, есть ли у вновь создаваемого пользователя роли, и только если их нет - присваивать ему роль юзверя.
Это лучший ментор! Гуру💪🏻🙏🏻
на новых версиях спринга private final AuthenticationManager authenticationManager; - почему-то больше не является бином или еще что-то(не получается внедрить)
Подскажите,что можно сделать
я не понимаю, что я сделал не так у меня на 1:08:30 все время выдает 401 ответ, хотя все вроде бы делал так же
Спасибо огромное!
Здравствуйте. 2 день не пойму как сделать токен просроченным, чтобы он не работал для скажем заблокированного юзера. Можно ли как то подменить в существующем токене дату истечения срока жизни?
А в чем суть наличия и работы через Principle или UserDetails интерфейсы, если у нас есть свой класс (условный User тот же или Customer, Employee и т.д), у которого мы можем получать все необходимое для авторизации и аутентификации?
PS. это вопрос из разряда "хочу понять Principle и UserDetails(Service)".
Интерфейс Principal представляет аутентифицированного пользователя. У него есть только метод getName().Principal не дает подробной информации о пользователях, таких как пароль, роли или разрешения.
Интерфейс UserDetails представляет полные детали пользователя, необходимые для аутентификации и авторизации. У него есть разные методы по получению информации о пользователе ( getUsername(), getAuthorities(), getPassword() и т.п.)
При авторизации дважды в базу лезем. AuthenticationManager под капотом сам бегает в UserService.
Спринг, ммм :) Спасибо!
1:30:06 не поняла, что меняем в токене?
Огромное спасибо)
Хорош!👍
Jwt использует javax.xml.bind.DatatypeConverter но в новых версиях java оно не используется и выдает ошибку
Может уже есть новая версия где не используется avax.xml.bind.DatatypeConverter?
Нужна зависимость javax.xml.bind:jaxb-api
Всё круто, спасибо, очень классное объяснение. Но JwtRequestFilter срабатывает на каждый запрос и из-за этого возвращается пустой 200 стоатус по всем запросам. Тут что-то надо поменять в конфигах или логику добавить в JwtRequestFilter
А в конце вызывается filterChain.doFilter(request, response)?
У кого-то возникала ошибка, что бин AuthenticationManager не регистрируется?
Решил проблему, если будете пробовать реализовывать, то класс SecurityConfig помечайте аннотацией @Configuration
@@jersonmade8043 спасибо большое! долго возился не понимал почему на все запросы 401 ловил.
после добавления @Configuration все заработало
лучший ты мне помог!!!!!!!! @@jersonmade8043
Объяснение хорошее. Но реализация хромает. Не показано как настраивать h2, flyway. Без которых проект не запускается или не работает как показано на видео
Подскажите, можно ли записаться на ваши курсы?
Если можно то где?
Спасибо автору
я не пойму тут старый спринг секьюрити? сейчас он так фильтрчейн не конфигурируется
Я просто смотрю и в шоке сколько я не знаю и как это вообще уложить в своей бошке😢 Я пытаюсь устроиться хотя бы на трейни или джуна. Но спринг со всеми своими библиотеками вообще тяжело идёт. Все эти аннотации и под классы 🥴
я думаю при регистрации мы должны редиректиться на форму входа, где мы вводим логин и пароль. это самое логичное было бы
Спасибо!🙂
А можно ещё видео как разлогиниться) а то как-то не полно вышло!)
Когда я делал авторизацию и аутентификацию на Python DRF удалось довольно быстро всё настроить и ещё logout сделать, но там токены были обычные не JWT и хранились в БД привязанные к пользователю и из можно было посмотреть и удалить или изменить через админку (которая кстати из коробки в Django, только настроить надо было что там будет). Я так понимаю JWT токены не обязательно сохранять в БД, т.к. в них закодированы username, roles и lifetime. Но как тогда сделать logout? Хранить список недействительных токенов или просто сохранять токены в бд? Какой подход надо лучше использовать?
Технически токен хранит приложение или браузер, если его удалить оттуда, то оно не сможет отправить запрос, потребуется авторизация, а на стороне бека просто время жизни токена истечет
Есть ли какая то конкретная причина использования Date для времени, или можно спокойно использовать Local[Date/Time/DateTime]?
Можно спокойно использовать LocalDateTime
А что делать если мы пользователю поменяли право или например удалили его? Получается что другой сервис, пока lifetime не истек, все равно прочитает токен и посчитает его корректным? Какое решение тут выбрать? Или JWT не про это и лучше тогда использовать сессии?
Как вариант - хранить токены (например в SQL или более быстрой памяти).
Условно генеришь токен и отправляешь его как пользователю так и в таблицу.
Что-то подобное есть тут watch?v=R4LwwJVjVP0
Но не совсем.
Пользователь стучится к тебе по токену, ты проверяешь валиден ли токен по признаку "активен" и только тогда пускаешь.
А при смене роли - принудительно сбрасываешь на "неактивен" и пусть новый токен получает через логин.
Ну или может быть ставить некий флаг "изменена роль" при котором в логаут не выкинет, но доступ по токену останется только для замены токена на более актуальный.
А ко всем иным эндпоинтам доступ не давать.
Учитывая что таких обращений будет много, то токены наверное стоит не в SQL, а в чём-то более быстром хранить.
в нормальном качестве будет позже , я так понимаю ? тема очень нужная и интересная
+ тоже жду лучше кач-во
TH-cam еще несколько часов видео будет обрабатывать и потом да, будет нормальное качество
@@FlameXander а можно ожидать что появится видео про юнит тесты? Особенно авторизация прям требует чтобы была покрыта юнит тестами
Спасибо за контент,правда мне до этого ещё далеко
То есть контроллер authitization заменяет контроллер login?
Хотелось бы теперь узнать, как сдлеать вход без postman так, чтобы токен встравивался в сылку
🤔🤔
Это достаточно просто делается на фронтенде
@@FlameXander я в фронтенде не шарю, не могли бы вы скинуть статью? Если не затруднит.
@@FlameXander я пытаюсь запустить через постман registration, но не могу понять каким должен быть путь
секрет любой или какой то особенный нужен?
У меня user может заходить куда угодно и получать корректные ответы, а вот admin нет, в /secured возвращается пустой текст, хотя user-у отдавалась строка secured-data, была у кого-нибудь схожая ситуация?
может в конфиге что-то?
Вот пример моего конфига:
```
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(request -> {
var corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOriginPatterns(List.of("*"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
corsConfiguration.setAllowedHeaders(List.of("*"));
corsConfiguration.setAllowCredentials(true);
return corsConfiguration;
}))
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/user/log").permitAll()
.requestMatchers("/user/logpost").permitAll()
.requestMatchers("/user/reg").permitAll()
.requestMatchers("/").hasAnyRole("ADMIN","USER")
.requestMatchers("/user").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
)
.httpBasic(Customizer.withDefaults())
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
```
супермегахарош
jwt:
secret:111ddd
lifetime:30m
'Cannot resolve configuration property 'jwt'
почему выходит циклическая зависимость, потому что в SecurityConfig мы инжектим
UserService userService;
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(userService);
return daoAuthenticationProvider;
}
Создание этого бина лишнее
@@TEOOOOOOOOOOOO спасибо
Под конец немного путанная подача, но тема сложная и даже автор немного подвисал или слабовато подготовился. Очень не хватает:
1. тайм-лайна
2. Ссылок после видео
Слушайте, вопрос такой. С какой-то версии спринга поменяли принцип описания SecurityFilterChain. Теперь тот метод через .cors().disable() и .csrf().disable() не совсем валиден. Подскажите, как выкрутиться?
http.cors(cors -> cors.disable()).csrf(csrf -> csrf.disable()) и т.д.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(request -> {
var corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOriginPatterns(List.of("*"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
corsConfiguration.setAllowedHeaders(List.of("*"));
corsConfiguration.setAllowCredentials(true);
return corsConfiguration;
}))
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/user/log").permitAll()
.requestMatchers("/user/logpost").permitAll()
.requestMatchers("/user/reg").permitAll()
.requestMatchers("/").hasAnyRole("ADMIN","USER")
.requestMatchers("/user").permitAll()
.requestMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
)
.httpBasic(Customizer.withDefaults())
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@@kai_9482 Спасибо большое
хтось може надіслати посилання на телеграм канал а то ця не дійсна
У меня скоро крыша полетит, до сих пор не нашёл нужного гайда как встроить токен в сылку
И помогите пожалуйста прописать контроллер logout
Очень устаревшие технологии. Давай 6-ю версию Security и JJWT 0.12+ Также интересен подход с рефреш токеном
Почему когда я кладу в claims List, потом достаю его, idea не может успокоиться и пишет что метод должен возвращать не List, а прост List, если я так сделаю это начнутся другие предупреждения, к решению я так и не пришёл, кроме как игнорировать, но почему же у меня так происходит, у вас такого не было когда вы писали код?
так же светилось желтым предупреждение. как вариант можно сделать так:
public List getRoles(String token) {
List roles = getAllClaimsFromToken(token).get("roles", List.class);
return roles.stream().map(Object::toString).toList();
}
или просто повесить аннотацию @SuppressWarnings("unchecked")
Туман в мозгу по поводу jwt начинает рассеиваться )
много что не объясняешь
Для разрешения циклической зависимости можно либо создать конструктор явно и указать в нём @Lazy, либо добавить после @RequiredArgsConstructor (onConstructor_={@Lazy})
метод контролера auth не авторизует пользователя и выдает сообщение o.s.s.c.bcrypt.BCryptPasswordEncoder : Encoded password does not look like BCrypt
Отличнное обьяснение работы!😊 а можно ли из principal.getname() его имя таким образом сохранять например как автора сообщения что он создает например. Если Principal будет в аигументе метода. Или лучше для таких случаев использовать @AutentificationPrincipal User user и из него получать детали?
Спасибо вам