diff --git a/pom.xml b/pom.xml
index 88282ee..7773001 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,19 @@
spring-boot-starter-test
test
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ com.github.javafaker
+ javafaker
+ 1.0.2
+
\ No newline at end of file
diff --git a/src/main/java/com/example/nto/config/SecurityConfig.java b/src/main/java/com/example/nto/config/SecurityConfig.java
new file mode 100644
index 0000000..6356ffa
--- /dev/null
+++ b/src/main/java/com/example/nto/config/SecurityConfig.java
@@ -0,0 +1,46 @@
+package com.example.nto.config;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+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.configurers.AbstractAuthenticationFilterConfigurer;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.core.userdetails.UserDetailsService;
+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.util.matcher.AntPathRequestMatcher;
+
+@Configuration
+@EnableWebSecurity
+@RequiredArgsConstructor
+public class SecurityConfig {
+
+ private final UserDetailsService userDetailsService;
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ return http.csrf(AbstractHttpConfigurer::disable)
+ .authorizeHttpRequests(auth -> auth.requestMatchers(new AntPathRequestMatcher("/api/login")).permitAll()
+ .requestMatchers(new AntPathRequestMatcher("/api/**")).authenticated())
+ .formLogin(AbstractAuthenticationFilterConfigurer::permitAll)
+ .getOrBuild();
+ }
+
+ @Bean
+ public AuthenticationProvider authenticationProvider() {
+ DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+ provider.setUserDetailsService(userDetailsService);
+ provider.setPasswordEncoder(passwordEncoder());
+ return provider;
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
\ 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 d776678..fa39f01 100644
--- a/src/main/java/com/example/nto/controller/EmployeeController.java
+++ b/src/main/java/com/example/nto/controller/EmployeeController.java
@@ -1,32 +1,38 @@
package com.example.nto.controller;
-import com.example.nto.entity.Code;
-import com.example.nto.entity.Employee;
+import com.example.nto.model.entity.Code;
+import com.example.nto.model.entity.Employee;
import com.example.nto.service.EmployeeService;
import lombok.RequiredArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
-import java.util.Map;
-
@RestController
-@RequestMapping("/api/{login}")
+@RequestMapping("/api")
@RequiredArgsConstructor
public class EmployeeController {
private final EmployeeService employeeService;
@GetMapping("/auth")
- public void auth(@PathVariable final String login) {
- employeeService.employeeExists(login);
+ public void auth(@RequestParam final String login, @RequestParam final String password) {
+ employeeService.auth(login, password);
}
+ @PreAuthorize("hasAuthority('User', 'Admin')")
@GetMapping("/info")
- public Employee info(@PathVariable final String login) {
+ public Employee info(@RequestParam final String login) {
return employeeService.getEmployee(login);
}
+ @PreAuthorize("hasAuthority('User', 'Admin')")
@PatchMapping("/open")
- public void open(@PathVariable final String login, @RequestBody final Code code) {
+ public void open(@RequestParam final String login, @RequestBody final Code code) {
employeeService.updateVisit(login, code.getValue());
}
+
+ @PostMapping("/add")
+ public void add(@RequestBody final Employee employee) {
+ employeeService.addEmployee(employee);
+ }
}
diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java
deleted file mode 100644
index 04f5c91..0000000
--- a/src/main/java/com/example/nto/entity/Employee.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.example.nto.entity;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import java.time.LocalDateTime;
-
-@Entity(name = "employee")
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class Employee {
-
- @Id
- private long id;
- private String login;
- private String name;
- private String photo;
- private String position;
- private LocalDateTime lastVisit;
-}
diff --git a/src/main/java/com/example/nto/model/EmployeeRoleType.java b/src/main/java/com/example/nto/model/EmployeeRoleType.java
new file mode 100644
index 0000000..55c5bf2
--- /dev/null
+++ b/src/main/java/com/example/nto/model/EmployeeRoleType.java
@@ -0,0 +1,6 @@
+package com.example.nto.model;
+
+public enum EmployeeRoleType {
+ USER,
+ ADMIN
+}
diff --git a/src/main/java/com/example/nto/entity/Code.java b/src/main/java/com/example/nto/model/entity/Code.java
similarity index 92%
rename from src/main/java/com/example/nto/entity/Code.java
rename to src/main/java/com/example/nto/model/entity/Code.java
index 5e3e92a..bb6fbac 100644
--- a/src/main/java/com/example/nto/entity/Code.java
+++ b/src/main/java/com/example/nto/model/entity/Code.java
@@ -1,4 +1,4 @@
-package com.example.nto.entity;
+package com.example.nto.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
diff --git a/src/main/java/com/example/nto/model/entity/Employee.java b/src/main/java/com/example/nto/model/entity/Employee.java
new file mode 100644
index 0000000..0812a7b
--- /dev/null
+++ b/src/main/java/com/example/nto/model/entity/Employee.java
@@ -0,0 +1,71 @@
+package com.example.nto.model.entity;
+
+import com.example.nto.model.EmployeeRoleType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+@Entity(name = "employee")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class Employee implements UserDetails {
+
+ @Id
+ private long id;
+
+ private String login;
+
+ private String password;
+
+ private String name;
+
+ private String photo;
+
+ private String position;
+
+ private LocalDateTime lastVisit;
+
+ @Enumerated(EnumType.STRING)
+ private EmployeeRoleType role;
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return List.of(new SimpleGrantedAuthority("ROLE_" + role.name()));
+ }
+
+ @Override
+ public String getUsername() {
+ return login;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/example/nto/repository/CodeRepository.java b/src/main/java/com/example/nto/repository/CodeRepository.java
index d1ed7da..be1ef7b 100644
--- a/src/main/java/com/example/nto/repository/CodeRepository.java
+++ b/src/main/java/com/example/nto/repository/CodeRepository.java
@@ -1,6 +1,6 @@
package com.example.nto.repository;
-import com.example.nto.entity.Code;
+import com.example.nto.model.entity.Code;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/com/example/nto/repository/EmployeeRepository.java b/src/main/java/com/example/nto/repository/EmployeeRepository.java
index 16440d3..404dacf 100644
--- a/src/main/java/com/example/nto/repository/EmployeeRepository.java
+++ b/src/main/java/com/example/nto/repository/EmployeeRepository.java
@@ -1,6 +1,6 @@
package com.example.nto.repository;
-import com.example.nto.entity.Employee;
+import com.example.nto.model.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java
index ae75d14..d18caaa 100644
--- a/src/main/java/com/example/nto/service/EmployeeService.java
+++ b/src/main/java/com/example/nto/service/EmployeeService.java
@@ -1,12 +1,17 @@
package com.example.nto.service;
-import com.example.nto.entity.Employee;
+import com.example.nto.model.entity.Employee;
+import org.springframework.security.core.userdetails.UserDetails;
public interface EmployeeService {
- void employeeExists(String login);
+ void auth(String login, String password);
Employee getEmployee(String login);
void updateVisit(String login, long value);
+
+ void addEmployee(Employee employee);
+
+ UserDetails loadUserByUsername(String username);
}
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 8a39171..3bb8fd3 100644
--- a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java
+++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java
@@ -1,30 +1,38 @@
package com.example.nto.service.impl;
-import com.example.nto.entity.Code;
-import com.example.nto.entity.Employee;
+import com.example.nto.model.entity.Employee;
import com.example.nto.repository.CodeRepository;
import com.example.nto.repository.EmployeeRepository;
import com.example.nto.service.EmployeeService;
import com.example.nto.service.exception.CodeNotFoundException;
import com.example.nto.service.exception.EmployeeNotFoundException;
import lombok.RequiredArgsConstructor;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
@RequiredArgsConstructor
-public class EmployeeServiceImpl implements EmployeeService {
+public class EmployeeServiceImpl implements EmployeeService, UserDetailsService {
private final EmployeeRepository employeeRepository;
+ private final PasswordEncoder passwordEncoder;
+
private final CodeRepository codeRepository;
+ private final AuthenticationManager authenticationManager;
+
@Override
- public void employeeExists(final String login) {
- if (!employeeRepository.existsByLogin(login)) {
- throw new EmployeeNotFoundException();
- }
+ public void auth(final String login, final String password) {
+ final Employee employee = getEmployee(login);
+ authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(employee.getUsername(), employee.getPassword()));
}
@Override
@@ -47,4 +55,15 @@ public class EmployeeServiceImpl implements EmployeeService {
employee.setLastVisit(LocalDateTime.now());
employeeRepository.save(employee);
}
+
+ @Override
+ public void addEmployee(Employee employee) {
+ employee.setPassword(passwordEncoder.encode(employee.getPassword()));
+ employeeRepository.save(employee);
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ return employeeRepository.findEmployeeByLogin(username);
+ }
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 1742b2b..b5dbfe5 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -28,4 +28,8 @@ spring:
operationsSorter: method
server:
- port: 8090
\ No newline at end of file
+ port: 8090
+
+token:
+ signing:
+ key: 53A73E5F1C4E0A2D3B5F2D784E6A1B423D6F247D1F6E5C3A596D635A75327855
\ No newline at end of file
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index 03720a9..8a6f29d 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -1,9 +1,9 @@
-INSERT INTO employee (id, login, name, photo, position, last_visit)
+INSERT INTO employee (id, login, name, photo, position, last_visit, role)
VALUES
-(1, 'pivanov', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30'),
-(2, 'ipetrov', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35'),
-(3, 'asemenov', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31'),
-(4, 'afedorov', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36');
+(1, 'pivanov', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30', 'USER'),
+(2, 'ipetrov', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35', 'ADMIN'),
+(3, 'asemenov', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31', 'USER'),
+(4, 'afedorov', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36', 'USER');
INSERT INTO code (value)
VALUES