From 010e862edc20ef88db23c7a01a347b31c0b7fd14 Mon Sep 17 00:00:00 2001 From: Gnazarov Date: Thu, 20 Feb 2025 12:57:53 +0300 Subject: [PATCH] Checkpoint 4. Basic Auth, get login. --- pom.xml | 8 +- .../example/nto/config/WebSecurityConfig.java | 83 ++++++++++--------- .../nto/controller/EmployeeController.java | 6 ++ .../com/example/nto/entity/Authority.java | 9 +- .../java/com/example/nto/entity/Employee.java | 52 +++++++----- .../nto/service/impl/EmployeeServiceImpl.java | 14 +++- .../service/impl/UserDetailsServiceImpl.java | 40 ++++----- src/main/resources/application.yml | 6 +- src/main/resources/data.sql | 17 +++- src/main/resources/schema.sql | 19 ++++- 10 files changed, 157 insertions(+), 97 deletions(-) diff --git a/pom.xml b/pom.xml index e400344..732d899 100644 --- a/pom.xml +++ b/pom.xml @@ -55,10 +55,10 @@ postgresql - - - - + + org.springframework.boot + spring-boot-starter-security + diff --git a/src/main/java/com/example/nto/config/WebSecurityConfig.java b/src/main/java/com/example/nto/config/WebSecurityConfig.java index 9c815f8..d626bc9 100644 --- a/src/main/java/com/example/nto/config/WebSecurityConfig.java +++ b/src/main/java/com/example/nto/config/WebSecurityConfig.java @@ -1,40 +1,43 @@ -//package com.example.nto.config; -// -//import lombok.RequiredArgsConstructor; -//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.core.userdetails.UserDetailsService; -//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -//import org.springframework.security.crypto.password.PasswordEncoder; -// -//@Configuration -//@EnableWebSecurity -//@RequiredArgsConstructor -//public class WebSecurityConfig extends WebSecurityConfigurerAdapter { -// -// private final UserDetailsService userDetailsService; -// -// @Override -// protected void configure(HttpSecurity http) throws Exception { -// http -// .csrf().disable() -// .authorizeRequests() -// .antMatchers("/api/employee/registration").hasAuthority("ROLE_ADMIN") -// .anyRequest().authenticated() -// .and() -// .httpBasic() -// .and() -// } -// -// @Override -// protected void configure(AuthenticationManagerBuilder auth) throws Exception { -// auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); -// } -// -// public PasswordEncoder passwordEncoder(){ -// return new BCryptPasswordEncoder(); -// } -//} +package com.example.nto.config; + +import lombok.RequiredArgsConstructor; +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.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + private final UserDetailsService userDetailsService; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .csrf().disable() + .authorizeRequests() + .antMatchers("/api/employee/registration").hasAuthority("ROLE_ADMIN") + .anyRequest().authenticated() + .and() + .httpBasic() + .and() + .headers().frameOptions().disable(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 245f6ad..45698b5 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -9,6 +9,7 @@ import com.example.nto.service.impl.EmployeeServiceImpl; import lombok.AllArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; @@ -92,4 +93,9 @@ public class EmployeeController { return ResponseEntity.status(HttpStatus.OK).body(service.createEmployee(dto)); } + @GetMapping("/login") + public ResponseEntity getLogin(Authentication authentication){ + return ResponseEntity.status(HttpStatus.OK).body(service.findEmployeeDTOByUsername(authentication.getName())); + } + } diff --git a/src/main/java/com/example/nto/entity/Authority.java b/src/main/java/com/example/nto/entity/Authority.java index e173046..eb4a5be 100644 --- a/src/main/java/com/example/nto/entity/Authority.java +++ b/src/main/java/com/example/nto/entity/Authority.java @@ -1,14 +1,16 @@ package com.example.nto.entity; import lombok.Data; -//import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.GrantedAuthority; import javax.persistence.*; +import java.util.List; +import java.util.Set; @Data @Entity @Table(name = "authorities") -public class Authority {//implements GrantedAuthority { +public class Authority implements GrantedAuthority { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -17,4 +19,7 @@ public class Authority {//implements GrantedAuthority { @Column(name = "authority") private String authority; +// @OneToMany(targetEntity = Employee.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL) +// private List employees; + } diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java index 65312b6..9983c71 100644 --- a/src/main/java/com/example/nto/entity/Employee.java +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -//import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetails; import javax.persistence.*; import java.util.Set; @@ -15,7 +15,7 @@ import java.util.Set; @AllArgsConstructor @Entity @Table(name="employee") -public class Employee {//implements UserDetails { +public class Employee implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @@ -38,26 +38,32 @@ public class Employee {//implements UserDetails { @Column(name="lastVisit") private String lastVisit; -// @ManyToMany(fetch = FetchType.EAGER) -// private Set authorities; + @ManyToMany(fetch = FetchType.EAGER) +// @JoinTable(name = "employee_authorities", +// joinColumns = @JoinColumn(name = "employee_id"), +// inverseJoinColumns = @JoinColumn(name = "authorities_id") +// ) + private Set authorities; +// @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) +// @JoinTable(name = "Employee_AUTHORITIES") -// @Override -// public boolean isAccountNonExpired() { -// return true; -// } -// -// @Override -// public boolean isAccountNonLocked() { -// return true; -// } -// -// @Override -// public boolean isCredentialsNonExpired() { -// return true; -// } -// -// @Override -// public boolean isEnabled() { -// return true; -// } + @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/service/impl/EmployeeServiceImpl.java b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java index d952cbf..8c68a7a 100644 --- a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java @@ -9,6 +9,7 @@ import com.example.nto.repository.EmployeeRepository; import com.example.nto.service.EmployeeService; import com.example.nto.util.EmployeeMapper; import lombok.AllArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.time.LocalDateTime; @@ -17,7 +18,10 @@ import java.util.Optional; @Service @AllArgsConstructor public class EmployeeServiceImpl implements EmployeeService { + private EmployeeRepository repository; + private final PasswordEncoder passwordEncoder; + @Override public void updateLocalTime(Employee employee) { employee.setLastVisit(LocalDateTime.now().toString()); @@ -30,6 +34,11 @@ public class EmployeeServiceImpl implements EmployeeService { return repository.findEmployeeByUsername(login).orElseThrow(() -> new EmployeeNotFoundException("Employee with username "+login+" not found")); } + public EmployeeDTO findEmployeeDTOByUsername(String login) { + + return EmployeeMapper.convertToDTO(repository.findEmployeeByUsername(login).orElseThrow(() -> new EmployeeNotFoundException("Employee with username "+login+" not found"))); + } + @Override public EmployeeDTO createEmployee(RegisterDTO dto) { @@ -41,7 +50,10 @@ public class EmployeeServiceImpl implements EmployeeService { Employee employee = new Employee(); employee.setName(dto.getName()); employee.setUsername(dto.getUsername()); - employee.setPassword(dto.getPassword()); + + // Encoding password + employee.setPassword(passwordEncoder.encode(dto.getPassword())); + employee.setPhoto(dto.getPhoto()); employee.setJobPos(dto.getJobPos()); employee.setLastVisit(LocalDateTime.now().toString()); diff --git a/src/main/java/com/example/nto/service/impl/UserDetailsServiceImpl.java b/src/main/java/com/example/nto/service/impl/UserDetailsServiceImpl.java index 7a40318..85d70e2 100644 --- a/src/main/java/com/example/nto/service/impl/UserDetailsServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/UserDetailsServiceImpl.java @@ -1,20 +1,20 @@ -//package com.example.nto.service.impl; -// -//import com.example.nto.repository.EmployeeRepository; -//import lombok.RequiredArgsConstructor; -//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 -//@RequiredArgsConstructor -//public class UserDetailsServiceImpl implements UserDetailsService { -// -// private final EmployeeRepository employeeRepository; -// -// @Override -// public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException{ -// return employeeRepository.findEmployeeByUsername(s).get(); -// } -//} +package com.example.nto.service.impl; + +import com.example.nto.repository.EmployeeRepository; +import lombok.RequiredArgsConstructor; +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 +@RequiredArgsConstructor +public class UserDetailsServiceImpl implements UserDetailsService { + + private final EmployeeRepository employeeRepository; + + @Override + public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException{ + return employeeRepository.findEmployeeByUsername(s).get(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3ce9b2c..c5e1217 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,7 +9,9 @@ spring: datasource: url: jdbc:postgresql://localhost:5432/testdb data: classpath:data.sql - schema: classpath:schema.sql + + init: + schema-locations: classpath:schema.sql username: "postgres" password: "MobileDev" @@ -28,7 +30,7 @@ spring: hibernate: #ddl-auto: none - ddl-auto: create-drop + ddl-auto: update # Показываем запросы show-sql: true diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 8f457ff..2f4de38 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -5,10 +5,11 @@ VALUES INSERT INTO employee (id, username, password, name, photo, job_pos, last_visit) VALUES -(1, 'pivanov', 'employee', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30'), -(2, 'ipetrov', 'employee', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35'), -(3, 'asemenov', 'employee', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31'), -(4, 'afedorov', 'employee', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36'); +(1, 'pivanov', '$2a$12$oSvuYhIhHJtyw3Gp542S3.WI2aupaIQ5265ItMDvnTPopcLQudx9q', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30'), +(2, 'ipetrov', '$2a$12$oSvuYhIhHJtyw3Gp542S3.WI2aupaIQ5265ItMDvnTPopcLQudx9q', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35'), +(3, 'asemenov', '$2a$12$oSvuYhIhHJtyw3Gp542S3.WI2aupaIQ5265ItMDvnTPopcLQudx9q', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31'), +(4, 'afedorov', '$2a$12$oSvuYhIhHJtyw3Gp542S3.WI2aupaIQ5265ItMDvnTPopcLQudx9q', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36'), +(5, 'gnazarov', '$2a$12$QH3S01HpdzDARg4qrZ4Qee9SkFmxmau2SiEvsSg5M17K2vBBm673O', 'Назаров Г. Н.', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Администратор', '2024-02-12T08:36'); INSERT INTO code (value) VALUES @@ -17,3 +18,11 @@ VALUES (1122334455667788990), (998877665544332211), (5566778899001122334); + +INSERT INTO employee_authorities(employee_id, authorities_id) +VALUES +(1, 1), +(2, 1), +(3, 1), +(4, 1), +(5, 2); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 083af02..0735c75 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -2,4 +2,21 @@ CREATE TABLE IF NOT EXISTS authorities( id auto_increment primary key, authority VARCHAR(255)); CREATE TABLE IF NOT EXISTS employee( -id auto_increment primary key, username VARCHAR(255), password VARCHAR(255), name VARCHAR(255), photo VARCHAR(255), job_pos VARCHAR(255), last_visit VARCHAR(255)); \ No newline at end of file +id auto_increment primary key, +username VARCHAR(255), +password VARCHAR(255), +name VARCHAR(255), +photo VARCHAR(255), +job_pos VARCHAR(255), +last_visit VARCHAR(255) +--authorities_id BIGINT NOT NULL, +--CONSTRAINT fk_employee_authorities FOREIGN KEY(authorities_id) REFERENCES authorities(id) +); + +CREATE TABLE IF NOT EXISTS employee_authorities( +employee_id BIGINT NOT NULL, +authorities_id BIGINT NOT NULL, +PRIMARY KEY(employee_id, authorities_id), +CONSTRAINT fk_employee_empauth FOREIGN KEY(employee_id) REFERENCES employee(id), +CONSTRAINT fk_authorities_empauth FOREIGN KEY(authorities_id) REFERENCES authorities(id) +); \ No newline at end of file