From 0137ba0bb23414a9bb645ac61d46e29cd0714063 Mon Sep 17 00:00:00 2001 From: truettwo Date: Thu, 20 Feb 2025 10:47:42 +0300 Subject: [PATCH] fixes+icripted passwords lol --- src/main/java/com/example/nto/App.java | 4 + .../example/nto/config/SecurityConfig.java | 72 +++++++++------- .../nto/controller/EmployeeController.java | 85 ++++++++----------- .../java/com/example/nto/entity/Employee.java | 12 ++- .../nto/repository/CodeRepository.java | 4 +- .../example/nto/service/EmployeeService.java | 2 + .../nto/service/impl/EmployeeServiceImpl.java | 29 +++++-- src/main/resources/data.sql | 24 +++--- 8 files changed, 127 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java index d4add94..b64b401 100644 --- a/src/main/java/com/example/nto/App.java +++ b/src/main/java/com/example/nto/App.java @@ -2,10 +2,14 @@ package com.example.nto; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); + System.out.println(new BCryptPasswordEncoder().encode("password000")); + + } } diff --git a/src/main/java/com/example/nto/config/SecurityConfig.java b/src/main/java/com/example/nto/config/SecurityConfig.java index 65ec483..4c62e64 100644 --- a/src/main/java/com/example/nto/config/SecurityConfig.java +++ b/src/main/java/com/example/nto/config/SecurityConfig.java @@ -1,57 +1,63 @@ package com.example.nto.config; import com.example.nto.entity.Employee; -import com.example.nto.service.EmployeeService; -import org.springframework.beans.factory.annotation.Autowired; +import com.example.nto.repository.EmployeeRepository; 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.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.crypto.password.NoOpPasswordEncoder; // Для незашифрованных паролей -import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; import java.util.Optional; @Configuration -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { - @Autowired - private EmployeeService employeeService; + private final EmployeeRepository employeeRepository; - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .csrf().disable() // Отключ CSRF - .authorizeRequests() - .antMatchers("/api/auth").permitAll() // Разрешаем доступ к /auth - .anyRequest().authenticated() // Все запросы требуют аутентификации - .and() - .httpBasic(); // Включаем базу + public SecurityConfig(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; } - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService()).passwordEncoder(NoOpPasswordEncoder.getInstance()); + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); } @Bean public UserDetailsService userDetailsService() { return username -> { - Optional employee = employeeService.findByLogin(username); - if (employee.isPresent()) { - Employee emp = employee.get(); - return org.springframework.security.core.userdetails.User.withUsername(emp.getLogin()) - .password(emp.getPassword()) - .roles(emp.getRole()) - .build(); - } else { - throw new UsernameNotFoundException("User not found with login: " + username); + Optional employee = Optional.ofNullable(employeeRepository.findByLogin(username)); + if (employee.isEmpty()) { + throw new RuntimeException("User not found"); } + + Employee emp = employee.get(); + return User.builder() + .username(emp.getLogin()) + .password(emp.getPassword()) // Пароль должен быть в BCrypt + .roles(emp.getRole().toUpperCase()) // Spring Security требует `ROLE_XXX` + .build(); }; } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeRequests() + .antMatchers("/api/auth").permitAll() + .antMatchers("/api/workers").hasRole("ADMIN") // Только админ может смотреть всех сотрудников + .antMatchers("/api/{login}/block").hasRole("ADMIN") // Только админ может блокировать + .anyRequest().authenticated() // Остальные запросы доступны всем авторизованным пользователям + .and() + .httpBasic() + .and() + .csrf().disable(); + + return http.build(); + } } \ No newline at end of file diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 7ff1e22..b43c59e 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -2,18 +2,14 @@ package com.example.nto.controller; import com.example.nto.entity.Employee; import com.example.nto.service.EmployeeService; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.Map; import java.util.Optional; @RestController -@RequestMapping("/api") // база +@RequestMapping("/api") public class EmployeeController { private final EmployeeService employeeService; @@ -22,66 +18,53 @@ public class EmployeeController { this.employeeService = employeeService; } - @GetMapping("/auth") // Проверка аутентификации - public ResponseEntity authenticate(@RequestHeader("Authorization") String authHeader) { - // Проверяем заголовок - if (authHeader == null || !authHeader.startsWith("Basic ")) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Missing or invalid Authorization header"); - } - - // Получение логина и пароля + // Аутентификация + @GetMapping("/auth") + public ResponseEntity authenticate(@RequestHeader("Authorization") String authHeader) { String[] credentials = new String(java.util.Base64.getDecoder().decode(authHeader.substring(6))).split(":"); - String login = credentials[0]; String password = credentials.length > 1 ? credentials[1] : ""; - Optional employee = employeeService.findByLogin(login); - - if (employee.isPresent() && employee.get().getPassword().equals(password)) { + if (employeeService.authenticate(login, password)) { return ResponseEntity.ok("Authenticated successfully"); } - - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid login or password"); + return ResponseEntity.status(401).body("Invalid login or password"); } - @PreAuthorize("isAuthenticated()") // Убедитесь, что пользователь аутентифицирован - @GetMapping("/{login}/info") // Получение информации о сотруднике - public ResponseEntity getInfo(@PathVariable String login) { + // Получение информации о пользователе + @PreAuthorize("isAuthenticated()") + @GetMapping("/{login}/info") + public ResponseEntity getUserInfo(@PathVariable String login) { Optional employee = employeeService.findByLogin(login); if (employee.isPresent()) { return ResponseEntity.ok(employee.get()); - } else { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Employee not found"); } + return ResponseEntity.status(404).body("User not found"); } - @PreAuthorize("isAuthenticated()") // Убедитесь, что пользователь аутентифицирован - @PatchMapping("/{login}/open") // Открыть дверь - public ResponseEntity openDoor(@PathVariable String login, @RequestBody Map payload) { - Long code = payload.get("value"); - - if (code != null) { - Optional employee = employeeService.findByLogin(login); - if (!employee.isPresent()) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid login"); - } - if (employeeService.validateCode(login, code)) { - return ResponseEntity.ok("Door opened"); - } else { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid code"); - } - } else { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid payload"); - } - } - - @PreAuthorize("hasRole('admin')") + // Получение списка всех сотрудников (только для администратора) + @PreAuthorize("hasRole('ADMIN')") @GetMapping("/workers") - public ResponseEntity> getAllWorkers() { - String currentUserName = SecurityContextHolder.getContext().getAuthentication().getName(); - // Логируем информацию о текущем пользователе - System.out.println("Current user: " + currentUserName); - List allEmployees = employeeService.findAll(); - return ResponseEntity.ok(allEmployees); + public ResponseEntity getAllWorkers() { + return ResponseEntity.ok(employeeService.findAll()); + } + + // Блокировка/разблокировка пользователя (только для администратора) + @PreAuthorize("hasRole('ADMIN')") + @PatchMapping("/{login}/block") + public ResponseEntity toggleBlockStatus(@PathVariable String login) { + employeeService.toggleBlockStatus(login); + return ResponseEntity.ok("User " + login + " status changed"); + } + + // Открытие двери, если сотрудник не заблокирован + @PreAuthorize("isAuthenticated()") + @PatchMapping("/{login}/open") + public ResponseEntity openDoor(@PathVariable String login, @RequestBody Long code) { + Optional employee = employeeService.findByLogin(login); + if (employee.isPresent() && !employee.get().isBlocked() && employeeService.validateCode(login, code)) { + return ResponseEntity.ok("Door opened"); + } + return ResponseEntity.status(403).body("Access denied"); } } \ No newline at end of file diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java index 5949da6..4f59d23 100644 --- a/src/main/java/com/example/nto/entity/Employee.java +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -1,7 +1,10 @@ + package com.example.nto.entity; import javax.persistence.*; import lombok.*; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + import java.time.LocalDateTime; @Data @@ -15,7 +18,9 @@ public class Employee { @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; + @Column(unique = true, nullable = false) private String login; + private String name; private String photo; private String position; @@ -24,11 +29,14 @@ public class Employee { private LocalDateTime lastVisit; private String password; - private String role; + @Column(nullable = false) + private String status = "works"; // Новый статус: 'works' или 'blocked' - + public boolean isBlocked() { + return "blocked".equals(status); + } } \ No newline at end of file diff --git a/src/main/java/com/example/nto/repository/CodeRepository.java b/src/main/java/com/example/nto/repository/CodeRepository.java index 0accbd9..7a881bc 100644 --- a/src/main/java/com/example/nto/repository/CodeRepository.java +++ b/src/main/java/com/example/nto/repository/CodeRepository.java @@ -11,5 +11,7 @@ public interface CodeRepository extends JpaRepository { // Метод для поиска кодов по логину @Query("SELECT c.value FROM Code c WHERE c.employee.login = :login") - List findCodesByLogin(@Param("login") String login); + static List findCodesByLogin(@Param("login") String login) { + return null; + } } \ No newline at end of file diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java index 6b37815..33a45d9 100644 --- a/src/main/java/com/example/nto/service/EmployeeService.java +++ b/src/main/java/com/example/nto/service/EmployeeService.java @@ -9,4 +9,6 @@ public interface EmployeeService { List findAll(); Optional findByLogin(String login); boolean validateCode(String login, long code); + boolean authenticate(String login, String rawPassword); + void toggleBlockStatus(String login); } \ No newline at end of file diff --git a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java index 8f463c4..10267fd 100644 --- a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java @@ -1,9 +1,10 @@ package com.example.nto.service.impl; import com.example.nto.entity.Employee; -import com.example.nto.repository.CodeRepository; // Импортируйте нужный репозиторий +import com.example.nto.repository.CodeRepository; import com.example.nto.repository.EmployeeRepository; import com.example.nto.service.EmployeeService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; @@ -13,12 +14,10 @@ import java.util.Optional; public class EmployeeServiceImpl implements EmployeeService { private final EmployeeRepository employeeRepository; - private final CodeRepository codeRepository; // Добавьте CodeRepository как зависимость + private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - // Конструктор с внедрением - public EmployeeServiceImpl(EmployeeRepository employeeRepository, CodeRepository codeRepository) { + public EmployeeServiceImpl(EmployeeRepository employeeRepository) { this.employeeRepository = employeeRepository; - this.codeRepository = codeRepository; // Инициируем код репозиторий } @Override @@ -33,8 +32,8 @@ public class EmployeeServiceImpl implements EmployeeService { @Override public boolean validateCode(String login, long code) { - // Получаем все коды для данного логина - List validCodes = codeRepository.findCodesByLogin(login); // Теперь вызывается из объекта + + List validCodes = CodeRepository.findCodesByLogin(login); // Теперь вызывается из объекта // Проверяем, если переданный код присутствует в списке boolean isValid = validCodes.contains(code); @@ -45,4 +44,20 @@ public class EmployeeServiceImpl implements EmployeeService { return isValid; } + + public boolean authenticate(String login, String rawPassword) { + Optional employee = findByLogin(login); + if (employee.isPresent() && !employee.get().isBlocked()) { + return passwordEncoder.matches(rawPassword, employee.get().getPassword()); + } + return false; + } + + public void toggleBlockStatus(String login) { + Optional employee = findByLogin(login); + employee.ifPresent(emp -> { + emp.setStatus(emp.isBlocked() ? "works" : "blocked"); + employeeRepository.save(emp); + }); + } } \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 3ccbf0c..1ef5b3f 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,26 +1,28 @@ -- Создание таблицы employee CREATE TABLE IF NOT EXISTS employee ( - id INT PRIMARY KEY, - login VARCHAR(255), - name VARCHAR(255), + id INT PRIMARY KEY AUTO_INCREMENT, + login VARCHAR(255) UNIQUE NOT NULL, + name VARCHAR(255) NOT NULL, photo VARCHAR(255), position VARCHAR(255), last_visit TIMESTAMP, - password VARCHAR(255), - role VARCHAR(50) + password VARCHAR(255) NOT NULL, -- Зашифрованный пароль + role VARCHAR(50) NOT NULL, + status VARCHAR(20) DEFAULT 'works' -- Новый статус ); -- Вставка данных в таблицу employee -INSERT INTO employee (id, login, name, photo, position, last_visit, password, role) //add +INSERT INTO employee (id, login, name, photo, position, last_visit, password, role, status) VALUES - (1, 'pivanov', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30', 'password123', 'admin'), - (2, 'ipetrov', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35', 'password456', 'user'), - (3, 'asemenov', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31', 'password789', 'user'), - (4, 'afedorov', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36', 'password000', 'user'); + (1, 'pivanov', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30', '$2a$10$LRykcZHYR0tb72biv9aqp./icK7ReK57gRFDd74kiF02ZoZqQtnEm', 'ADMIN','works'), + (2, 'ipetrov', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35', '$2a$10$rscyLIftEqucmDbSzBHZbO5DUOyICzkYXzQ4stJfbSN.Ao9R4kfQe', 'USER', 'works'), + (3, 'asemenov', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31', '$2a$10$o/g9lV7iDi.WhwztohTcfuIEhHHWUo5xlR0Vvdy2xaaI3RNwfbqzO', 'USER', 'works'), + (4, 'afedorov', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36', '$2a$10$s33LR8PuMLQJQY85.zusceJVJLUn8mwEEwAsAUzQIaiwnjeKjt.km', 'USER', 'works'); -- Создание таблицы code CREATE TABLE IF NOT EXISTS code ( - value BIGINT + value BIGINT, + employee_id INT ); -- Вставка данных в таблицу code