Вовлеченность
Средний охват
—Индекс качества MyDash
Загрузка…
Упоминания
0Активность
публикаций, — рекламных
постов в день,
последний пост
—О канале
- Регион
- Россия
- Категория
- Технологии
- Создан
- 20.09.2025
- В категории
- —
- В регионе
- —
AI-резюме канала
Описание
Канал о Java-разработке: разборы синтаксиса и механизмов языка, Spring и JPA, инструменты вроде picocli, подготовка к техническим интервью и новости экосистемы. Публикует обучающие посты с примерами кода, пояснениями и приглашения на открытые уроки. Формат полезен разработчикам,
Tone of Voice
экспертный, образовательный, наставнический
Реклама
Совет по рекламе
Подойдёт нативный обучающий пост с техническим примером и спокойным упоминанием продукта, без длинного продающего текста.
Нужно сравнить канал с рынком?
Покажем, как канал выглядит на фоне конкурентов: подписчики, охваты, ER и динамика.
- Карта категории и основных игроков
- Сравнение подписчиков, охватов и ER
- Динамика и краткие выводы
Последние публикации канала
В асинхронных или веб-сервисах на реактиве нужно быть осторожным: SecurityContext не “переходит” автоматически в новые потоки. Для этого используют SecurityContextRepository и специальные методы в WebFlux. ⚠️ Важно: не храните SecurityContext в сессии, если у вас stateless-приложение (REST API). Вместо сессии используйте JWT или OAuth 2.0. 🧠 5. Авторизация: FilterSecurityInterceptor & AccessDecisionManager FilterSecurityInterceptor запускается в конце цепочки фильтров и проверяет доступ к URL. Он запрашивает у SecurityMetadataSource список необходимых ролей для данного эндпоинта (Spring на основании @PreAuthorize, HttpSecurity конфигурации или XML). Затем передаёт дело в AccessDecisionManager (по умолчанию AffirmativeBased), который опрашивает список AccessDecisionVoter (например, RoleVoter для проверок ролей, WebExpressionVoter для SpEL). FilterSecurityInterceptor └─> SecurityMetadataSource (что нужно: ROLE_ADMIN) └─> AccessDecisionManager.vote() ├─ RoleVoter.vote() → совпадает? └─ WebExpressionVoter.vote() → SpEL-выражения? Если хотя бы один голос “grant”, AffirmativeBased отпускает запрос (по умолчанию). Можно менять стратегию на Consensus или Unanimous. 💡 Трюк: чтобы локально протестировать SecurityContext, можно в тестах использовать аннотацию @WithMockUser(roles = "ADMIN") и проверять, что нужный эндпоинт доступен. 🧠 6. Аннотации & Method Security Помимо URL-уровня, есть методная проверка: @EnableMethodSecurity // (Spring Boot 3+) вместо @EnableGlobalMethodSecurity public class SecurityConfig { ... } // Где-то в сервисе: @PreAuthorize("hasRole('ADMIN') and #id == principal.id") public void deleteUser(Long id) { ... } * 📌 @PreAuthorize / @PostAuthorize / @Secured / @RolesAllowed — все используют тот же механизм Voter’ов, но проверяют уже на методах сервиса. * 💡 Совет: включайте методную безопасность только там, где действительно нужна тонкая грануляция. 🧠 7. Хранение паролей & PasswordEncoder С Java 17+ используйте PasswordEncoder с алгоритмами Argon2 или BCrypt: @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } ⚠️ Никогда не храните пароли в открытом виде и не используйте MD5/SHA-1 — они считаются небезопасными. 🧠 8. Stateless vs Stateful * Stateful (Сессии): Spring создаёт HTTP-сессию, а SecurityContextPersistenceFilter хранит контекст в сессии. Удобно для монолитов с классическим web-приложением. * Stateless (JWT/OAuth2): убираем SessionCreationPolicy.STATELESS, используем BearerTokenAuthenticationFilter, аутентификация и авторизация проверяются по JWT в каждом запросе. 💡 Современный стек (Spring Boot 3+): 1. Настраиваем SecurityFilterChain с oauth2ResourceServer().jwt(). 2. Подключаем spring-boot-starter-oauth2-resource-server. 3. Указываем issuer-uri или jwk-set-uri в application.yml. spring: security: oauth2: resourceserver: jwt: issuer-uri: https://keycloak.example.com/realms/myrealm 🧠 9. Подпись запросов & CSRF * По умолчанию CSRF включён для “форменных” запросов (POST, PUT, DELETE). Для stateless-API его обычно отключают: http.csrf().disable(); * Если используете формы, не забудьте добавить в шаблон: <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> ⚠️ Внимание: не отключайте CSRF, если ваше приложение использует сессии и cookie на фронтенде! 💡 Совет по отладке: включите логирование фильтров: logging.level.org.springframework.security=DEBUG Тогда в логах вы увидите, как проходит запрос через каждый фильтр и где происходит отказ. 👉 @BookJava
🤖 ИИ помогает писать код, искать ошибки и создавать тесты. Но скорость не имеет смысла, если вместе с ней растёт количество ошибок, а разработчик перестаёт понимать, что именно сгенерировала модель. На открытом уроке разберём, где ИИ действительно ускоряет разработку, а где требует особенно внимательной проверки. Покажем применение ИИ для написания и анализа кода, поиска ошибок, рефакторинга и создания тестов. Отдельно разберём, как выбирать модели под конкретные задачи. В результате вы поймёте, какие инструменты можно встроить в повседневную разработку, и научитесь критически оценивать сгенерированный код. 📱19 ноября в 20:00 МСК. Открытый урок проходит в преддверии старта курса «Python-разработчик. Продвинутый уровень». Принять участие: https://vk.cc/d3Pswe Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
📌 Spring Security: основная архитектура 🧠 1. SecurityFilterChain & FilterChainProxy Spring Security строит всё вокруг цепочки фильтров (FilterChainProxy). При запросе к приложению запрос проходит через набор фильтров, каждый из которых отвечает за свой кусок логики: * ⚙️ ChannelProcessingFilter – перенаправление на HTTPS, если нужно. * ⚙️ SecurityContextPersistenceFilter – загружает/сохраняет SecurityContext (где хранится Authentication). * ⚙️ UsernamePasswordAuthenticationFilter – обрабатывает форму логина (если вы используете formLogin). * ⚙️ BasicAuthenticationFilter – поддерживает HTTP Basic (для REST). * ⚙️ BearerTokenAuthenticationFilter (Spring Boot 3+) – для JWT/OAuth2 Bearer-токенов. * ⚙️ ExceptionTranslationFilter – перехватывает AccessDeniedException и AuthenticationException, перенаправляет на страницу логина или возвращает 401. * ⚙️ FilterSecurityInterceptor – проверяет, есть ли у аутентифицированного пользователя разрешение (ROLE_*) для доступа к ресурсу. Каждый фильтр решает конкретную задачу, и порядок важен: если, например, фильтр авторизации (FilterSecurityInterceptor) стоит раньше, чем фильтр аутентификации, вы получите неожиданный отказ. 💡 Современный подход (Spring Boot 3+): @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated() ) .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .oauth2ResourceServer(oauth2 -> oauth2.jwt()); // JWT из OIDC/JWK return http.build(); } Таким образом вы сами управляете порядком фильтров и включаете только нужные. 🧠 2. AuthenticationManager & ProviderManager Когда UsernamePasswordAuthenticationFilter (или другой аутентификатор) получает учётные данные, он создает UsernamePasswordAuthenticationToken с неверифицированными (unauthenticated) флагом. Затем передаёт этот токен в AuthenticationManager: UsernamePasswordAuthenticationFilter → AuthenticationManager.authenticate() AuthenticationManager по умолчанию — это ProviderManager, который хранит список AuthenticationProvider (например, DaoAuthenticationProvider для UserDetailsService или JwtAuthenticationProvider для токенов). Каждый Provider пытается аутентифицировать токен, и если успешно, возвращает уже аутентифицированный Authentication с authorities. 📌 Совет: если нужно добавить кастомную проверку (например, MFA), реализуйте свой AuthenticationProvider и зарегистрируйте его перед DaoAuthenticationProvider. 🧠 3. UserDetailsService & UserDetails DaoAuthenticationProvider опирается на UserDetailsService (или ReactiveUserDetailsService в WebFlux), чтобы получить UserDetails (имя, пароль, роли, статус аккаунта). В Java 17+ можно пользоваться Map.of(...) или List.of(...), но в реальных проектах лучше хранить в БД через JPA/Hibernate. @Service public class CustomUserDetailsService implements UserDetailsService { private final UserRepository repo; @Override public UserDetails loadUserByUsername(String username) { UserEntity user = repo.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); return User.withUsername(user.getUsername()) .password(user.getPassword()) .authorities(user.getRoles().toArray(new String[0])) .accountLocked(!user.isAccountNonLocked()) .build(); } } 🧠 4. SecurityContext & SecurityContextHolder После успешной аутентификации фильтр устанавливает SecurityContext в SecurityContextHolder. По умолчанию используется стратегия MODE_THREADLOCAL, т.е. контекст привязан к текущему потоку. SecurityContextHolder.getContext().setAuthentication(authenticatedToken); 👉 @BookJava
🧠 Чем Spring Native Image отличается от обычного Spring-приложения? 📌 Обычный Spring: * Запускается на JVM, динамически загружает классы, использует рефлексию. * Медленный старт (секунды), выше потребление памяти. * Подходит для сложной логики с динамическим поведением (настройки, рефлексия, прокси). 📌 Spring Native Image (GraalVM): * Компиляция в нативный бинарник. * ⚡️ Мгновенный старт (миллисекунды), низкое потребление памяти. * Отсутствие динамики: ограничения в рефлексии, прокси и динамической загрузке. 💡 Когда что использовать? * Native Image — идеален для микросервисов и Serverless-приложений. * Обычный JVM Spring — когда важна максимальная гибкость и динамика. ⚠️ Помни, что Native Image требует больше усилий по настройке и ограничений на библиотеки. 👉 @BookJava
🤯 Java-хардкор: найди неочевидную ошибку! Сегодня задачка со звездочкой. На первый взгляд, код абсолютно рабочий и логичный. Мы создаем класс-наследник, переопределяем метод и вызываем его. Что выведет этот код при запуске? public class Main { static class Parent { public Parent() { init(); } void init() { System.out.println("Инициализация родителя"); } } static class Child extends Parent { private String name = "Java"; @Override void init() { System.out.println("Длина имени: " + name.length()); } } public static void main(String[] args) { new Child(); } } Варианты ответа: 1. Длина имени: 4 2. Инициализация родителя 3. Ошибка компиляции 4. NullPointerException во время выполнения 👇 Пишите, как думаете, и почему! Чур не запускать в IDE! А правильный ответ и объяснение я спрятал в первом комменте: 👉 @BookJava

Бот для модерации комментариев в MAX
Автоматически удаляет мат, спам, повторы и ссылки. Три режима защиты для чатов и каналов.

Бот для розыгрышей
Создавай розыгрыши прямо в MAX. Бот соберёт участников и выберет победителя случайно.

Рекомендуйте MyDash и получайте до 30% с платежей клиентов
Делитесь короткой партнёрской ссылкой или промокодом. Получайте комиссию с оплат тарифов и API MyDash

Анализ подписчиков
Бот для анализа подписок в Макс: показывает, откуда приходят подписчики, кто отписался и какие источники трафика работают лучше.

Новости MyDash
Канал сервиса MyDash в MAX

Чат админов MAX
Комьюнити владельцев каналов в MAX. Общение, опыт, аналитика и развитие каналов.

Бот для модерации комментариев в MAX
Автоматически удаляет мат, спам, повторы и ссылки. Три режима защиты для чатов и каналов.

Бот для розыгрышей
Создавай розыгрыши прямо в MAX. Бот соберёт участников и выберет победителя случайно.

Рекомендуйте MyDash и получайте до 30% с платежей клиентов
Делитесь короткой партнёрской ссылкой или промокодом. Получайте комиссию с оплат тарифов и API MyDash

Анализ подписчиков
Бот для анализа подписок в Макс: показывает, откуда приходят подписчики, кто отписался и какие источники трафика работают лучше.
