From 293be1d46e3e34709d74ac64f89bcd04b5a907db Mon Sep 17 00:00:00 2001 From: Andrii Solianyk Date: Sat, 31 May 2025 12:02:15 +0200 Subject: [PATCH 1/4] =?UTF-8?q?Autoryzacja=20pocz=C4=85tkowo=20zaimplement?= =?UTF-8?q?owana?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 26 ++++++ .../config/AppConfig.java | 15 ++++ .../config/SecurityConfig.java | 39 +++++++++ .../controller/AuthController.java | 77 ++++++++++++++++++ .../controller/VariablesController.java | 7 -- .../dto/AuthRequestDTO.java | 10 +++ .../dto/AuthResponseDTO.java | 12 +++ .../artisanconnectbackend/dto/ClientDTO.java | 2 +- .../dto/ClientRegistrationDTO.java | 16 ++++ .../entities/Client.java | 15 ++-- .../entities/GlobalVariables.java | 16 ---- .../artisanconnectbackend/entities/Role.java | 19 +++++ .../repository/ClientRepository.java | 2 +- .../repository/RolesRepository.java | 10 +++ .../security/JwtRequestFilter.java | 67 ++++++++++++++++ .../security/JwtUtil.java | 80 +++++++++++++++++++ .../service/ClientService.java | 42 +++++++++- src/main/resources/application.properties | 4 + src/main/resources/sql/data.sql | 17 ++-- 19 files changed, 437 insertions(+), 39 deletions(-) create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/config/AppConfig.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthRequestDTO.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthResponseDTO.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientRegistrationDTO.java delete mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/entities/GlobalVariables.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/entities/Role.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java diff --git a/pom.xml b/pom.xml index d6ef542..ee2a1cb 100644 --- a/pom.xml +++ b/pom.xml @@ -78,6 +78,32 @@ spring-boot-starter-webflux + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-test + test + diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/config/AppConfig.java b/src/main/java/_11/asktpk/artisanconnectbackend/config/AppConfig.java new file mode 100644 index 0000000..9636a39 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/config/AppConfig.java @@ -0,0 +1,15 @@ +package _11.asktpk.artisanconnectbackend.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class AppConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} \ No newline at end of file diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java b/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java new file mode 100644 index 0000000..34e57d6 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java @@ -0,0 +1,39 @@ +package _11.asktpk.artisanconnectbackend.config; + +import _11.asktpk.artisanconnectbackend.security.JwtRequestFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +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.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + private final JwtRequestFilter jwtRequestFilter; + + public SecurityConfig(JwtRequestFilter jwtRequestFilter) { + this.jwtRequestFilter = jwtRequestFilter; + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .cors(cors -> cors.configure(http)) + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/api/v1/auth/**").permitAll() + .requestMatchers("/api/v1/admin/**").hasRole("ADMIN") + .anyRequest().authenticated()) + .sessionManagement(session -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + + http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } +} \ No newline at end of file diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java new file mode 100644 index 0000000..5f6d98d --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java @@ -0,0 +1,77 @@ +package _11.asktpk.artisanconnectbackend.controller; + +import _11.asktpk.artisanconnectbackend.dto.*; +import _11.asktpk.artisanconnectbackend.entities.Client; +import _11.asktpk.artisanconnectbackend.security.JwtUtil; +import _11.asktpk.artisanconnectbackend.service.ClientService; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/auth") +public class AuthController { + + private final ClientService clientService; + private final JwtUtil jwtUtil; + + public AuthController(ClientService clientService, JwtUtil jwtUtil) { + this.clientService = clientService; + this.jwtUtil = jwtUtil; + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody AuthRequestDTO authRequestDTO) { + if (clientService.checkClientCredentials(authRequestDTO)) { + Client client = clientService.getClientByEmail(authRequestDTO.getEmail()); + Long userId = client.getId(); + String userRole = client.getRole().getRole(); + + String token = jwtUtil.generateToken(client.getEmail(), userRole, userId); + + return ResponseEntity.status(HttpStatus.OK) + .body(new AuthResponseDTO(userId, userRole, token)); + } else { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); + } + } + + @PostMapping("/register") + public ResponseEntity register(@RequestBody ClientRegistrationDTO clientDTO) { + if (clientService.getClientByEmail(clientDTO.getEmail()) != null) { + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } + + ClientDTO savedClient = clientService.registerClient(clientDTO); + + String token = jwtUtil.generateToken( + savedClient.getEmail(), + savedClient.getRole().getRole(), + savedClient.getId() + ); + + return ResponseEntity.status(HttpStatus.CREATED) + .body(new AuthResponseDTO( + savedClient.getId(), + savedClient.getRole().getRole(), + token + )); + } + + @PostMapping("/logout") + public ResponseEntity logout(HttpServletRequest request) { + String authHeader = request.getHeader("Authorization"); + + if (authHeader != null && authHeader.startsWith("Bearer ")) { + String token = authHeader.substring(7); + jwtUtil.blacklistToken(token); + return ResponseEntity.ok(new RequestResponseDTO("Successfully logged out")); + } + + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Invalid token")); + } +} \ No newline at end of file diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/VariablesController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/VariablesController.java index 009aeb4..e9767ba 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/controller/VariablesController.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/VariablesController.java @@ -13,7 +13,6 @@ import java.util.Map; @RestController @RequestMapping("/api/v1/vars") public class VariablesController { - @GetMapping("/categories") public List getAllVariables() { List categoriesDTOList = new ArrayList<>(); @@ -31,10 +30,4 @@ public class VariablesController { public List getAllStatuses() { return List.of(Enums.Status.values()); } - - @GetMapping("/roles") - public List getAllRoles() { - return List.of(Enums.Role.values()); - } - } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthRequestDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthRequestDTO.java new file mode 100644 index 0000000..3c37189 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthRequestDTO.java @@ -0,0 +1,10 @@ +package _11.asktpk.artisanconnectbackend.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class AuthRequestDTO { + private String email; + private String password; +} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthResponseDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthResponseDTO.java new file mode 100644 index 0000000..5c76d39 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/AuthResponseDTO.java @@ -0,0 +1,12 @@ +package _11.asktpk.artisanconnectbackend.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter @AllArgsConstructor +public class AuthResponseDTO { + private Long user_id; + private String user_role; + private String token; +} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java index 09fde80..4be1595 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java @@ -6,7 +6,7 @@ import lombok.Setter; import jakarta.validation.constraints.Email; -import _11.asktpk.artisanconnectbackend.utils.Enums.Role; +import _11.asktpk.artisanconnectbackend.entities.Role; @Getter @Setter public class ClientDTO { diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientRegistrationDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientRegistrationDTO.java new file mode 100644 index 0000000..4d4cd07 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientRegistrationDTO.java @@ -0,0 +1,16 @@ +package _11.asktpk.artisanconnectbackend.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class ClientRegistrationDTO { + @Email + @NotBlank + private String email; + private String firstName; + private String lastName; + private String password; +} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/entities/Client.java b/src/main/java/_11/asktpk/artisanconnectbackend/entities/Client.java index 0a25d3d..c6ca7c0 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/entities/Client.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/entities/Client.java @@ -1,11 +1,11 @@ package _11.asktpk.artisanconnectbackend.entities; -import _11.asktpk.artisanconnectbackend.utils.Enums.Role; - import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; +import org.hibernate.annotations.CreationTimestamp; +import java.util.Date; import java.util.List; @Entity @@ -24,14 +24,15 @@ public class Client { private String lastName; - private String image; // Optional field + private String image; - @Enumerated(EnumType.STRING) + @ManyToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "role_id", referencedColumnName = "id") private Role role; -// @OneToMany(mappedBy = "client", cascade = CascadeType.ALL) -// private List notices; - @OneToMany(mappedBy = "client", cascade = CascadeType.ALL) private List orders; + + @CreationTimestamp + private Date createdAt; } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/entities/GlobalVariables.java b/src/main/java/_11/asktpk/artisanconnectbackend/entities/GlobalVariables.java deleted file mode 100644 index cb50f6f..0000000 --- a/src/main/java/_11/asktpk/artisanconnectbackend/entities/GlobalVariables.java +++ /dev/null @@ -1,16 +0,0 @@ -package _11.asktpk.artisanconnectbackend.entities; - -import jakarta.persistence.*; - -@Entity -@Table(name = "global_variables") -public class GlobalVariables { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String name; - private String value; - - // Getters, setters, and constructors -} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/entities/Role.java b/src/main/java/_11/asktpk/artisanconnectbackend/entities/Role.java new file mode 100644 index 0000000..ec2d8a8 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/entities/Role.java @@ -0,0 +1,19 @@ +package _11.asktpk.artisanconnectbackend.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "roles") +@Getter +@Setter +public class Role { + @Id + private Long id; + @Column(name="rolename") + private String role; +} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/repository/ClientRepository.java b/src/main/java/_11/asktpk/artisanconnectbackend/repository/ClientRepository.java index d4d07b7..eccd51f 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/repository/ClientRepository.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/repository/ClientRepository.java @@ -1,8 +1,8 @@ package _11.asktpk.artisanconnectbackend.repository; import _11.asktpk.artisanconnectbackend.entities.Client; - import org.springframework.data.jpa.repository.JpaRepository; public interface ClientRepository extends JpaRepository { + Client findByEmail(String email); } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java b/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java new file mode 100644 index 0000000..d766026 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java @@ -0,0 +1,10 @@ +package _11.asktpk.artisanconnectbackend.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import _11.asktpk.artisanconnectbackend.entities.Role; + +@Repository +public interface RolesRepository extends JpaRepository { + Role findRoleById(Long id); +} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java new file mode 100644 index 0000000..7700ee2 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java @@ -0,0 +1,67 @@ +package _11.asktpk.artisanconnectbackend.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Collections; + +@Component +public class JwtRequestFilter extends OncePerRequestFilter { + + private final JwtUtil jwtUtil; + + public JwtRequestFilter(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain chain) + throws ServletException, IOException { + + final String authorizationHeader = request.getHeader("Authorization"); + + String email = null; + String jwt = null; + + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + jwt = authorizationHeader.substring(7); + + if (jwtUtil.isBlacklisted(jwt)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + try { + email = jwtUtil.extractEmail(jwt); + } catch (Exception e) { + logger.error(e.getMessage()); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + } + + if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) { + String role = jwtUtil.extractRole(jwt); + + UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( + email, null, Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role))); + + authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authToken); + } + +// logger.info("Token of user " + jwtUtil.extractEmail(jwt) + (jwtUtil.isTokenExpired(jwt) ? " is expired" : " is not expired")); + + chain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java new file mode 100644 index 0000000..4ac4895 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java @@ -0,0 +1,80 @@ +package _11.asktpk.artisanconnectbackend.security; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +@Component +public class JwtUtil { + + @Value("${jwt.secret:defaultSecretKeyNeedsToBeAtLeast32BytesLong}") + private String secret; + + @Value("${jwt.expiration}") + private long expiration; + + // sterowanie tokenami wygasnietymi + private final Set blacklistedTokens = ConcurrentHashMap.newKeySet(); + + public void blacklistToken(String token) { + blacklistedTokens.add(token); + } + + public boolean isBlacklisted(String token) { + return blacklistedTokens.contains(token); + } + + + private SecretKey getSigningKey() { + return Keys.hmacShaKeyFor(secret.getBytes()); + } + + public String generateToken(String email, String role, Long userId) { + Map claims = new HashMap<>(); + claims.put("role", role); + claims.put("userId", userId); + return createToken(claims, email); + } + + private String createToken(Map claims, String subject) { + return Jwts.builder() + .setClaims(claims) + .setSubject(subject) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(getSigningKey(), SignatureAlgorithm.HS256) + .compact(); + } + + public String extractEmail(String token) { + return extractClaim(token, Claims::getSubject); + } + + public String extractRole(String token) { + return extractAllClaims(token).get("role", String.class); + } + + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + private Claims extractAllClaims(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } +} \ No newline at end of file diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java b/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java index 2394015..115480a 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java @@ -1,9 +1,13 @@ package _11.asktpk.artisanconnectbackend.service; +import _11.asktpk.artisanconnectbackend.dto.AuthRequestDTO; import _11.asktpk.artisanconnectbackend.dto.ClientDTO; +import _11.asktpk.artisanconnectbackend.dto.ClientRegistrationDTO; import _11.asktpk.artisanconnectbackend.entities.Client; import _11.asktpk.artisanconnectbackend.repository.ClientRepository; +import _11.asktpk.artisanconnectbackend.repository.RolesRepository; import jakarta.persistence.EntityNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; @@ -11,9 +15,13 @@ import java.util.List; @Service public class ClientService { private final ClientRepository clientRepository; + private final PasswordEncoder passwordEncoder; + private final RolesRepository rolesRepository; - public ClientService(ClientRepository clientRepository) { + public ClientService(ClientRepository clientRepository, PasswordEncoder passwordEncoder, RolesRepository rolesRepository) { this.clientRepository = clientRepository; + this.passwordEncoder = passwordEncoder; + this.rolesRepository = rolesRepository; } private ClientDTO toDto(Client client) { @@ -42,6 +50,16 @@ public class ClientService { return client; } + private Client fromDto(ClientRegistrationDTO dto) { + Client client = new Client(); + + client.setFirstName(dto.getFirstName()); + client.setLastName(dto.getLastName()); + client.setEmail(dto.getEmail()); + client.setPassword(dto.getPassword()); + return client; + } + public List getAllClients() { List clients = clientRepository.findAll(); return clients.stream().map(this::toDto).toList(); @@ -75,4 +93,26 @@ public class ClientService { public void deleteClient(Long id) { clientRepository.deleteById(id); } + + // И замените метод checkClientCredentials на: + public boolean checkClientCredentials(AuthRequestDTO dto) { + Client cl = clientRepository.findByEmail(dto.getEmail()); + if (cl == null) { + return false; + } + + return passwordEncoder.matches(dto.getPassword(), cl.getPassword()); + } + + // При создании нового пользователя не забудьте шифровать пароль: + public ClientDTO registerClient(ClientRegistrationDTO clientDTO) { + Client client = fromDto(clientDTO); + client.setRole(rolesRepository.findRoleById(1L)); + client.setPassword(passwordEncoder.encode(client.getPassword())); + return toDto(clientRepository.save(client)); + } + + public Client getClientByEmail(String email) { + return clientRepository.findByEmail(email); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ca1826a..4f7ea0c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -23,3 +23,7 @@ tpay.clientSecret = 44898642be53381cdcc47f3e44bf5a15e592f5d270fc3a6cf6fb81a8b8eb tpay.authUrl = https://openapi.sandbox.tpay.com/oauth/auth tpay.transactionUrl = https://openapi.sandbox.tpay.com/transactions +#jwt settings +jwt.secret=DIXLsOs3FKmCAQwISd0SKsHMXJrPl3IKIRkVlkOvYW7kEcdUTbxh8zFe1B3eZWkY +jwt.expiration=300000 + diff --git a/src/main/resources/sql/data.sql b/src/main/resources/sql/data.sql index 3a9c65e..d9c2989 100644 --- a/src/main/resources/sql/data.sql +++ b/src/main/resources/sql/data.sql @@ -1,10 +1,15 @@ -INSERT INTO clients (email, first_name, image, last_name, password, role) +INSERT INTO roles (id, rolename) VALUES - ('dignissim.tempor.arcu@aol.ca', 'Diana', 'null', 'Harrison', 'password', 'USER'), - ('john.doe@example.com', 'John', 'null', 'Doe', 'password123', 'ADMIN'), - ('jane.smith@example.com', 'Jane', 'null', 'Smith', 'securepass', 'USER'), - ('michael.brown@example.com', 'Michael', 'null', 'Brown', 'mypassword', 'USER'), - ('emily.jones@example.com', 'Emily', 'null', 'Jones', 'passw0rd', 'USER'); + (1, 'USER'), + (2, 'ADMIN'); + +INSERT INTO clients (email, first_name, last_name, password, role_id) +VALUES + ('dignissim.tempor.arcu@aol.ca', 'Diana', 'Harrison', 'password', 1), + ('john.doe@example.com', 'John', 'Doe', 'password123', 2), + ('jane.smith@example.com', 'Jane', 'Smith', 'securepass', 1), + ('michael.brown@example.com', 'Michael', 'Brown', 'mypassword', 1), + ('emily.jones@example.com', 'Emily', 'Jones', 'passw0rd', 1); INSERT INTO notice (title, description, client_id, price, category, status, publish_date) VALUES From ffbd8d220c74e9eed7f3eef1d48cbcf54ef4b7e4 Mon Sep 17 00:00:00 2001 From: Andrii Solianyk Date: Mon, 2 Jun 2025 13:46:09 +0200 Subject: [PATCH 2/4] =?UTF-8?q?du=C5=BCo=20lepsza=20autoryzacja=20teraz,?= =?UTF-8?q?=20du=C5=BCo=20lepsza.=20Tokeny=20wygasaj=C4=85,=20mo=C5=BCna?= =?UTF-8?q?=20mie=C4=87=20tylko=20jeden=20aktywny=20token=20per=20user?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/SecurityConfig.java | 1 - .../controller/AuthController.java | 5 ++++ .../security/JwtRequestFilter.java | 6 ++++- .../security/JwtUtil.java | 27 +++++++++++++++---- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java b/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java index 34e57d6..bf88946 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/config/SecurityConfig.java @@ -27,7 +27,6 @@ public class SecurityConfig { .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/v1/auth/**").permitAll() - .requestMatchers("/api/v1/admin/**").hasRole("ADMIN") .anyRequest().authenticated()) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java index 5f6d98d..230a964 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java @@ -5,6 +5,7 @@ import _11.asktpk.artisanconnectbackend.entities.Client; import _11.asktpk.artisanconnectbackend.security.JwtUtil; import _11.asktpk.artisanconnectbackend.service.ClientService; import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -12,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +@Slf4j @RestController @RequestMapping("/api/v1/auth") public class AuthController { @@ -33,6 +35,7 @@ public class AuthController { String token = jwtUtil.generateToken(client.getEmail(), userRole, userId); + log.info("Logged in as " + client.getEmail()); return ResponseEntity.status(HttpStatus.OK) .body(new AuthResponseDTO(userId, userRole, token)); } else { @@ -54,6 +57,8 @@ public class AuthController { savedClient.getId() ); + log.info("Registered as " + savedClient.getEmail()); + return ResponseEntity.status(HttpStatus.CREATED) .body(new AuthResponseDTO( savedClient.getId(), diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java index 7700ee2..458b719 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java @@ -36,8 +36,12 @@ public class JwtRequestFilter extends OncePerRequestFilter { if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); - if (jwtUtil.isBlacklisted(jwt)) { + if (jwtUtil.isBlacklisted(jwt) || !jwtUtil.isLatestToken(jwt)) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + String jsonResponse = "{\"error\": \"Token is invalid or expired. Please login again.\"}"; + response.getWriter().write(jsonResponse); return; } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java index 4ac4895..ae36e06 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtUtil.java @@ -8,10 +8,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -40,11 +37,27 @@ public class JwtUtil { return Keys.hmacShaKeyFor(secret.getBytes()); } + private final Map userActiveTokens = new ConcurrentHashMap<>(); + + public boolean isLatestToken(String token) { + String email = extractEmail(token); + String tokenId = extractTokenId(token); + String latestTokenId = userActiveTokens.get(email); + + return latestTokenId != null && latestTokenId.equals(tokenId); + } + public String generateToken(String email, String role, Long userId) { Map claims = new HashMap<>(); claims.put("role", role); claims.put("userId", userId); - return createToken(claims, email); + claims.put("tokenId", UUID.randomUUID().toString()); + + String token = createToken(claims, email); + + userActiveTokens.put(email, extractTokenId(token)); + + return token; } private String createToken(Map claims, String subject) { @@ -57,6 +70,10 @@ public class JwtUtil { .compact(); } + public String extractTokenId(String token) { + return extractAllClaims(token).get("tokenId", String.class); + } + public String extractEmail(String token) { return extractClaim(token, Claims::getSubject); } From 5f548de73a29a41ee4245fbcea4bb6a0a983b151 Mon Sep 17 00:00:00 2001 From: Andrii Solianyk Date: Wed, 4 Jun 2025 12:07:56 +0200 Subject: [PATCH 3/4] dto change to show good role --- .../controller/AuthController.java | 4 +-- .../controller/ClientController.java | 12 ++++----- .../artisanconnectbackend/dto/ClientDTO.java | 4 +-- .../dto/RequestResponseDTO.java | 4 +++ .../repository/RolesRepository.java | 2 ++ .../security/JwtRequestFilter.java | 26 ++++++++++++------- .../service/ClientService.java | 25 +++++++++++++++--- 7 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java index 230a964..2a7f5e2 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java @@ -53,7 +53,7 @@ public class AuthController { String token = jwtUtil.generateToken( savedClient.getEmail(), - savedClient.getRole().getRole(), + savedClient.getRole(), savedClient.getId() ); @@ -62,7 +62,7 @@ public class AuthController { return ResponseEntity.status(HttpStatus.CREATED) .body(new AuthResponseDTO( savedClient.getId(), - savedClient.getRole().getRole(), + savedClient.getRole(), token )); } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/ClientController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/ClientController.java index b20fddd..f5ba9a5 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/controller/ClientController.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/ClientController.java @@ -24,16 +24,16 @@ public class ClientController { } @GetMapping("/get/{id}") - public ResponseEntity getClientById(@PathVariable long id) { + public ResponseEntity getClientById(@PathVariable long id) { if(clientService.getClientById(id) != null) { - return new ResponseEntity(clientService.getClientById(id), HttpStatus.OK); + return new ResponseEntity<>(clientService.getClientByIdDTO(id), HttpStatus.OK); } else { - return new ResponseEntity(HttpStatus.NOT_FOUND); + return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } @PostMapping("/add") - public ResponseEntity addClient(@RequestBody ClientDTO clientDTO) { + public ResponseEntity addClient(@RequestBody ClientDTO clientDTO) { if(clientService.clientExists(clientDTO.getId())) { return new ResponseEntity<>(HttpStatus.CONFLICT); } else { @@ -43,7 +43,7 @@ public class ClientController { // TODO: do zrobienia walidacja danych @PutMapping("/edit/{id}") - public ResponseEntity updateClient(@PathVariable("id") long id, @RequestBody ClientDTO clientDTO) { + public ResponseEntity updateClient(@PathVariable("id") long id, @RequestBody ClientDTO clientDTO) { if(clientService.clientExists(id)) { return new ResponseEntity<>(clientService.updateClient(id, clientDTO),HttpStatus.OK); } else { @@ -52,7 +52,7 @@ public class ClientController { } @DeleteMapping("/delete/{id}") - public ResponseEntity deleteClient(@PathVariable("id") long id) { + public ResponseEntity deleteClient(@PathVariable("id") long id) { if(clientService.clientExists(id)) { clientService.deleteClient(id); return new ResponseEntity<>(HttpStatus.OK); diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java index 4be1595..ab6af54 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/ClientDTO.java @@ -6,8 +6,6 @@ import lombok.Setter; import jakarta.validation.constraints.Email; -import _11.asktpk.artisanconnectbackend.entities.Role; - @Getter @Setter public class ClientDTO { private Long id; @@ -18,5 +16,5 @@ public class ClientDTO { private String firstName; private String lastName; private String image; - private Role role; + private String role; } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/RequestResponseDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/RequestResponseDTO.java index 96a0ed5..845258d 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/dto/RequestResponseDTO.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/RequestResponseDTO.java @@ -10,4 +10,8 @@ public class RequestResponseDTO { public RequestResponseDTO(String message) { this.message = message; } + + public String toJSON() { + return "{\"message\":\"" + message + "\"}"; + } } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java b/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java index d766026..0ba644e 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/repository/RolesRepository.java @@ -7,4 +7,6 @@ import _11.asktpk.artisanconnectbackend.entities.Role; @Repository public interface RolesRepository extends JpaRepository { Role findRoleById(Long id); + + Role findRoleByRole(String role); } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java index 458b719..035d373 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/security/JwtRequestFilter.java @@ -1,5 +1,7 @@ package _11.asktpk.artisanconnectbackend.security; +import _11.asktpk.artisanconnectbackend.dto.RequestResponseDTO; +import io.jsonwebtoken.ExpiredJwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -36,20 +38,26 @@ public class JwtRequestFilter extends OncePerRequestFilter { if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); - if (jwtUtil.isBlacklisted(jwt) || !jwtUtil.isLatestToken(jwt)) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - String jsonResponse = "{\"error\": \"Token is invalid or expired. Please login again.\"}"; - response.getWriter().write(jsonResponse); - return; - } - try { + if (jwtUtil.isBlacklisted(jwt) || !jwtUtil.isLatestToken(jwt)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + String jsonResponse = "{\"error\": \"Token is invalid or expired. Please login again.\"}"; + response.getWriter().write(jsonResponse); + return; + } + + email = jwtUtil.extractEmail(jwt); + } catch (ExpiredJwtException expiredJwtException) { + logger.error(expiredJwtException.getMessage()); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; } catch (Exception e) { logger.error(e.getMessage()); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write(new RequestResponseDTO(e.getMessage()).toJSON()); return; } } diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java b/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java index 115480a..94ab65c 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java @@ -4,6 +4,7 @@ import _11.asktpk.artisanconnectbackend.dto.AuthRequestDTO; import _11.asktpk.artisanconnectbackend.dto.ClientDTO; import _11.asktpk.artisanconnectbackend.dto.ClientRegistrationDTO; import _11.asktpk.artisanconnectbackend.entities.Client; +import _11.asktpk.artisanconnectbackend.entities.Role; import _11.asktpk.artisanconnectbackend.repository.ClientRepository; import _11.asktpk.artisanconnectbackend.repository.RolesRepository; import jakarta.persistence.EntityNotFoundException; @@ -25,13 +26,17 @@ public class ClientService { } private ClientDTO toDto(Client client) { + if(client == null) { + return null; + } + ClientDTO dto = new ClientDTO(); dto.setId(client.getId()); dto.setFirstName(client.getFirstName()); dto.setLastName(client.getLastName()); dto.setEmail(client.getEmail()); - dto.setRole(client.getRole()); + dto.setRole(client.getRole().getRole()); dto.setImage(client.getImage()); return dto; @@ -39,12 +44,20 @@ public class ClientService { private Client fromDto(ClientDTO dto) { Client client = new Client(); + Role rola; + + if (clientRepository.findById(dto.getId()).isPresent()) { + rola = clientRepository.findById(dto.getId()).get().getRole(); + } else { + rola = new Role(); + rola.setRole("USER"); + } client.setId(dto.getId()); client.setFirstName(dto.getFirstName()); client.setLastName(dto.getLastName()); client.setEmail(dto.getEmail()); - client.setRole(dto.getRole()); + client.setRole(rola); client.setImage(dto.getImage()); return client; @@ -69,6 +82,10 @@ public class ClientService { return clientRepository.findById(id).orElse(null); } + public ClientDTO getClientByIdDTO(Long id) { + return toDto(clientRepository.findById(id).orElse(null)); + } + public boolean clientExists(Long id) { return clientRepository.existsById(id); } @@ -81,11 +98,13 @@ public class ClientService { Client existingClient = clientRepository.findById(id) .orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id)); + Role newRole = rolesRepository.findRoleByRole(clientDTO.getRole()); + existingClient.setEmail(clientDTO.getEmail()); existingClient.setFirstName(clientDTO.getFirstName()); existingClient.setLastName(clientDTO.getLastName()); existingClient.setImage(clientDTO.getImage()); - existingClient.setRole(clientDTO.getRole()); + existingClient.setRole(newRole); return toDto(clientRepository.save(existingClient)); } From 5262749e2ddb500fcb03b47f6ae7012d0dbff860 Mon Sep 17 00:00:00 2001 From: Andrii Solianyk Date: Fri, 6 Jun 2025 16:05:18 +0200 Subject: [PATCH 4/4] autoryzacja google --- pom.xml | 5 ++ .../controller/AuthController.java | 60 ++++++++++++++++--- .../dto/GoogleAuthRequestDTO.java | 9 +++ .../service/ClientService.java | 8 +++ src/main/resources/application.properties | 2 +- 5 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 src/main/java/_11/asktpk/artisanconnectbackend/dto/GoogleAuthRequestDTO.java diff --git a/pom.xml b/pom.xml index ee2a1cb..e0ef644 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,11 @@ runtime true + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + 2.4.12 + org.postgresql postgresql diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java index 2a7f5e2..231f1df 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/controller/AuthController.java @@ -6,12 +6,12 @@ import _11.asktpk.artisanconnectbackend.security.JwtUtil; import _11.asktpk.artisanconnectbackend.service.ClientService; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; @Slf4j @RestController @@ -35,7 +35,7 @@ public class AuthController { String token = jwtUtil.generateToken(client.getEmail(), userRole, userId); - log.info("Logged in as " + client.getEmail()); + log.info("User logged in with {}", client.getEmail()); return ResponseEntity.status(HttpStatus.OK) .body(new AuthResponseDTO(userId, userRole, token)); } else { @@ -57,7 +57,7 @@ public class AuthController { savedClient.getId() ); - log.info("Registered as " + savedClient.getEmail()); + log.info("New user registered with {}", savedClient.getEmail()); return ResponseEntity.status(HttpStatus.CREATED) .body(new AuthResponseDTO( @@ -79,4 +79,48 @@ public class AuthController { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Invalid token")); } + + @PostMapping("/google") + public ResponseEntity authenticateWithGoogle(@RequestBody GoogleAuthRequestDTO dto) { + try { + String accessToken = dto.getGoogleToken(); + String googleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo"; + + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + HttpEntity entity = new HttpEntity<>(headers); + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange( + googleUserInfoUrl, HttpMethod.GET, entity, Map.class); + + Map userInfo = response.getBody(); + +// String googleId = (String) userInfo.get("sub"); Potencjalnie możemy używać googlowskiego ID, ale to ma konflikt z naszym generowanym + assert userInfo != null; + String email = (String) userInfo.get("email"); + String name = (String) userInfo.get("name"); + + Client client = clientService.getClientByEmail(email); + if (client == null) { + client = new Client(); + client.setEmail(email); + client.setFirstName(name); + client.setRole(clientService.getUserRole()); // to pobiera po prostu role "USER" z tabeli w bazie + clientService.saveClientToDB(client); + } + + String jwt = jwtUtil.generateToken(client.getEmail(), client.getRole().getRole(), client.getId()); + + log.info("User authenticated with google: {}", email); + return ResponseEntity.ok(new AuthResponseDTO(client.getId(), client.getRole().getRole(), jwt)); + } catch (HttpClientErrorException httpClientErrorException) { + log.error("Token is invalid or expired"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new RequestResponseDTO("Invalid access token")); + } catch (Exception e) { + log.error("Error while checking Google access token", e); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(new RequestResponseDTO("Authentication Error (Google): " + e.getMessage())); + } + } } \ No newline at end of file diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/dto/GoogleAuthRequestDTO.java b/src/main/java/_11/asktpk/artisanconnectbackend/dto/GoogleAuthRequestDTO.java new file mode 100644 index 0000000..df94256 --- /dev/null +++ b/src/main/java/_11/asktpk/artisanconnectbackend/dto/GoogleAuthRequestDTO.java @@ -0,0 +1,9 @@ +package _11.asktpk.artisanconnectbackend.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter @Setter +public class GoogleAuthRequestDTO { + private String googleToken; +} diff --git a/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java b/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java index 94ab65c..36af97b 100644 --- a/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java +++ b/src/main/java/_11/asktpk/artisanconnectbackend/service/ClientService.java @@ -94,6 +94,10 @@ public class ClientService { return toDto(clientRepository.save(fromDto(clientDTO))); } + public Client saveClientToDB(Client client) { + return clientRepository.save(client); + } + public ClientDTO updateClient(long id, ClientDTO clientDTO) { Client existingClient = clientRepository.findById(id) .orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id)); @@ -134,4 +138,8 @@ public class ClientService { public Client getClientByEmail(String email) { return clientRepository.findByEmail(email); } + + public Role getUserRole() { + return rolesRepository.findRoleByRole("USER"); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e4e02c7..8f83fb5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -29,4 +29,4 @@ jwt.secret=DIXLsOs3FKmCAQwISd0SKsHMXJrPl3IKIRkVlkOvYW7kEcdUTbxh8zFe1B3eZWkY jwt.expiration=300000 logging.file.name=logs/payment-notifications.log -logging.level.TpayLogger=INFO +logging.level.TpayLogger=INFO \ No newline at end of file