fixes+icripted passwords lol

This commit is contained in:
truettwo 2025-02-20 10:47:42 +03:00
parent c0eef0a2c5
commit 0137ba0bb2
8 changed files with 127 additions and 105 deletions

View File

@ -2,10 +2,14 @@ package com.example.nto;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@SpringBootApplication @SpringBootApplication
public class App { public class App {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(App.class, args); SpringApplication.run(App.class, args);
System.out.println(new BCryptPasswordEncoder().encode("password000"));
} }
} }

View File

@ -1,57 +1,63 @@
package com.example.nto.config; package com.example.nto.config;
import com.example.nto.entity.Employee; import com.example.nto.entity.Employee;
import com.example.nto.service.EmployeeService; import com.example.nto.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 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.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.userdetails.User;
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.UserDetails; 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; import java.util.Optional;
@Configuration @Configuration
@EnableWebSecurity public class SecurityConfig {
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private final EmployeeRepository employeeRepository;
private EmployeeService employeeService;
@Override public SecurityConfig(EmployeeRepository employeeRepository) {
protected void configure(HttpSecurity http) throws Exception { this.employeeRepository = employeeRepository;
http
.csrf().disable() // Отключ CSRF
.authorizeRequests()
.antMatchers("/api/auth").permitAll() // Разрешаем доступ к /auth
.anyRequest().authenticated() // Все запросы требуют аутентификации
.and()
.httpBasic(); // Включаем базу
} }
@Override @Bean
protected void configure(AuthenticationManagerBuilder auth) throws Exception { public BCryptPasswordEncoder passwordEncoder() {
auth.userDetailsService(userDetailsService()).passwordEncoder(NoOpPasswordEncoder.getInstance()); return new BCryptPasswordEncoder();
} }
@Bean @Bean
public UserDetailsService userDetailsService() { public UserDetailsService userDetailsService() {
return username -> { return username -> {
Optional<Employee> employee = employeeService.findByLogin(username); Optional<Employee> employee = Optional.ofNullable(employeeRepository.findByLogin(username));
if (employee.isPresent()) { if (employee.isEmpty()) {
Employee emp = employee.get(); throw new RuntimeException("User not found");
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);
} }
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();
}
} }

View File

@ -2,18 +2,14 @@ package com.example.nto.controller;
import com.example.nto.entity.Employee; import com.example.nto.entity.Employee;
import com.example.nto.service.EmployeeService; import com.example.nto.service.EmployeeService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
@RestController @RestController
@RequestMapping("/api") // база @RequestMapping("/api")
public class EmployeeController { public class EmployeeController {
private final EmployeeService employeeService; private final EmployeeService employeeService;
@ -22,66 +18,53 @@ public class EmployeeController {
this.employeeService = employeeService; this.employeeService = employeeService;
} }
@GetMapping("/auth") // Проверка аутентификации // Аутентификация
public ResponseEntity<?> authenticate(@RequestHeader("Authorization") String authHeader) { @GetMapping("/auth")
// Проверяем заголовок public ResponseEntity<String> authenticate(@RequestHeader("Authorization") String authHeader) {
if (authHeader == null || !authHeader.startsWith("Basic ")) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Missing or invalid Authorization header");
}
// Получение логина и пароля
String[] credentials = new String(java.util.Base64.getDecoder().decode(authHeader.substring(6))).split(":"); String[] credentials = new String(java.util.Base64.getDecoder().decode(authHeader.substring(6))).split(":");
String login = credentials[0]; String login = credentials[0];
String password = credentials.length > 1 ? credentials[1] : ""; String password = credentials.length > 1 ? credentials[1] : "";
Optional<Employee> employee = employeeService.findByLogin(login); if (employeeService.authenticate(login, password)) {
if (employee.isPresent() && employee.get().getPassword().equals(password)) {
return ResponseEntity.ok("Authenticated successfully"); return ResponseEntity.ok("Authenticated successfully");
} }
return ResponseEntity.status(401).body("Invalid login or password");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid login or password");
} }
@PreAuthorize("isAuthenticated()") // Убедитесь, что пользователь аутентифицирован // Получение информации о пользователе
@GetMapping("/{login}/info") // Получение информации о сотруднике @PreAuthorize("isAuthenticated()")
public ResponseEntity<?> getInfo(@PathVariable String login) { @GetMapping("/{login}/info")
public ResponseEntity<?> getUserInfo(@PathVariable String login) {
Optional<Employee> employee = employeeService.findByLogin(login); Optional<Employee> employee = employeeService.findByLogin(login);
if (employee.isPresent()) { if (employee.isPresent()) {
return ResponseEntity.ok(employee.get()); 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") // Открыть дверь @PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<?> openDoor(@PathVariable String login, @RequestBody Map<String, Long> payload) {
Long code = payload.get("value");
if (code != null) {
Optional<Employee> 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')")
@GetMapping("/workers") @GetMapping("/workers")
public ResponseEntity<List<Employee>> getAllWorkers() { public ResponseEntity<?> getAllWorkers() {
String currentUserName = SecurityContextHolder.getContext().getAuthentication().getName(); return ResponseEntity.ok(employeeService.findAll());
// Логируем информацию о текущем пользователе }
System.out.println("Current user: " + currentUserName);
List<Employee> allEmployees = employeeService.findAll(); // Блокировка/разблокировка пользователя (только для администратора)
return ResponseEntity.ok(allEmployees); @PreAuthorize("hasRole('ADMIN')")
@PatchMapping("/{login}/block")
public ResponseEntity<String> toggleBlockStatus(@PathVariable String login) {
employeeService.toggleBlockStatus(login);
return ResponseEntity.ok("User " + login + " status changed");
}
// Открытие двери, если сотрудник не заблокирован
@PreAuthorize("isAuthenticated()")
@PatchMapping("/{login}/open")
public ResponseEntity<String> openDoor(@PathVariable String login, @RequestBody Long code) {
Optional<Employee> 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");
} }
} }

View File

@ -1,7 +1,10 @@
package com.example.nto.entity; package com.example.nto.entity;
import javax.persistence.*; import javax.persistence.*;
import lombok.*; import lombok.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Data @Data
@ -15,7 +18,9 @@ public class Employee {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private long id; private long id;
@Column(unique = true, nullable = false)
private String login; private String login;
private String name; private String name;
private String photo; private String photo;
private String position; private String position;
@ -24,11 +29,14 @@ public class Employee {
private LocalDateTime lastVisit; private LocalDateTime lastVisit;
private String password; private String password;
private String role; private String role;
@Column(nullable = false)
private String status = "works"; // Новый статус: 'works' или 'blocked'
public boolean isBlocked() {
return "blocked".equals(status);
}
} }

View File

@ -11,5 +11,7 @@ public interface CodeRepository extends JpaRepository<Code, Long> {
// Метод для поиска кодов по логину // Метод для поиска кодов по логину
@Query("SELECT c.value FROM Code c WHERE c.employee.login = :login") @Query("SELECT c.value FROM Code c WHERE c.employee.login = :login")
List<Long> findCodesByLogin(@Param("login") String login); static List<Long> findCodesByLogin(@Param("login") String login) {
return null;
}
} }

View File

@ -9,4 +9,6 @@ public interface EmployeeService {
List<Employee> findAll(); List<Employee> findAll();
Optional<Employee> findByLogin(String login); Optional<Employee> findByLogin(String login);
boolean validateCode(String login, long code); boolean validateCode(String login, long code);
boolean authenticate(String login, String rawPassword);
void toggleBlockStatus(String login);
} }

View File

@ -1,9 +1,10 @@
package com.example.nto.service.impl; package com.example.nto.service.impl;
import com.example.nto.entity.Employee; 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.repository.EmployeeRepository;
import com.example.nto.service.EmployeeService; import com.example.nto.service.EmployeeService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@ -13,12 +14,10 @@ import java.util.Optional;
public class EmployeeServiceImpl implements EmployeeService { public class EmployeeServiceImpl implements EmployeeService {
private final EmployeeRepository employeeRepository; private final EmployeeRepository employeeRepository;
private final CodeRepository codeRepository; // Добавьте CodeRepository как зависимость private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
// Конструктор с внедрением public EmployeeServiceImpl(EmployeeRepository employeeRepository) {
public EmployeeServiceImpl(EmployeeRepository employeeRepository, CodeRepository codeRepository) {
this.employeeRepository = employeeRepository; this.employeeRepository = employeeRepository;
this.codeRepository = codeRepository; // Инициируем код репозиторий
} }
@Override @Override
@ -33,8 +32,8 @@ public class EmployeeServiceImpl implements EmployeeService {
@Override @Override
public boolean validateCode(String login, long code) { public boolean validateCode(String login, long code) {
// Получаем все коды для данного логина
List<Long> validCodes = codeRepository.findCodesByLogin(login); // Теперь вызывается из объекта List<Long> validCodes = CodeRepository.findCodesByLogin(login); // Теперь вызывается из объекта
// Проверяем, если переданный код присутствует в списке // Проверяем, если переданный код присутствует в списке
boolean isValid = validCodes.contains(code); boolean isValid = validCodes.contains(code);
@ -45,4 +44,20 @@ public class EmployeeServiceImpl implements EmployeeService {
return isValid; return isValid;
} }
public boolean authenticate(String login, String rawPassword) {
Optional<Employee> 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> employee = findByLogin(login);
employee.ifPresent(emp -> {
emp.setStatus(emp.isBlocked() ? "works" : "blocked");
employeeRepository.save(emp);
});
}
} }

View File

@ -1,26 +1,28 @@
-- Создание таблицы employee -- Создание таблицы employee
CREATE TABLE IF NOT EXISTS employee ( CREATE TABLE IF NOT EXISTS employee (
id INT PRIMARY KEY, id INT PRIMARY KEY AUTO_INCREMENT,
login VARCHAR(255), login VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255), name VARCHAR(255) NOT NULL,
photo VARCHAR(255), photo VARCHAR(255),
position VARCHAR(255), position VARCHAR(255),
last_visit TIMESTAMP, last_visit TIMESTAMP,
password VARCHAR(255), password VARCHAR(255) NOT NULL, -- Зашифрованный пароль
role VARCHAR(50) role VARCHAR(50) NOT NULL,
status VARCHAR(20) DEFAULT 'works' -- Новый статус
); );
-- Вставка данных в таблицу employee -- Вставка данных в таблицу 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 VALUES
(1, 'pivanov', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30', 'password123', 'admin'), (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', 'password456', 'user'), (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', 'password789', 'user'), (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', 'password000', 'user'); (4, 'afedorov', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36', '$2a$10$s33LR8PuMLQJQY85.zusceJVJLUn8mwEEwAsAUzQIaiwnjeKjt.km', 'USER', 'works');
-- Создание таблицы code -- Создание таблицы code
CREATE TABLE IF NOT EXISTS code ( CREATE TABLE IF NOT EXISTS code (
value BIGINT value BIGINT,
employee_id INT
); );
-- Вставка данных в таблицу code -- Вставка данных в таблицу code