From 413d071443a4a83fa275502eaa1ebbe89e1e1dd5 Mon Sep 17 00:00:00 2001 From: IndexZero Date: Tue, 18 Feb 2025 20:34:33 +0300 Subject: [PATCH] Added new requests --- build.gradle | 3 + .../finals/config/SecurityConfig.java | 59 +++++++++++++++++++ .../finals/controller/EmployeeController.java | 32 +++++----- .../com/indexzero/finals/dto/EmployeeDTO.java | 13 ++++ .../indexzero/finals/entity/Authority.java | 5 +- .../com/indexzero/finals/entity/Employee.java | 9 ++- .../com/indexzero/finals/entity/Visit.java | 3 +- .../finals/repository/CodeRepository.java | 1 + .../finals/service/EmployeeService.java | 7 ++- .../service/impl/EmployeeServiceImpl.java | 40 +++++++------ .../service/impl/UserDetailsServiceImpl.java | 20 +++++++ .../indexzero/finals/util/EmployeeMapper.java | 19 ++++++ 12 files changed, 170 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/indexzero/finals/config/SecurityConfig.java create mode 100644 src/main/java/com/indexzero/finals/dto/EmployeeDTO.java create mode 100644 src/main/java/com/indexzero/finals/service/impl/UserDetailsServiceImpl.java create mode 100644 src/main/java/com/indexzero/finals/util/EmployeeMapper.java diff --git a/build.gradle b/build.gradle index 35848a6..1ba39a9 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,9 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-security' + testImplementation 'org.springframework.security:spring-security-test' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5' } tasks.named('test') { diff --git a/src/main/java/com/indexzero/finals/config/SecurityConfig.java b/src/main/java/com/indexzero/finals/config/SecurityConfig.java new file mode 100644 index 0000000..d8f94e3 --- /dev/null +++ b/src/main/java/com/indexzero/finals/config/SecurityConfig.java @@ -0,0 +1,59 @@ +package com.indexzero.finals.config; + +import com.indexzero.finals.service.impl.UserDetailsServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.Customizer; +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.HeadersConfigurer; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +import static org.springframework.boot.autoconfigure.security.servlet.PathRequest.toH2Console; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Autowired + private UserDetailsServiceImpl userDetailsService; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((authorize) -> authorize + .requestMatchers("/v3/api-docs/**").permitAll() + .requestMatchers("/api/employee/login").authenticated() + .requestMatchers("/api/employee/profile").authenticated() + .anyRequest().authenticated() + ) + .httpBasic(Customizer.withDefaults()).csrf(csrf -> csrf + .ignoringRequestMatchers(toH2Console()) + .disable()).headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)); + + + + + return http.build(); + } + + @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/indexzero/finals/controller/EmployeeController.java b/src/main/java/com/indexzero/finals/controller/EmployeeController.java index cb2c80f..76e2ce9 100644 --- a/src/main/java/com/indexzero/finals/controller/EmployeeController.java +++ b/src/main/java/com/indexzero/finals/controller/EmployeeController.java @@ -1,5 +1,6 @@ package com.indexzero.finals.controller; +import com.indexzero.finals.dto.EmployeeDTO; import com.indexzero.finals.entity.Code; import com.indexzero.finals.entity.Employee; import com.indexzero.finals.entity.Visit; @@ -8,39 +9,34 @@ import com.indexzero.finals.repository.EmployeeRepository; import com.indexzero.finals.repository.VisitRepository; import com.indexzero.finals.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController -@RequestMapping("/api") +@RequestMapping("/api/employee") public class EmployeeController { - @Autowired - EmployeeRepository employeeRepository; - - @Autowired - CodeRepository codeRepository; @Autowired EmployeeService employeeService; - @Autowired - VisitRepository visitRepository; - - @GetMapping("/{login}/auth") - public ResponseEntity Auth(@PathVariable String login) { - return employeeService.checkIfUserExists(login); + @PostMapping("/login") + public ResponseEntity login() { + return new ResponseEntity(HttpStatus.OK); } - @GetMapping("/{login}/info") - public ResponseEntity getInfo(@PathVariable String login) { - return employeeService.getUserInfo(login); + @PostMapping("/profile") + public ResponseEntity getInfo() { + return employeeService.getUserInfo(SecurityContextHolder.getContext().getAuthentication()); } - @PatchMapping("/{login}/open") - public ResponseEntity Open(@RequestParam Long code, @PathVariable String login) { - return employeeService.openTheDoor(login, code); + @PatchMapping("/open") + public ResponseEntity Open(@RequestParam Long code) { + return employeeService.openTheDoor(code, SecurityContextHolder.getContext().getAuthentication()); } + } diff --git a/src/main/java/com/indexzero/finals/dto/EmployeeDTO.java b/src/main/java/com/indexzero/finals/dto/EmployeeDTO.java new file mode 100644 index 0000000..fe47668 --- /dev/null +++ b/src/main/java/com/indexzero/finals/dto/EmployeeDTO.java @@ -0,0 +1,13 @@ +package com.indexzero.finals.dto; + +import lombok.Data; + +@Data +public class EmployeeDTO { + private long id; + private String login; + private String name; + private String authority; + private String position; + private String photoUrl; +} diff --git a/src/main/java/com/indexzero/finals/entity/Authority.java b/src/main/java/com/indexzero/finals/entity/Authority.java index 464456c..02c1d8f 100644 --- a/src/main/java/com/indexzero/finals/entity/Authority.java +++ b/src/main/java/com/indexzero/finals/entity/Authority.java @@ -2,11 +2,14 @@ package com.indexzero.finals.entity; import jakarta.persistence.*; import lombok.Data; +import org.springframework.security.core.GrantedAuthority; + +import java.io.Serializable; @Entity @Data @Table(name = "authority") -public class Authority { +public class Authority implements GrantedAuthority { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) diff --git a/src/main/java/com/indexzero/finals/entity/Employee.java b/src/main/java/com/indexzero/finals/entity/Employee.java index ebc8326..766fdb3 100644 --- a/src/main/java/com/indexzero/finals/entity/Employee.java +++ b/src/main/java/com/indexzero/finals/entity/Employee.java @@ -5,6 +5,9 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.security.core.userdetails.UserDetails; + +import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; import java.util.Set; @@ -14,7 +17,7 @@ import java.util.Set; @Builder @NoArgsConstructor @AllArgsConstructor -public class Employee { +public class Employee implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) @@ -41,4 +44,8 @@ public class Employee { @OneToMany(mappedBy = "id") List visits; + @Override + public String getUsername() { + return this.login; + } } diff --git a/src/main/java/com/indexzero/finals/entity/Visit.java b/src/main/java/com/indexzero/finals/entity/Visit.java index 2208f87..631b990 100644 --- a/src/main/java/com/indexzero/finals/entity/Visit.java +++ b/src/main/java/com/indexzero/finals/entity/Visit.java @@ -4,6 +4,7 @@ import jakarta.persistence.*; import lombok.Data; import org.apache.catalina.User; +import java.time.LocalDateTime; import java.util.Date; import java.util.List; @@ -16,7 +17,7 @@ public class Visit { private long id; @Column(name = "visit_time") - private Date visitTime; + private LocalDateTime visitTime; @Column(name = "type") private String type; diff --git a/src/main/java/com/indexzero/finals/repository/CodeRepository.java b/src/main/java/com/indexzero/finals/repository/CodeRepository.java index d590346..c7bc54c 100644 --- a/src/main/java/com/indexzero/finals/repository/CodeRepository.java +++ b/src/main/java/com/indexzero/finals/repository/CodeRepository.java @@ -5,4 +5,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface CodeRepository extends JpaRepository { boolean existsByValue(Long value); + Code findByValue(Long code); } diff --git a/src/main/java/com/indexzero/finals/service/EmployeeService.java b/src/main/java/com/indexzero/finals/service/EmployeeService.java index e44d507..dc45100 100644 --- a/src/main/java/com/indexzero/finals/service/EmployeeService.java +++ b/src/main/java/com/indexzero/finals/service/EmployeeService.java @@ -1,10 +1,13 @@ package com.indexzero.finals.service; +import com.indexzero.finals.dto.EmployeeDTO; import com.indexzero.finals.entity.Employee; +import org.apache.catalina.User; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; public interface EmployeeService { ResponseEntity checkIfUserExists(String login); - ResponseEntity getUserInfo(String login); - ResponseEntity openTheDoor(String login, Long code); + ResponseEntity getUserInfo(Authentication auth); + ResponseEntity openTheDoor(Long code, Authentication auth); } diff --git a/src/main/java/com/indexzero/finals/service/impl/EmployeeServiceImpl.java b/src/main/java/com/indexzero/finals/service/impl/EmployeeServiceImpl.java index bb053b5..d17f3de 100644 --- a/src/main/java/com/indexzero/finals/service/impl/EmployeeServiceImpl.java +++ b/src/main/java/com/indexzero/finals/service/impl/EmployeeServiceImpl.java @@ -1,16 +1,21 @@ package com.indexzero.finals.service.impl; +import com.indexzero.finals.dto.EmployeeDTO; import com.indexzero.finals.entity.Employee; +import com.indexzero.finals.entity.Visit; import com.indexzero.finals.repository.CodeRepository; import com.indexzero.finals.repository.EmployeeRepository; import com.indexzero.finals.service.EmployeeService; +import com.indexzero.finals.util.EmployeeMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.List; @Service public class EmployeeServiceImpl implements EmployeeService { @@ -33,29 +38,28 @@ public class EmployeeServiceImpl implements EmployeeService { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } } - public ResponseEntity getUserInfo(String login) { - try { - if (employeeRepository.existsByLogin(login)) { - return new ResponseEntity<>(employeeRepository.findByLogin(login), HttpStatus.OK); - } - else { - return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); - } - } - catch(Exception e) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - } + + @Override + public ResponseEntity getUserInfo(Authentication auth) { + return new ResponseEntity<>(EmployeeMapper.convertToDTO(employeeRepository.findByLogin(auth.getName())), HttpStatus.OK); } - public ResponseEntity openTheDoor(String login, Long code) { + + public ResponseEntity openTheDoor(Long code, Authentication auth) { try { - if(employeeRepository.existsByLogin(login)) { + if(codeRepository.findByValue(code).isActive()) { if (codeRepository.existsByValue(Long.valueOf(code))) { - Employee employee = employeeRepository.findByLogin(login); + Employee employee = employeeRepository.findByLogin(auth.getName()); + + Visit visit = new Visit(); LocalDateTime time = LocalDateTime.now(); - String formatted = time.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); - formatted = formatted.split("\\.")[0]; - // employee.setLastVisit(LocalDateTime.parse(formatted)); + visit.setVisitTime(LocalDateTime.now()); + visit.setType("smartphone"); + + List v = employee.getVisits(); + v.add(visit); + + employee.setVisits(v); employeeRepository.save(employee); return new ResponseEntity<>(HttpStatus.OK); diff --git a/src/main/java/com/indexzero/finals/service/impl/UserDetailsServiceImpl.java b/src/main/java/com/indexzero/finals/service/impl/UserDetailsServiceImpl.java new file mode 100644 index 0000000..bc4f106 --- /dev/null +++ b/src/main/java/com/indexzero/finals/service/impl/UserDetailsServiceImpl.java @@ -0,0 +1,20 @@ +package com.indexzero.finals.service.impl; + +import com.indexzero.finals.repository.EmployeeRepository; +import com.indexzero.finals.service.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +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 UserDetailsServiceImpl implements UserDetailsService { + @Autowired + private EmployeeRepository employeeRepository; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return employeeRepository.findByLogin(username); + } +} diff --git a/src/main/java/com/indexzero/finals/util/EmployeeMapper.java b/src/main/java/com/indexzero/finals/util/EmployeeMapper.java new file mode 100644 index 0000000..09471c9 --- /dev/null +++ b/src/main/java/com/indexzero/finals/util/EmployeeMapper.java @@ -0,0 +1,19 @@ +package com.indexzero.finals.util; + +import com.indexzero.finals.dto.EmployeeDTO; +import com.indexzero.finals.entity.Employee; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class EmployeeMapper { + public static EmployeeDTO convertToDTO(Employee user) { + EmployeeDTO employeeDTO = new EmployeeDTO(); + employeeDTO.setId(user.getId()); + employeeDTO.setLogin(user.getLogin()); + employeeDTO.setAuthority(user.getAuthorities().iterator().next().getAuthority()); + employeeDTO.setName(user.getName()); + employeeDTO.setPosition(user.getPosition()); + employeeDTO.setPhotoUrl(user.getPhotoUrl()); + return employeeDTO; + } +}