Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
2.6 Настройка Конфигурации Безопасности
Настроим SecurityConfig для использования пользовательской реализации UserDetailsService.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

private final CustomUserDetailsService customUserDetailsService;

public SecurityConfig(CustomUserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin()
.and()
.logout().permitAll();

return http.build();
}

@Bean
public AuthenticationManager authManager(HttpSecurity http, PasswordEncoder passwordEncoder)
throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder)
.and()
.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}


3. Тестирование

Теперь, когда настройка завершена:
Вы можете зарегистрировать новых пользователей, хэшировать их пароли с помощью BCryptPasswordEncoder и сохранять их в базу данных.
При попытке входа Spring Security будет извлекать пользователя из базы данных через CustomUserDetailsService.


#Java #Training #Spring #Security #Security_BD
Что выведет код?

class Parent1312 {
String name = "Parent";

void printName() {
System.out.println("Name: " + name);
}
}

class Child1312 extends Parent1312 {
String name = "Child";

@Override
void printName() {
System.out.println("Name: " + name);
}
}

public class Task131224_1 {
public static void main(String[] args) {
Parent1312 obj1 = new Child1312();
Child1312 obj2 = new Child1312();

System.out.println("Direct access:");
System.out.println("obj1.name: " + obj1.name);
System.out.println("obj2.name: " + obj2.name);

System.out.println("Method call:");
obj1.printName();
obj2.printName();
}
}


#Tasks
Вечер пятницы?🧐

https://t.me/Java_for_beginner_dev

#Mems
И еще немного про команды в JVM

1. Основные специальные символы

1.1. Символ * (звёздочка)
Используется для подстановки любого количества символов.
Применяется для работы с несколькими файлами.

javac src/com/example/*.java
Этот пример компилирует все файлы .java в указанной директории.


1.2. Символ ?
Подставляет любой один символ.
javac src/com/example/Fi?e.java
Компилирует файлы, чьи имена начинаются с Fi, заканчиваются на e и содержат один символ между ними (например, File.java, Fike.java).


1.3. Символы > и >>
>: перенаправляет вывод в файл, заменяя его содержимое.
>>: перенаправляет вывод в файл, добавляя данные в конец.

java -Xlog:gc > gc.log
Записывает логи сборщика мусора в файл gc.log, перезаписывая его содержимое.


java -Xlog:gc >> gc.log
Добавляет новые логи в конец файла gc.log.


1.4. Символ <
Перенаправляет ввод из файла.
java com.example.MyClass < input.txt
Передаёт содержимое файла input.txt как стандартный ввод для программы.


1.5. Символы | и &&
|: перенаправляет вывод одной команды на вход другой.
&&: выполняет следующую команду только если предыдущая завершилась успешно.

java com.example.MyClass | grep "Error"
Передаёт вывод программы в команду grep, которая фильтрует строки, содержащие Error.


javac MyClass.java && java MyClass
Компилирует MyClass.java и, если компиляция прошла успешно, запускает программу.


1.6. Символ &
Запускает процесс в фоновом режиме.
java com.example.MyClass &
Запускает программу в фоновом режиме, позволяя продолжать вводить команды.


1.7. Кавычки (", ', `)

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

Двойные кавычки ("): сохраняют пробелы, но позволяют интерполяцию переменных.
java -Dpath="C:\My Folder"


Одинарные кавычки ('): игнорируют интерполяцию переменных и спецсимволов.
java -Dpath='C:\My Folder'


Обратные кавычки (`): выполняют команду и подставляют её вывод.
java -Dtime=`date`


1.8. Символы []
Указывают диапазоны символов для подстановки.
javac src/[a-c]*.java
Компилирует все файлы, начинающиеся с букв a, b или c.


2. Пример комбинирования специальных символов

javac src/com/example/*.java && java -cp src com.example.Main > output.log


Этот пример:
Компилирует все файлы .java в указанной директории.
Если компиляция успешна, запускает класс Main.
Записывает вывод программы в файл output.log.


3. Особенности в разных ОС


Windows (CMD):

Некоторые символы требуют экранирования с помощью ^:
java -Dpath="C:\My^ Folder"


В PowerShell используется обратный апостроф (`) для экранирования:
java -Dpath="C:\My` Folder"


Linux и MacOS (Bash, Zsh):
Используются стандартные символы, такие как \ для экранирования.
java -Dpath="C:\My\ Folder"


4. Полезные советы

Если необходимо передать символы буквально (например, *, ?, или $), экранируйте их с помощью \:
java -Dspecial=\* com.example.Main


Используйте кавычки для обработки путей с пробелами:
javac -cp "lib/some library.jar" MyClass.java


#Java #Training #Medium #JVM_Commands
Настройка ролей и прав доступа в Spring Security

1. Основные концепции


Authentication (аутентификация): процесс проверки подлинности пользователя, т.е. кто он такой.
Authorization (авторизация): процесс проверки прав пользователя, т.е. что он может делать.
Principal: представляет текущего аутентифицированного пользователя.
GrantedAuthority: представляет разрешение или роль, назначенную пользователю.
Role: определенная категория, которая группирует определенные разрешения.


2. Архитектура и основные компоненты

SecurityContext и SecurityContextHolder: SecurityContext хранит данные о текущей аутентификации, включая Principal и GrantedAuthority. SecurityContextHolder — это контейнер, который обеспечивает доступ к текущему SecurityContext.
AuthenticationManager: основной интерфейс для выполнения аутентификации. Он принимает объект Authentication и возвращает аутентифицированный объект или выбрасывает исключение.
AccessDecisionManager: принимает решение о предоставлении или отклонении доступа к защищенному ресурсу на основе предоставленных прав.
FilterSecurityInterceptor: фильтр, который проверяет доступ к ресурсам на основе настроек безопасности.


3. Настройка ролей и прав доступа

Spring Security поддерживает настройку через Java-код (Java Config) и XML.

3.1 Подключение Spring Security
Добавьте зависимости в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>


3.2 Создание конфигурационного класса
Конфигурация Spring Security осуществляется с помощью аннотации @EnableWebSecurity и наследования от класса WebSecurityConfigurerAdapter.

Пример базовой конфигурации:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // Только для ADMIN
.antMatchers("/user/**").hasRole("USER") // Только для USER
.antMatchers("/public/**").permitAll() // Доступ для всех
.anyRequest().authenticated() // Все остальные запросы требуют аутентификации
.and()
.formLogin() // Включить форму логина
.and()
.logout().permitAll(); // Разрешить logout для всех
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("adminPass")).roles("ADMIN")
.and()
.withUser("user").password(passwordEncoder().encode("userPass")).roles("USER");
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}


4. Роли и права: тонкая настройка

Роли (ROLE_*) — это абстракция для группировки прав. Spring Security требует, чтобы роли начинались с префикса ROLE_.


4.1 Настройка прав доступа через аннотации
Spring Security поддерживает аннотации для определения прав доступа на уровне методов.

Включение поддержки аннотаций:

В классе конфигурации добавьте @EnableGlobalMethodSecurity:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// Конфигурация как ранее
}


#Java #Training #Spring #Security #Security_Roles
Использование аннотаций в методах:
@Service
public class MyService {

@PreAuthorize("hasRole('ADMIN')")
public void adminOnlyMethod() {
// Только для ADMIN
}

@PreAuthorize("hasAuthority('PERMISSION_VIEW')")
public void specificPermissionMethod() {
// Проверка конкретного разрешения
}

@PostAuthorize("returnObject.owner == authentication.name")
public MyEntity getEntity() {
// Проверка после выполнения метода
}
}


4.2 Определение прав доступа (Authorities)
Вместо простого использования ролей можно настроить более тонкие права:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("adminPass")).authorities("ROLE_ADMIN", "PERMISSION_READ", "PERMISSION_WRITE")
.and()
.withUser("user").password(passwordEncoder().encode("userPass")).authorities("ROLE_USER", "PERMISSION_READ");
}


5. Настройка пользовательской аутентификации и хранения данных

В реальных приложениях данные о пользователях и ролях хранятся в базе данных.

5.1 Создание модели пользователя
@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String username;
private String password;
private boolean enabled;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles;

// Геттеры и сеттеры
}


5.2 Создание модели роли
@Entity
public class Role {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@ManyToMany(mappedBy = "roles")
private Set<User> users;

// Геттеры и сеттеры
}


5.3 Создание пользовательского UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {

@Autowired
private UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));

return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
mapRolesToAuthorities(user.getRoles())
);
}

private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles) {
return roles.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}


5.4 Использование кастомного сервиса в конфигурации
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}


6. Защита REST API

Если вы разрабатываете REST API, можно отключить CSRF и использовать статeless-сессию:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/user/**").hasRole("USER")
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic(); // Для простоты базовая аутентификация
}


#Java #Training #Spring #Security #Security_Roles
Всем доброго субботнего утра!☀️

Как у Вас прошла неделя? Готовитесь к Новому году?🎄

А я для Вас на завтра готовлю то, что не успел реализовать в прошлое воскресение - CI/CD. 🔄
Все подробности завтра.


Всем хороших выходных!💪
This media is not supported in your browser
VIEW IN TELEGRAM
Всем доброго воскресения! 🖐

Сегодня в 16:00 я вновь жду всех Вас на встречу!

Темы сегодняшней встречи:
🔹 зачем таким как мы удаленный сервер и как его настроить для минимально приемлемой работы
🔹 что такое CI/CD и при чем тут Jenkins
🔹 вспомним о существовании Docker, потыкаем его в разные команды
🔹 создадим минимально рабочий проект на Spring и настроим его непрерывную интеграцию и непрерывное развертывание в контейнер
🔹 просто пообщаемся в хорошей компании IT-шников


Жду конечно же всех🫵
(но придут как всегда единицы😡)
Изучаем CI/CD. Метод для контейнеризации приложения в Docker через Jenkins. Встреча от 15.12.2024

Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE

Крайне благодарен всем кто пришел, за участие!💪

На сегодняшней встрече мы на примере, разобрали:
— что такое CI/CD и для чего он нужен.
— как поставить Java, Maven, Docker на удаленный сервер.
— как поставить и настроить для работы Jenkins.
— как создать простейшее веб-приложение и задеплоить его на сервер в Docker контейнер, через CI/CD и Jenkins


Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!

Ссылка на GitHub - https://github.com/Oleborn/CICDReserch

Всем хорошего настроения! 🫡✌️
JWT (JSON Web Token)

JWT (JSON Web Token) — это компактный и безопасный стандарт для передачи информации между сторонами в виде JSON-объекта. Он часто используется для аутентификации и передачи данных в веб-приложениях. JWT токены обладают рядом преимуществ, таких как легкость использования, самодостаточность (вся необходимая информация содержится внутри токена) и поддержка подписей для проверки подлинности.

1. Что такое JWT?

JWT представляет собой строку, состоящую из трех частей, разделенных точками (.):
xxxxx.yyyyy.zzzzz


Эти части соответствуют:
Header (заголовок) — метаинформация о токене.
Payload (полезная нагрузка) — данные, которые содержатся в токене.
Signature (подпись) — защита токена от подделки.


2. Структура JWT

2.1 Header
Заголовок содержит информацию о типе токена и алгоритме подписи.
{
"alg": "HS256",
"typ": "JWT"
}


alg — алгоритм подписи (например, HMAC-SHA256, RS256 и др.).
typ — тип токена (обычно "JWT").
Заголовок кодируется в формате Base64Url.


2.2 Payload
Полезная нагрузка содержит данные, которые передаются в токене. Эти данные называются "claims" (утверждения).

Они делятся на три типа:

Registered claims (зарегистрированные утверждения):
iss (issuer) — кто выдал токен.
sub (subject) — пользователь или субъект токена.
aud (audience) — для кого предназначен токен.
exp (expiration time) — время истечения токена (UNIX-время).
nbf (not before) — токен не должен использоваться до указанного времени.
iat (issued at) — время выдачи токена.
jti (JWT ID) — уникальный идентификатор токена.


Public claims (публичные утверждения): настраиваемые пользователем данные, такие как role, username и т.д.

Private claims (приватные утверждения): данные, специфичные для приложения, которые не входят в публичный стандарт.

{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"exp": 1701234567
}
Payload также кодируется в формате Base64Url.


2.3 Signature
Подпись обеспечивает целостность токена. Она создается путем использования:

Закодированных в Base64Url Header и Payload.
Секретного ключа.
Алгоритма подписи.


Пример создания подписи (при использовании алгоритма HMAC-SHA256):
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
Результат (подпись) добавляется в конец токена.


3. Виды шифрования и алгоритмы

JWT может быть подписан или зашифрован:

3.1 Подписанные JWT
Подписанные токены защищены от изменения, но их содержимое можно прочитать. Используемые алгоритмы:

HMAC (симметричное шифрование):
Пример: HS256 (HMAC-SHA256).
Использует один общий секретный ключ для создания и проверки подписи.
Подходит для приложений с одним центром проверки.


RSA (асимметричное шифрование):

Пример: RS256 (RSA-SHA256).
Использует пару ключей: приватный для подписания и публичный для проверки.
Применяется в системах, где проверку подписи выполняют разные сервисы.


ECDSA (эллиптическая криптография):
Пример: ES256.
Более производительный, чем RSA, но с аналогичным подходом к подписи.


3.2 Зашифрованные JWT
Иногда требуется скрыть содержимое токена. Для этого используется JSON Web Encryption (JWE). Зашифрованные токены обеспечивают конфиденциальность данных.

Основные алгоритмы шифрования:
AES (например, A256GCM).
RSA (например, RSA-OAEP).
Шифрование выполняется с использованием публичного ключа, а расшифровка — с помощью приватного.


4. Как формируется JWT?

Создается Header.
Создается Payload с данными.
Заголовок и полезная нагрузка кодируются в формате Base64Url.
Создается Signature, используя заголовок, полезную нагрузку и секретный ключ.
Все части объединяются в строку через точки.


Пример токена:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImV4cCI6MTcwMTIzNDU2N30
.
sX5yQNjQp17l-lF6fBt6CXyP0NItBTppS-ANkSQ6jCk


#Java #Training #Spring #Security #JWT
5. Что необходимо для расшифровки и проверки?

5.1 Для подписи на основе HMAC:
Алгоритм (например, HS256).
Секретный ключ (shared secret).


5.2 Для подписи на основе RSA:

Алгоритм (например, RS256).
Публичный ключ (для проверки подписи).
Приватный ключ (для создания подписи, если вы являетесь сервером).


5.3 Для шифрования:

Алгоритм (например, AES256 или RSA-OAEP).
Публичный ключ (для расшифровки).


6. Преимущества JWT
Самодостаточность: Вся необходимая информация содержится в токене.
Безопасность: Подпись обеспечивает защиту от подделки.
Простота использования: Легко передается между клиентом и сервером.
Масштабируемость: Подходит для распределенных систем (например, микросервисов).


7. Уязвимости и меры безопасности
Использование слабых секретных ключей: Используйте сложные и длинные ключи.
Отсутствие проверки срока действия (exp): Убедитесь, что токен истекает через разумный период.
Применение неподходящих алгоритмов: Используйте надежные алгоритмы (например, RS256, HS256).
Утечка приватного ключа: Приватные ключи должны быть строго защищены.
XSS-атаки: Храните JWT в HttpOnly cookies, а не в localStorage.


8. Пример реализации на Java
Пример генерации и проверки JWT с использованием библиотеки jjwt (Java JWT):

Зависимость в pom.xml:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>


Генерация токена:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;

public class JwtExample {

private static final String SECRET_KEY = "your-secret-key";

public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 час
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
}


Проверка токена:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.Claims;

public class JwtExample {

private static final String SECRET_KEY = "your-secret-key";

public static Claims validateToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}


#Java #Training #Spring #Security #JWT
Что выведет код?

class Parent1612 {
private String message = "Parent";

public String getMessage() {
return message;
}
}

class Child1612 extends Parent1612 {
private String message = "Child";

@Override
public String getMessage() {
return message;
}
}

public class Task161224_1 {
public static void main(String[] args) {
Parent1612 obj = new Child1612 ();
System.out.println(obj.getMessage());
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
22%
Parent
67%
Child
11%
Ошибка компиляции
0%
null
И ведь правда...🤪😂

https://t.me/Java_for_beginner_dev

#Mems
Внедрение JWT-аутентификации в Spring Security

JWT (JSON Web Token) аутентификация — это популярный подход к обеспечению безопасности веб-приложений, особенно в REST API. Она позволяет передавать информацию о пользователе в токене и исключает необходимость поддерживать сессии на сервере.

1. Общий процесс JWT-аутентификации

Аутентификация пользователя: Клиент отправляет логин и пароль на сервер.
Генерация токена: После успешной аутентификации сервер создает JWT токен и возвращает его клиенту.
Доступ к защищенным ресурсам: Клиент отправляет токен в заголовке Authorization (Bearer <token>), чтобы получить доступ к ресурсам.
Проверка токена: Сервер проверяет токен при каждом запросе и предоставляет доступ только аутентифицированным пользователям.


2. Необходимые зависимости

Добавьте в pom.xml зависимости:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>


3. Шаги реализации JWT-аутентификации

3.1 Создание конфигурационного класса Spring Security
Создаем класс SecurityConfig для настройки Spring Security:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

private final JwtAuthenticationFilter jwtAuthenticationFilter;

public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/auth/login", "/auth/register").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
}


#Java #Training #Spring #Security #JWT
3.2 Создание модели пользователя
Создаем сущности User и Role для хранения пользователей и ролей в базе данных.
import javax.persistence.*;
import java.util.Set;

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String username;
private String password;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles;

// Getters and Setters
}


@Entity
public class Role {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

// Getters and Setters
}


3.3 Создание сервиса для загрузки пользователя
Создаем сервис, который будет находить пользователя в базе данных и предоставлять его данные Spring Security.
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {

private final UserRepository userRepository;

public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));

return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.authorities(user.getRoles().stream().map(Role::getName).toArray(String[]::new))
.build();
}
}


3.4 Создание утилиты для работы с JWT
Создаем класс JwtUtils для генерации и проверки токенов.
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class JwtUtils {

private final String jwtSecret = "your-secret-key";
private final long jwtExpirationMs = 86400000; // 24 часа

public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS256, jwtSecret)
.compact();
}

public String extractUsername(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}

public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
}


#Java #Training #Spring #Security #JWT
3.5 Создание фильтра для проверки JWT
Фильтр проверяет JWT токен в каждом запросе.
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

private final JwtUtils jwtUtils;
private final CustomUserDetailsService userDetailsService;

public JwtAuthenticationFilter(JwtUtils jwtUtils, CustomUserDetailsService userDetailsService) {
this.jwtUtils = jwtUtils;
this.userDetailsService = userDetailsService;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String jwt = authHeader.substring(7);
if (jwtUtils.validateToken(jwt)) {
String username = jwtUtils.extractUsername(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}


3.6 Контроллер для аутентификации
Создаем контроллер для входа и регистрации пользователей.
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
public class AuthController {

private final AuthenticationManager authenticationManager;
private final JwtUtils jwtUtils;

public AuthController(AuthenticationManager authenticationManager, JwtUtils jwtUtils) {
this.authenticationManager = authenticationManager;
this.jwtUtils = jwtUtils;
}

@PostMapping("/login")
public String login(@RequestBody AuthRequest authRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
);
SecurityContextHolder.getContext().setAuthentication(authentication);
return jwtUtils.generateToken(authRequest.getUsername());
}
}


#Java #Training #Spring #Security #JWT
Обработка исключений в Spring Security

Обработка исключений в Spring Security — это важная часть настройки безопасности, позволяющая управлять реакцией приложения на различные виды ошибок безопасности, такие как неудачная аутентификация, попытка доступа без разрешений или некорректные данные токена.

1. Виды исключений в Spring Security

1.1 Исключения аутентификации
Эти исключения возникают, когда пользователь пытается пройти аутентификацию, но предоставленные данные неверны:
BadCredentialsException — неверный логин или пароль.
UsernameNotFoundException — пользователь не найден.
AccountExpiredException — учетная запись пользователя истекла.
DisabledException — учетная запись отключена.
LockedException — учетная запись заблокирована.
CredentialsExpiredException — срок действия учетных данных истек.


1.2 Исключения авторизации
Эти исключения связаны с попытками доступа к ресурсам без соответствующих прав:
AccessDeniedException — у пользователя недостаточно прав для доступа.
InsufficientAuthenticationException — аутентификация отсутствует или недостаточна.


1.3 Исключения токенов (в случае использования JWT)
JwtException — ошибки валидации JWT токена.
ExpiredJwtException — токен истек.
SignatureException — подпись токена неверна.


2. Как Spring Security обрабатывает исключения?

Spring Security предоставляет встроенные обработчики для исключений:
AuthenticationEntryPoint — используется для обработки ошибок аутентификации. Например, если пользователь не аутентифицирован, возвращается HTTP-статус 401 (Unauthorized).
AccessDeniedHandler — обрабатывает ошибки авторизации (HTTP-статус 403, Forbidden).


Эти компоненты можно настроить или переопределить для обеспечения пользовательской логики.

3. Настройка обработки исключений в Spring Security

3.1 Обработка ошибок аутентификации
Создаем собственный AuthenticationEntryPoint:
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\": \"Unauthorized\", \"message\": \"" + authException.getMessage() + "\"}");
}
}
Этот обработчик возвращает 401 Unauthorized с описанием ошибки в формате JSON.


3.2 Обработка ошибок авторизации
Создаем собственный AccessDeniedHandler:
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("{\"error\": \"Forbidden\", \"message\": \"" + accessDeniedException.getMessage() + "\"}");
}
}
Этот обработчик возвращает 403 Forbidden с описанием причины отказа.


#Java #Training #Spring #Security #Security_Exceptions
3.3 Подключение обработчиков в конфигурации Spring Security
Подключаем наши обработчики в конфигурационном классе:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

private final CustomAuthenticationEntryPoint authenticationEntryPoint;
private final CustomAccessDeniedHandler accessDeniedHandler;

public SecurityConfig(CustomAuthenticationEntryPoint authenticationEntryPoint,
CustomAccessDeniedHandler accessDeniedHandler) {
this.authenticationEntryPoint = authenticationEntryPoint;
this.accessDeniedHandler = accessDeniedHandler;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);

return http.build();
}
}


4. Обработка исключений для JWT токенов

При использовании JWT токенов можно добавить проверку токена в собственном фильтре, а также обрабатывать связанные исключения.

Пример обработки ошибок JWT
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
String errorMessage = "Unauthorized access";

Throwable cause = authException.getCause();
if (cause instanceof ExpiredJwtException) {
errorMessage = "JWT token expired";
} else if (cause instanceof SignatureException) {
errorMessage = "JWT signature invalid";
}

response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\": \"" + errorMessage + "\"}");
}
}
Подключите JwtAuthenticationEntryPoint вместо стандартного обработчика ошибок аутентификации.


5. Дополнительная обработка исключений

Spring Security позволяет также настроить:
Обработчики неудачной аутентификации: Используйте AuthenticationFailureHandler.
Обработчики успешной аутентификации: Используйте AuthenticationSuccessHandler.


Пример настройки AuthenticationFailureHandler:
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\": \"Authentication failed\", \"message\": \"" + exception.getMessage() + "\"}");
}
}


Добавьте его в цепочку фильтров:
http.formLogin()
.failureHandler(customAuthenticationFailureHandler);


#Java #Training #Spring #Security #Security_Exceptions
6. Глобальная обработка исключений

Для обработки всех исключений в приложении (не только Spring Security), можно использовать аннотацию
@ControllerAdvice:
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(AccessDeniedException.class)
public void handleAccessDeniedException(AccessDeniedException ex, HttpServletResponse response) throws IOException {
response.setStatus(HttpStatus.FORBIDDEN.value());
response.getWriter().write("{\"error\": \"Access Denied\", \"message\": \"" + ex.getMessage() + "\"}");
}

@ExceptionHandler(AuthenticationException.class)
public void handleAuthenticationException(AuthenticationException ex, HttpServletResponse response) throws IOException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write("{\"error\": \"Authentication Failed\", \"message\": \"" + ex.getMessage() + "\"}");
}
}


7. Тестирование обработки исключений

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

Пример теста с использованием MockMvc:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
public class SecurityExceptionTest {

@Autowired
private MockMvc mockMvc;

@Test
void accessDeniedShouldReturn403() throws Exception {
mockMvc.perform(get("/protected-resource"))
.andExpect(status().isForbidden());
}
}


#Java #Training #Spring #Security #Security_Exceptions