From a1ca9d1328280fa684f73d8c0fcfbf8aaa0f0902 Mon Sep 17 00:00:00 2001 From: Hyojin Ahn Date: Wed, 19 Nov 2025 12:13:29 -0500 Subject: [PATCH] =?UTF-8?q?=ED=86=A0=ED=81=B0=20=ED=8C=8C=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 +- .../java/com/goi/erp/SecurityApplication.java | 30 +--- .../erp/auditing/ApplicationAuditAware.java | 30 ---- .../erp/auth/AuthenticationController.java | 37 ---- .../goi/erp/auth/AuthenticationRequest.java | 16 -- .../goi/erp/auth/AuthenticationResponse.java | 19 --- .../goi/erp/auth/AuthenticationService.java | 158 ------------------ .../com/goi/erp/auth/RegisterRequest.java | 21 --- .../com/goi/erp/config/ApplicationConfig.java | 78 +-------- .../erp/config/JwtAuthenticationFilter.java | 67 +++----- .../java/com/goi/erp/config/JwtService.java | 132 --------------- .../com/goi/erp/config/LogoutService.java | 40 ----- .../com/goi/erp/config/SecurityConfig.java | 42 +++++ .../goi/erp/config/SecurityConfiguration.java | 81 --------- .../{demo => controller}/AdminController.java | 2 +- .../erp/controller/CustomerController.java | 55 ++++++ .../java/com/goi/erp/demo/DemoController.java | 19 --- .../goi/erp/demo/ManagementController.java | 50 ------ .../com/goi/erp/dto/CustomerRequestDto.java | 30 ++++ .../com/goi/erp/dto/CustomerResponseDto.java | 34 ++++ .../com/goi/erp/employee/EmployeeDetails.java | 62 ------- .../erp/employee/EmployeeDetailsService.java | 30 ---- .../goi/erp/employee/EmployeeRepository.java | 13 -- .../com/goi/erp/employee/EmployeeRole.java | 49 ------ .../erp/employee/EmployeeRoleRepository.java | 19 --- .../java/com/goi/erp/entity/Customer.java | 93 +++++++++++ .../erp/{employee => entity}/Employee.java | 14 +- .../goi/erp/permission/PermissionInfo.java | 46 ----- .../permission/PermissionInfoRepository.java | 15 -- .../erp/repository/CustomerRepository.java | 13 ++ src/main/java/com/goi/erp/role/RoleInfo.java | 48 ------ .../com/goi/erp/role/RoleInfoRepository.java | 14 -- .../java/com/goi/erp/role/RolePermission.java | 40 ----- .../erp/role/RolePermissionRepository.java | 26 --- .../com/goi/erp/service/CustomerService.java | 77 +++++++++ .../goi/erp/token/ApplicationAuditAware.java | 85 ++++++++++ .../java/com/goi/erp/token/JwtService.java | 129 ++++++++++++++ src/main/java/com/goi/erp/token/Token.java | 50 ------ .../com/goi/erp/token/TokenRepository.java | 22 --- .../java/com/goi/erp/token/TokenType.java | 5 - .../goi/erp/user/ChangePasswordRequest.java | 15 -- .../java/com/goi/erp/user/Permission.java | 22 --- src/main/java/com/goi/erp/user/Role.java | 59 ------- src/main/resources/application.yml | 7 +- 44 files changed, 597 insertions(+), 1303 deletions(-) delete mode 100644 src/main/java/com/goi/erp/auditing/ApplicationAuditAware.java delete mode 100644 src/main/java/com/goi/erp/auth/AuthenticationController.java delete mode 100644 src/main/java/com/goi/erp/auth/AuthenticationRequest.java delete mode 100644 src/main/java/com/goi/erp/auth/AuthenticationResponse.java delete mode 100644 src/main/java/com/goi/erp/auth/AuthenticationService.java delete mode 100644 src/main/java/com/goi/erp/auth/RegisterRequest.java delete mode 100644 src/main/java/com/goi/erp/config/JwtService.java delete mode 100644 src/main/java/com/goi/erp/config/LogoutService.java create mode 100644 src/main/java/com/goi/erp/config/SecurityConfig.java delete mode 100644 src/main/java/com/goi/erp/config/SecurityConfiguration.java rename src/main/java/com/goi/erp/{demo => controller}/AdminController.java (97%) create mode 100644 src/main/java/com/goi/erp/controller/CustomerController.java delete mode 100644 src/main/java/com/goi/erp/demo/DemoController.java delete mode 100644 src/main/java/com/goi/erp/demo/ManagementController.java create mode 100644 src/main/java/com/goi/erp/dto/CustomerRequestDto.java create mode 100644 src/main/java/com/goi/erp/dto/CustomerResponseDto.java delete mode 100644 src/main/java/com/goi/erp/employee/EmployeeDetails.java delete mode 100644 src/main/java/com/goi/erp/employee/EmployeeDetailsService.java delete mode 100644 src/main/java/com/goi/erp/employee/EmployeeRepository.java delete mode 100644 src/main/java/com/goi/erp/employee/EmployeeRole.java delete mode 100644 src/main/java/com/goi/erp/employee/EmployeeRoleRepository.java create mode 100644 src/main/java/com/goi/erp/entity/Customer.java rename src/main/java/com/goi/erp/{employee => entity}/Employee.java (69%) delete mode 100644 src/main/java/com/goi/erp/permission/PermissionInfo.java delete mode 100644 src/main/java/com/goi/erp/permission/PermissionInfoRepository.java create mode 100644 src/main/java/com/goi/erp/repository/CustomerRepository.java delete mode 100644 src/main/java/com/goi/erp/role/RoleInfo.java delete mode 100644 src/main/java/com/goi/erp/role/RoleInfoRepository.java delete mode 100644 src/main/java/com/goi/erp/role/RolePermission.java delete mode 100644 src/main/java/com/goi/erp/role/RolePermissionRepository.java create mode 100644 src/main/java/com/goi/erp/service/CustomerService.java create mode 100644 src/main/java/com/goi/erp/token/ApplicationAuditAware.java create mode 100644 src/main/java/com/goi/erp/token/JwtService.java delete mode 100644 src/main/java/com/goi/erp/token/Token.java delete mode 100644 src/main/java/com/goi/erp/token/TokenRepository.java delete mode 100644 src/main/java/com/goi/erp/token/TokenType.java delete mode 100644 src/main/java/com/goi/erp/user/ChangePasswordRequest.java delete mode 100644 src/main/java/com/goi/erp/user/Permission.java delete mode 100644 src/main/java/com/goi/erp/user/Role.java diff --git a/pom.xml b/pom.xml index 9f60383..7b29dea 100644 --- a/pom.xml +++ b/pom.xml @@ -9,10 +9,10 @@ com.goi - auth-service + crm-rest-api 0.0.1-SNAPSHOT - security - Demo project for Spring Boot + Customer Service + Customer Service REST Api 17 diff --git a/src/main/java/com/goi/erp/SecurityApplication.java b/src/main/java/com/goi/erp/SecurityApplication.java index 199783c..f7c79a2 100644 --- a/src/main/java/com/goi/erp/SecurityApplication.java +++ b/src/main/java/com/goi/erp/SecurityApplication.java @@ -8,37 +8,11 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication @EnableJpaAuditing(auditorAwareRef = "auditorAware") -@EntityScan(basePackages = {"com.goi.erp"}) -@EnableJpaRepositories(basePackages = {"com.goi.erp"}) +@EntityScan(basePackages = {"com.goi.erp.entity"}) +@EnableJpaRepositories(basePackages = {"com.goi.erp.repository"}) public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } - -// @Bean -// public CommandLineRunner commandLineRunner( -// AuthenticationService service -// ) { -// return args -> { -// var admin = RegisterRequest.builder() -// .firstname("Admin") -// .lastname("Admin") -// .email("admin@mail.com") -// .password("password") -// .role(ADMIN) -// .build(); -// System.out.println("Admin token: " + service.register(admin).getAccessToken()); -// -// var manager = RegisterRequest.builder() -// .firstname("Admin") -// .lastname("Admin") -// .email("manager@mail.com") -// .password("password") -// .role(MANAGER) -// .build(); -// System.out.println("Manager token: " + service.register(manager).getAccessToken()); -// -// }; -// } } diff --git a/src/main/java/com/goi/erp/auditing/ApplicationAuditAware.java b/src/main/java/com/goi/erp/auditing/ApplicationAuditAware.java deleted file mode 100644 index 08b167c..0000000 --- a/src/main/java/com/goi/erp/auditing/ApplicationAuditAware.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.goi.erp.auditing; - -import org.springframework.data.domain.AuditorAware; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; - -import com.goi.erp.employee.EmployeeDetails; - -import java.util.Optional; - -public class ApplicationAuditAware implements AuditorAware { - - @Override - public Optional getCurrentAuditor() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - - if (authentication == null || - !authentication.isAuthenticated() || - authentication instanceof AnonymousAuthenticationToken) { - return Optional.empty(); - } - - // EmployeeDetails로 캐스팅 - EmployeeDetails employeeDetails = (EmployeeDetails) authentication.getPrincipal(); - - // 내부 PK(empId) 반환 - return Optional.ofNullable(employeeDetails.getEmployee().getEmpId()); - } -} diff --git a/src/main/java/com/goi/erp/auth/AuthenticationController.java b/src/main/java/com/goi/erp/auth/AuthenticationController.java deleted file mode 100644 index ab8282f..0000000 --- a/src/main/java/com/goi/erp/auth/AuthenticationController.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.goi.erp.auth; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -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 java.io.IOException; - -@RestController -@RequestMapping("/auth") -@RequiredArgsConstructor -public class AuthenticationController { - - private final AuthenticationService service; - -// @PostMapping("/register") -// public ResponseEntity register( -// @RequestBody RegisterRequest request -// ) { -// return ResponseEntity.ok(service.register(request)); -// } - @PostMapping("/authenticate") - public ResponseEntity authenticate(@RequestBody AuthenticationRequest request) { - return ResponseEntity.ok(service.authenticate(request)); - } - - @PostMapping("/refresh-token") - public void refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException { - service.refreshToken(request, response); - } - -} diff --git a/src/main/java/com/goi/erp/auth/AuthenticationRequest.java b/src/main/java/com/goi/erp/auth/AuthenticationRequest.java deleted file mode 100644 index 4b2c587..0000000 --- a/src/main/java/com/goi/erp/auth/AuthenticationRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.goi.erp.auth; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class AuthenticationRequest { - - private String empLoginId; // 기존 email 대신 - private String empLoginPassword; -} diff --git a/src/main/java/com/goi/erp/auth/AuthenticationResponse.java b/src/main/java/com/goi/erp/auth/AuthenticationResponse.java deleted file mode 100644 index 6072fbd..0000000 --- a/src/main/java/com/goi/erp/auth/AuthenticationResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.goi.erp.auth; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class AuthenticationResponse { - - @JsonProperty("access_token") - private String accessToken; - @JsonProperty("refresh_token") - private String refreshToken; -} diff --git a/src/main/java/com/goi/erp/auth/AuthenticationService.java b/src/main/java/com/goi/erp/auth/AuthenticationService.java deleted file mode 100644 index 6132dc8..0000000 --- a/src/main/java/com/goi/erp/auth/AuthenticationService.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.goi.erp.auth; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.goi.erp.config.JwtService; -import com.goi.erp.token.Token; -import com.goi.erp.token.TokenRepository; -import com.goi.erp.token.TokenType; -import com.goi.erp.employee.Employee; -import com.goi.erp.employee.EmployeeRepository; -import com.goi.erp.employee.EmployeeRole; -import com.goi.erp.employee.EmployeeRoleRepository; -import com.goi.erp.role.RolePermissionRepository; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpHeaders; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -public class AuthenticationService { - private final EmployeeRepository employeeRepository; - private final EmployeeRoleRepository employeeRoleRepository; - private final TokenRepository tokenRepository; - private final PasswordEncoder passwordEncoder; - private final RolePermissionRepository rolePermissionRepository; - - private final JwtService jwtService; -// private final AuthenticationManager authenticationManager; - -// public AuthenticationResponse register(RegisterRequest request) { -// var user = User.builder().firstname(request.getFirstname()).lastname(request.getLastname()) -// .email(request.getEmail()).password(passwordEncoder.encode(request.getPassword())) -// .role(request.getRole()).build(); -// var savedUser = repository.save(user); -// var jwtToken = jwtService.generateToken(user); -// var refreshToken = jwtService.generateRefreshToken(user); -// saveUserToken(savedUser, jwtToken); -// return AuthenticationResponse.builder().accessToken(jwtToken).refreshToken(refreshToken).build(); -// } - - // 로그인 처리 - public AuthenticationResponse authenticate(AuthenticationRequest request) { - // 1. Employee 조회 - Employee employee = employeeRepository.findByEmpLoginId(request.getEmpLoginId()) - .orElseThrow(() -> new RuntimeException("Employee not found")); - - // 2. 비밀번호 검증 - if (!passwordEncoder.matches(request.getEmpLoginPassword(), employee.getEmpLoginPassword())) { - throw new RuntimeException("Invalid password"); - } - - // 3. EmployeeRole 조회 → Role 이름 리스트 생성 - List activeRoles = employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId()); - - List roles = activeRoles.stream() - .map(er -> er.getRoleInfo().getRoleName()) - .collect(Collectors.toList()); - - - // 4. Role → Permission 조회 - List permissions = activeRoles.stream() - .flatMap(er -> rolePermissionRepository.findByRoleId(er.getRoleInfo().getRoleId()).stream()) - .map(rp -> rp.getPermissionInfo().getPermModule() + ":" + rp.getPermissionInfo().getPermAction() + ":" + rp.getPermissionInfo().getPermScope()) - .distinct() - .collect(Collectors.toList()); - - // 5. generate token - String jwtToken = jwtService.generateToken(employee, roles, permissions); - String refreshToken = jwtService.generateRefreshToken(employee, roles, permissions); - - // 기존 토큰 회수 및 새 토큰 저장 - revokeAllEmployeeTokens(employee); - saveEmployeeToken(employee, jwtToken); - - return AuthenticationResponse.builder() - .accessToken(jwtToken) - .refreshToken(refreshToken) - .build(); - } - - // JWT 토큰 저장 - private void saveEmployeeToken(Employee employee, String jwtToken) { - Token token = Token.builder() - .employee(employee) - .token(jwtToken) - .tokenType(TokenType.BEARER) - .expired(false) - .revoked(false) - .build(); - tokenRepository.save(token); - } - - // 기존 토큰 회수 - private void revokeAllEmployeeTokens(Employee employee) { - List validTokens = tokenRepository.findAllValidTokenByEmployee(employee.getEmpId()); - if (validTokens.isEmpty()) return; - - validTokens.forEach(token -> { - token.setExpired(true); - token.setRevoked(true); - }); - - tokenRepository.saveAll(validTokens); - } - - // 리프레시 토큰 처리 - public void refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException { - final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); - if (authHeader == null || !authHeader.startsWith("Bearer ")) { - return; - } - - final String refreshToken = authHeader.substring(7); - String empLoginId = jwtService.extractUsername(refreshToken); - - if (empLoginId != null) { - Employee employee = employeeRepository.findByEmpLoginId(empLoginId) - .orElseThrow(() -> new RuntimeException("Employee not found")); - - if (jwtService.isTokenValid(refreshToken, employee)) { - // 3. EmployeeRole 조회 → Role 이름 리스트 생성 - List activeRoles = employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId()); - - List roles = activeRoles.stream() - .map(er -> er.getRoleInfo().getRoleName()) - .collect(Collectors.toList()); - - - // 4. Role → Permission 조회 - List permissions = activeRoles.stream() - .flatMap(er -> rolePermissionRepository.findByRoleId(er.getRoleInfo().getRoleId()).stream()) - .map(rp -> rp.getPermissionInfo().getPermModule() + ":" + rp.getPermissionInfo().getPermAction() + ":" + rp.getPermissionInfo().getPermScope()) - .distinct() - .collect(Collectors.toList()); - - // 5. generate token - String accessToken = jwtService.generateToken(employee, roles, permissions); - - revokeAllEmployeeTokens(employee); - saveEmployeeToken(employee, accessToken); - - AuthenticationResponse authResponse = AuthenticationResponse.builder() - .accessToken(accessToken) - .refreshToken(refreshToken) - .build(); - - new ObjectMapper().writeValue(response.getOutputStream(), authResponse); - } - } - } -} diff --git a/src/main/java/com/goi/erp/auth/RegisterRequest.java b/src/main/java/com/goi/erp/auth/RegisterRequest.java deleted file mode 100644 index e964bcf..0000000 --- a/src/main/java/com/goi/erp/auth/RegisterRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.goi.erp.auth; - -import com.goi.erp.user.Role; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class RegisterRequest { - - private String firstname; - private String lastname; - private String email; - private String password; - private Role role; -} diff --git a/src/main/java/com/goi/erp/config/ApplicationConfig.java b/src/main/java/com/goi/erp/config/ApplicationConfig.java index f2fdbb3..3e10dec 100644 --- a/src/main/java/com/goi/erp/config/ApplicationConfig.java +++ b/src/main/java/com/goi/erp/config/ApplicationConfig.java @@ -1,83 +1,21 @@ package com.goi.erp.config; -import lombok.RequiredArgsConstructor; - -import java.util.List; - +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import com.goi.erp.auditing.ApplicationAuditAware; -import com.goi.erp.employee.Employee; -import com.goi.erp.employee.EmployeeRole; -import com.goi.erp.employee.EmployeeRoleRepository; -import com.goi.erp.employee.EmployeeDetails; -import com.goi.erp.employee.EmployeeRepository; +import com.goi.erp.token.ApplicationAuditAware; @Configuration -@RequiredArgsConstructor public class ApplicationConfig { - - private final EmployeeRepository employeeRepository; - private final EmployeeRoleRepository employeeRoleRepository; + + @Value("${application.security.jwt.secret-key}") + private String jwtSecret; @Bean - public UserDetailsService userDetailsService() { - return username -> { - Employee employee = employeeRepository.findByEmpLoginId(username) - .orElseThrow(() -> new UsernameNotFoundException("Employee not found")); - - // EmployeeRole 조회 - List roles = employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId()); - - // EmployeeDetails 생성 - return new EmployeeDetails(employee, roles); - }; - } - - @Bean - public AuthenticationProvider authenticationProvider() { - DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); - authProvider.setUserDetailsService(userDetailsService()); - authProvider.setPasswordEncoder(passwordEncoder()); - return authProvider; - } - - @Bean - public AuditorAware auditorAware() { - return new ApplicationAuditAware(); - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { - return config.getAuthenticationManager(); - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - public static void main(String[] args) { - String rawPassword = "1111"; // 테스트할 비밀번호 - PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - - String hashedPassword = passwordEncoder.encode(rawPassword); - System.out.println("Raw password: " + rawPassword); - System.out.println("Hashed password: " + hashedPassword); - - // 확인용 matches 테스트 - boolean matches = passwordEncoder.matches(rawPassword, hashedPassword); - System.out.println("Matches: " + matches); - } + public AuditorAware auditorAware() { + return new ApplicationAuditAware(jwtSecret); + } } diff --git a/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java b/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java index 244377e..16e2f06 100644 --- a/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java +++ b/src/main/java/com/goi/erp/config/JwtAuthenticationFilter.java @@ -1,15 +1,11 @@ package com.goi.erp.config; -import com.goi.erp.employee.Employee; -import com.goi.erp.employee.EmployeeDetails; -import com.goi.erp.employee.EmployeeRepository; -import com.goi.erp.employee.EmployeeRole; -import com.goi.erp.employee.EmployeeRoleRepository; -import com.goi.erp.token.TokenRepository; +import com.goi.erp.token.JwtService; import lombok.RequiredArgsConstructor; import org.springframework.lang.NonNull; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -18,19 +14,15 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; - import java.io.IOException; import java.util.List; -import java.util.UUID; +import java.util.stream.Collectors; @Component @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtService jwtService; - private final EmployeeRepository employeeRepository; - private final EmployeeRoleRepository employeeRoleRepository; - private final TokenRepository tokenRepository; @Override protected void doFilterInternal( @@ -39,51 +31,32 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { @NonNull FilterChain filterChain ) throws ServletException, IOException { - // 인증 API는 필터링 제외 - if (request.getServletPath().contains("/api/v1/auth")) { - filterChain.doFilter(request, response); - return; - } - final String authHeader = request.getHeader("Authorization"); - final String jwt; - if (authHeader == null || !authHeader.startsWith("Bearer ")) { filterChain.doFilter(request, response); return; } - jwt = authHeader.substring(7); - final String empUuidStr = jwtService.extractUsername(jwt); + final String jwt = authHeader.substring(7); - if (empUuidStr != null && SecurityContextHolder.getContext().getAuthentication() == null) { - UUID empUuid = UUID.fromString(empUuidStr); + if (SecurityContextHolder.getContext().getAuthentication() == null && jwtService.isTokenValid(jwt)) { - // Employee 조회 - Employee employee = employeeRepository.findByEmpUuid(empUuid) - .orElseThrow(() -> new RuntimeException("Employee not found")); - // Role 조회 - List roles = employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId()); - EmployeeDetails employeeDetails = new EmployeeDetails(employee, roles); + // 토큰에서 empUuid와 권한 추출 + String empUuid = jwtService.extractEmpUuid(jwt); + List permissions = jwtService.extractPermissions(jwt); + List authorities = permissions.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); - // DB 토큰 검증 - boolean isTokenValid = tokenRepository.findByToken(jwt) - .map(t -> !t.isExpired() && !t.isRevoked()) - .orElse(false); - - // JWT 유효성 검증 + DB 토큰 검증 - if (jwtService.isTokenValid(jwt, employee) && isTokenValid) { - UsernamePasswordAuthenticationToken authToken = - new UsernamePasswordAuthenticationToken( - employeeDetails, - null, - employeeDetails.getAuthorities() - ); - authToken.setDetails( - new WebAuthenticationDetailsSource().buildDetails(request) - ); - SecurityContextHolder.getContext().setAuthentication(authToken); - } + // 인증 정보 SecurityContextHolder에 세팅 + UsernamePasswordAuthenticationToken authToken = + new UsernamePasswordAuthenticationToken( + empUuid, // principal + null, // credentials + authorities + ); + authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authToken); } filterChain.doFilter(request, response); diff --git a/src/main/java/com/goi/erp/config/JwtService.java b/src/main/java/com/goi/erp/config/JwtService.java deleted file mode 100644 index 91f9ada..0000000 --- a/src/main/java/com/goi/erp/config/JwtService.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.goi.erp.config; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.io.Encoders; -import io.jsonwebtoken.security.Keys; -import java.security.Key; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import com.goi.erp.employee.Employee; - -@Service -public class JwtService { - - @Value("${application.security.jwt.secret-key}") - private String secretKey; - - @Value("${application.security.jwt.expiration}") - private long jwtExpiration; - - @Value("${application.security.jwt.refresh-token.expiration}") - private long refreshExpiration; - - // =================== 기존 UserDetails용 =================== - public String extractUsername(String token) { - return extractClaim(token, Claims::getSubject); - } - - public T extractClaim(String token, Function claimsResolver) { - final Claims claims = extractAllClaims(token); - return claimsResolver.apply(claims); - } - - public String generateToken(Employee employee, List roles, List permissions) { - Map extraClaims = new HashMap<>(); - extraClaims.put("roles", roles); - - // Admin 계정 여부 확인 - boolean isAdmin = roles.stream().anyMatch(r -> r.equalsIgnoreCase("Admin")); - - if (isAdmin) { - // Admin이면 permissions를 ALL로 단순화 - extraClaims.put("permissions", List.of("ALL")); - } else { - // 일반 계정이면 상세 권한 넣기 - extraClaims.put("permissions", permissions); - } - - return buildToken(extraClaims, employee.getEmpUuid().toString(), jwtExpiration); - } - - public String generateRefreshToken(Employee employee, List roles, List permissions) { - Map extraClaims = new HashMap<>(); - extraClaims.put("roles", roles); - // Admin 계정 여부 확인 - boolean isAdmin = roles.stream().anyMatch(r -> r.equalsIgnoreCase("Admin")); - - if (isAdmin) { - // Admin이면 permissions를 ALL로 단순화 - extraClaims.put("permissions", List.of("ALL")); - } else { - // 일반 계정이면 상세 권한 넣기 - extraClaims.put("permissions", permissions); - } - return buildToken(extraClaims, employee.getEmpUuid().toString(), refreshExpiration); - } - - private String buildToken(Map extraClaims, String subject, long expiration) { - return Jwts.builder().setClaims(extraClaims).setSubject(subject) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + expiration)) - .signWith(getSignInKey(), SignatureAlgorithm.HS256).compact(); - } - - public boolean isTokenValid(String token, Employee employee) { - final String username = extractUsername(token); - return (username.equals(employee.getEmpUuid().toString())) && !isTokenExpired(token); - } - - private boolean isTokenExpired(String token) { - return extractExpiration(token).before(new Date()); - } - - private Date extractExpiration(String token) { - return extractClaim(token, Claims::getExpiration); - } - - private Claims extractAllClaims(String token) { - return Jwts.parserBuilder().setSigningKey(getSignInKey()).build().parseClaimsJws(token).getBody(); - } - - private Key getSignInKey() { - byte[] keyBytes = Decoders.BASE64.decode(secretKey); - return Keys.hmacShaKeyFor(keyBytes); - } - - public static void main(String[] args) { - JwtService jwtService = new JwtService(); - jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8="; - - String token = "eyJhbGciOiJIUzI1NiJ9.eyJwZXJtaXNzaW9ucyI6WyJIOlI6UCIsIk86QzpBIiwiTzpSOkEiLCJPOlU6QSIsIk86RDpBIiwiUzpDOkEiLCJTOlI6QSIsIlM6VTpBIl0sInJvbGVzIjpbIk9wZXJhdGlvbnMgTWFuYWdlciJdLCJzdWIiOiJmZGE1NGZkZS03MTBmLTQ4ZDItYTRmYi00NzM2YjJhM2RhNWEiLCJpYXQiOjE3NjMxMzU4MzMsImV4cCI6MTc2MzIyMjIzM30.ie38b2JnkP3k4Vz7TzAwI7oRgOsIFYf0yMYADq5EhNM"; - - // user 정보 - Claims claims = jwtService.extractAllClaims(token); - - System.out.println("Subject (emp_uuid): " + claims.getSubject()); - System.out.println("Roles: " + claims.get("roles")); - System.out.println("Roles: " + claims.get("permissions")); - System.out.println("IssuedAt: " + claims.getIssuedAt()); - System.out.println("Expiration: " + claims.getExpiration()); - - // 모든 Claims 확인 -// Claims claims = Jwts.parserBuilder() -// .setSigningKey(Keys.hmacShaKeyFor("".getBytes())) -// .build() -// .parseClaimsJws(token) -// .getBody(); - - System.out.println("Claims: " + claims); - } -} diff --git a/src/main/java/com/goi/erp/config/LogoutService.java b/src/main/java/com/goi/erp/config/LogoutService.java deleted file mode 100644 index 7115381..0000000 --- a/src/main/java/com/goi/erp/config/LogoutService.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.goi.erp.config; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.logout.LogoutHandler; -import org.springframework.stereotype.Service; - -import com.goi.erp.token.TokenRepository; - -@Service -@RequiredArgsConstructor -public class LogoutService implements LogoutHandler { - - private final TokenRepository tokenRepository; - - @Override - public void logout( - HttpServletRequest request, - HttpServletResponse response, - Authentication authentication - ) { - final String authHeader = request.getHeader("Authorization"); - final String jwt; - if (authHeader == null ||!authHeader.startsWith("Bearer ")) { - return; - } - jwt = authHeader.substring(7); - var storedToken = tokenRepository.findByToken(jwt) - .orElse(null); - if (storedToken != null) { - storedToken.setExpired(true); - storedToken.setRevoked(true); - tokenRepository.save(storedToken); - SecurityContextHolder.clearContext(); - } - } -} diff --git a/src/main/java/com/goi/erp/config/SecurityConfig.java b/src/main/java/com/goi/erp/config/SecurityConfig.java new file mode 100644 index 0000000..7c32b88 --- /dev/null +++ b/src/main/java/com/goi/erp/config/SecurityConfig.java @@ -0,0 +1,42 @@ +package com.goi.erp.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableMethodSecurity // @PreAuthorize 등 사용 가능 +@RequiredArgsConstructor +public class SecurityConfig { + + private final JwtAuthenticationFilter jwtAuthFilter; // JWT 인증 필터 + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + // CSRF 비활성화 (API 서버라면 stateless) + .csrf(csrf -> csrf.disable()) + + // 세션 사용 안함 + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + + // 요청 권한 설정 + .authorizeHttpRequests(auth -> auth + .requestMatchers( + "/swagger-ui/**", + "/v3/api-docs/**" + ).permitAll() // 인증 없이 접근 허용 + .anyRequest().authenticated() // 나머지는 JWT 인증 필요 + ) + + // JWT 필터 등록 + .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } +} diff --git a/src/main/java/com/goi/erp/config/SecurityConfiguration.java b/src/main/java/com/goi/erp/config/SecurityConfiguration.java deleted file mode 100644 index 6b0bcd4..0000000 --- a/src/main/java/com/goi/erp/config/SecurityConfiguration.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.goi.erp.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.config.annotation.method.configuration.EnableMethodSecurity; -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.core.context.SecurityContextHolder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.logout.LogoutHandler; - -import static com.goi.erp.user.Permission.ADMIN_CREATE; -import static com.goi.erp.user.Permission.ADMIN_DELETE; -import static com.goi.erp.user.Permission.ADMIN_READ; -import static com.goi.erp.user.Permission.ADMIN_UPDATE; -import static com.goi.erp.user.Permission.MANAGER_CREATE; -import static com.goi.erp.user.Permission.MANAGER_DELETE; -import static com.goi.erp.user.Permission.MANAGER_READ; -import static com.goi.erp.user.Permission.MANAGER_UPDATE; -import static com.goi.erp.user.Role.ADMIN; -import static com.goi.erp.user.Role.MANAGER; -import static org.springframework.http.HttpMethod.DELETE; -import static org.springframework.http.HttpMethod.GET; -import static org.springframework.http.HttpMethod.POST; -import static org.springframework.http.HttpMethod.PUT; -import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; - -@Configuration -@EnableWebSecurity -@RequiredArgsConstructor -@EnableMethodSecurity -public class SecurityConfiguration { - - private static final String[] WHITE_LIST_URL = { - "/auth/**", - "/v2/api-docs", - "/v3/api-docs", - "/v3/api-docs/**", - "/swagger-resources", - "/swagger-resources/**", - "/configuration/ui", - "/configuration/security", - "/swagger-ui/**", - "/webjars/**", - "/swagger-ui.html"}; - private final JwtAuthenticationFilter jwtAuthFilter; - private final AuthenticationProvider authenticationProvider; - private final LogoutHandler logoutHandler; - - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http - .csrf(AbstractHttpConfigurer::disable) - .authorizeHttpRequests(req -> - req.requestMatchers(WHITE_LIST_URL) - .permitAll() - .requestMatchers("/api/v1/management/**").hasAnyRole(ADMIN.name(), MANAGER.name()) - .requestMatchers(GET, "/api/v1/management/**").hasAnyAuthority(ADMIN_READ.name(), MANAGER_READ.name()) - .requestMatchers(POST, "/api/v1/management/**").hasAnyAuthority(ADMIN_CREATE.name(), MANAGER_CREATE.name()) - .requestMatchers(PUT, "/api/v1/management/**").hasAnyAuthority(ADMIN_UPDATE.name(), MANAGER_UPDATE.name()) - .requestMatchers(DELETE, "/api/v1/management/**").hasAnyAuthority(ADMIN_DELETE.name(), MANAGER_DELETE.name()) - .anyRequest() - .authenticated() - ) - .sessionManagement(session -> session.sessionCreationPolicy(STATELESS)) - .authenticationProvider(authenticationProvider) - .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class) - .logout(logout -> - logout.logoutUrl("/api/v1/auth/logout") - .addLogoutHandler(logoutHandler) - .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext()) - ) - ; - - return http.build(); - } -} diff --git a/src/main/java/com/goi/erp/demo/AdminController.java b/src/main/java/com/goi/erp/controller/AdminController.java similarity index 97% rename from src/main/java/com/goi/erp/demo/AdminController.java rename to src/main/java/com/goi/erp/controller/AdminController.java index b0f6b2f..1e7d5a9 100644 --- a/src/main/java/com/goi/erp/demo/AdminController.java +++ b/src/main/java/com/goi/erp/controller/AdminController.java @@ -1,4 +1,4 @@ -package com.goi.erp.demo; +package com.goi.erp.controller; import io.swagger.v3.oas.annotations.Hidden; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/src/main/java/com/goi/erp/controller/CustomerController.java b/src/main/java/com/goi/erp/controller/CustomerController.java new file mode 100644 index 0000000..b450af5 --- /dev/null +++ b/src/main/java/com/goi/erp/controller/CustomerController.java @@ -0,0 +1,55 @@ +package com.goi.erp.controller; + +import com.goi.erp.dto.CustomerRequestDto; +import com.goi.erp.dto.CustomerResponseDto; +import com.goi.erp.service.CustomerService; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/customer") +@RequiredArgsConstructor +public class CustomerController { + + private final CustomerService customerService; + + // CREATE + @PostMapping + public ResponseEntity createCustomer(@RequestBody CustomerRequestDto requestDto) { + CustomerResponseDto responseDto = customerService.createCustomer(requestDto); + return new ResponseEntity<>(responseDto, HttpStatus.CREATED); + } + + // READ ALL + @GetMapping + public ResponseEntity> getAllCustomers() { + return ResponseEntity.ok(customerService.getAllCustomers()); + } + + // READ ONE + @GetMapping("/{uuid}") + public ResponseEntity getCustomer(@PathVariable UUID uuid) { + return ResponseEntity.ok(customerService.getCustomerByUuid(uuid)); + } + + // UPDATE + @PutMapping("/{uuid}") + public ResponseEntity updateCustomer( + @PathVariable UUID uuid, + @RequestBody CustomerRequestDto requestDto) { + return ResponseEntity.ok(customerService.updateCustomer(uuid, requestDto)); + } + + // DELETE + @DeleteMapping("/{uuid}") + public ResponseEntity deleteCustomer(@PathVariable UUID uuid) { + customerService.deleteCustomer(uuid); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/goi/erp/demo/DemoController.java b/src/main/java/com/goi/erp/demo/DemoController.java deleted file mode 100644 index 24b6cf0..0000000 --- a/src/main/java/com/goi/erp/demo/DemoController.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.goi.erp.demo; - -import io.swagger.v3.oas.annotations.Hidden; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/v1/demo-controller") -@Hidden -public class DemoController { - - @GetMapping - public ResponseEntity sayHello() { - return ResponseEntity.ok("Hello from secured endpoint"); - } - -} diff --git a/src/main/java/com/goi/erp/demo/ManagementController.java b/src/main/java/com/goi/erp/demo/ManagementController.java deleted file mode 100644 index c59d240..0000000 --- a/src/main/java/com/goi/erp/demo/ManagementController.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.goi.erp.demo; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/v1/management") -@Tag(name = "Management") -public class ManagementController { - - - @Operation( - description = "Get endpoint for manager", - summary = "This is a summary for management get endpoint", - responses = { - @ApiResponse( - description = "Success", - responseCode = "200" - ), - @ApiResponse( - description = "Unauthorized / Invalid Token", - responseCode = "403" - ) - } - - ) - @GetMapping - public String get() { - return "GET:: management controller"; - } - @PostMapping - public String post() { - return "POST:: management controller"; - } - @PutMapping - public String put() { - return "PUT:: management controller"; - } - @DeleteMapping - public String delete() { - return "DELETE:: management controller"; - } -} diff --git a/src/main/java/com/goi/erp/dto/CustomerRequestDto.java b/src/main/java/com/goi/erp/dto/CustomerRequestDto.java new file mode 100644 index 0000000..5a9f7b8 --- /dev/null +++ b/src/main/java/com/goi/erp/dto/CustomerRequestDto.java @@ -0,0 +1,30 @@ +package com.goi.erp.dto; + +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; + +@Data +public class CustomerRequestDto { + private String cusNo; + private String cusName; + private String cusStatus; + private Integer cusAreaId; + private String cusAddress1; + private String cusAddress2; + private String cusPostalCode; + private String cusCity; + private String cusProvince; + private BigDecimal cusGeoLat; + private BigDecimal cusGeoLon; + private String cusEmail; + private String cusPhone; + private String cusPhoneExt; + private LocalTime cusOpenTime; + private String cusNote; + private LocalDate cusContractDate; + private String cusContractedBy; + private LocalDate cusInstallDate; + private String cusInstallLocatoin; +} diff --git a/src/main/java/com/goi/erp/dto/CustomerResponseDto.java b/src/main/java/com/goi/erp/dto/CustomerResponseDto.java new file mode 100644 index 0000000..e012581 --- /dev/null +++ b/src/main/java/com/goi/erp/dto/CustomerResponseDto.java @@ -0,0 +1,34 @@ +package com.goi.erp.dto; + +import lombok.Builder; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.UUID; + +@Data +@Builder +public class CustomerResponseDto { + private UUID cusUuid; + private String cusNo; + private String cusName; + private String cusStatus; + private Integer cusAreaId; + private String cusAddress1; + private String cusAddress2; + private String cusPostalCode; + private String cusCity; + private String cusProvince; + private BigDecimal cusGeoLat; + private BigDecimal cusGeoLon; + private String cusEmail; + private String cusPhone; + private String cusPhoneExt; + private LocalTime cusOpenTime; + private String cusNote; + private LocalDate cusContractDate; + private String cusContractedBy; + private LocalDate cusInstallDate; + private String cusInstallLocatoin; +} diff --git a/src/main/java/com/goi/erp/employee/EmployeeDetails.java b/src/main/java/com/goi/erp/employee/EmployeeDetails.java deleted file mode 100644 index 888df71..0000000 --- a/src/main/java/com/goi/erp/employee/EmployeeDetails.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.goi.erp.employee; - -import lombok.Getter; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -@Getter -public class EmployeeDetails implements UserDetails { - // 이 UID는 객체를 직렬화 후 다시 역직렬화할 때, 클래스 버전이 맞는지 확인하는 용도 - private static final long serialVersionUID = 1L; - - private final Employee employee; - private final List authorities; - - public EmployeeDetails(Employee employee, List roles) { - this.employee = employee; - // EmployeeRole → GrantedAuthority 변환 - this.authorities = roles.stream() - .map(er -> new SimpleGrantedAuthority(er.getRoleInfo().getRoleName())) - .collect(Collectors.toList()); - } - - @Override - public Collection getAuthorities() { - return authorities; - } - - @Override - public String getPassword() { - return employee.getEmpLoginPassword(); - } - - @Override - public String getUsername() { - return employee.getEmpLoginId(); - } - - @Override - public boolean isAccountNonExpired() { - return true; // 필요에 따라 Employee 상태로 제어 가능 - } - - @Override - public boolean isAccountNonLocked() { - return !"I".equals(employee.getEmpStatus()); // 예: 'I'면 잠금 - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return "A".equals(employee.getEmpStatus()); // Active 상태만 사용 가능 - } -} diff --git a/src/main/java/com/goi/erp/employee/EmployeeDetailsService.java b/src/main/java/com/goi/erp/employee/EmployeeDetailsService.java deleted file mode 100644 index 1ec43a1..0000000 --- a/src/main/java/com/goi/erp/employee/EmployeeDetailsService.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.goi.erp.employee; - -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; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class EmployeeDetailsService implements UserDetailsService { - - private final EmployeeRepository employeeRepository; - private final EmployeeRoleRepository employeeRoleRepository; - - @Override - public UserDetails loadUserByUsername(String empLoginId) throws UsernameNotFoundException { - // Employee 조회 - Employee employee = employeeRepository.findByEmpLoginId(empLoginId) - .orElseThrow(() -> new UsernameNotFoundException("Employee not found")); - - // EmployeeRole 조회 (활성화된 역할만) - List roles = employeeRoleRepository.findActiveRolesByEmployeeId(employee.getEmpId()); - - // EmployeeDetails에 Employee + 역할 전달 - return new EmployeeDetails(employee, roles); - } -} diff --git a/src/main/java/com/goi/erp/employee/EmployeeRepository.java b/src/main/java/com/goi/erp/employee/EmployeeRepository.java deleted file mode 100644 index d671066..0000000 --- a/src/main/java/com/goi/erp/employee/EmployeeRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.goi.erp.employee; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; -import java.util.UUID; - -@Repository -public interface EmployeeRepository extends JpaRepository { - Optional findByEmpLoginId(String empLoginId); - Optional findByEmpUuid(UUID empUuid); -} \ No newline at end of file diff --git a/src/main/java/com/goi/erp/employee/EmployeeRole.java b/src/main/java/com/goi/erp/employee/EmployeeRole.java deleted file mode 100644 index 6f43600..0000000 --- a/src/main/java/com/goi/erp/employee/EmployeeRole.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.goi.erp.employee; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; - -import java.time.LocalDateTime; -import java.util.UUID; - -import com.goi.erp.role.RoleInfo; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "employee_role") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class EmployeeRole { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "emr_id") - private Integer emrId; // 내부 PK - - @Column(name = "emr_uuid", unique = true, nullable = false) - private UUID emrUuid; // 외부용 UUID - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "emr_emp_id", nullable = false) // DB 컬럼명 지정 - private Employee employee; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "emr_role_id", nullable = false) // DB 컬럼명 지정 - private RoleInfo roleInfo; - - @Column(name = "emr_revoked_at") - private LocalDateTime emrRevokedAt; -} - diff --git a/src/main/java/com/goi/erp/employee/EmployeeRoleRepository.java b/src/main/java/com/goi/erp/employee/EmployeeRoleRepository.java deleted file mode 100644 index 5bf3d3c..0000000 --- a/src/main/java/com/goi/erp/employee/EmployeeRoleRepository.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.goi.erp.employee; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface EmployeeRoleRepository extends JpaRepository { - - @Query(""" - SELECT er - FROM EmployeeRole er - WHERE er.employee.id = :empId - AND er.emrRevokedAt IS NULL - """) - List findActiveRolesByEmployeeId(Integer empId); -} \ No newline at end of file diff --git a/src/main/java/com/goi/erp/entity/Customer.java b/src/main/java/com/goi/erp/entity/Customer.java new file mode 100644 index 0000000..c923de9 --- /dev/null +++ b/src/main/java/com/goi/erp/entity/Customer.java @@ -0,0 +1,93 @@ +package com.goi.erp.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.UUID; + +@Entity +@Table(name = "customer") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Customer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer cusId; + + @Column(nullable = false, unique = true) + private UUID cusUuid; + + @Column(length = 50) + private String cusNo; + + @Column(nullable = false) + private String cusName; + + @Column(length = 1) + private String cusStatus; + + private Integer cusAreaId; + + private String cusAddress1; + private String cusAddress2; + private String cusPostalCode; + private String cusCity; + private String cusProvince; + + private BigDecimal cusGeoLat; + private BigDecimal cusGeoLon; + + private String cusEmail; + private String cusPhone; + private String cusPhoneExt; + + private LocalTime cusOpenTime; + private String cusNote; + + private LocalDate cusContractDate; + private String cusContractedBy; + + private LocalDate cusInstallDate; + private String cusInstallLocatoin; + + private LocalDate cusLastPickupDate; + private Integer cusLastPickupQty; + private BigDecimal cusLastPickupLat; + private BigDecimal cusLastPickupLon; + + private Integer cusFullCycle; + private Boolean cusFullCycleFlag; + private Integer cusFullCycleForced; + private LocalDate cusFullCycleForcedDate; + + private String cusSchedule; + private String cusScheduledays; + + private LocalDate cusLastPaidDate; + private BigDecimal cusRate; + private String cusPayMethod; + private String cusAccountNo; + + private LocalDate cusIsccDate; + private LocalDate cusCorsiaDate; + + private String cusHstNo; + + private LocalDate cusTerminatedDate; + private String cusTerminationReason; +} diff --git a/src/main/java/com/goi/erp/employee/Employee.java b/src/main/java/com/goi/erp/entity/Employee.java similarity index 69% rename from src/main/java/com/goi/erp/employee/Employee.java rename to src/main/java/com/goi/erp/entity/Employee.java index e4bb169..4799b24 100644 --- a/src/main/java/com/goi/erp/employee/Employee.java +++ b/src/main/java/com/goi/erp/entity/Employee.java @@ -1,4 +1,4 @@ -package com.goi.erp.employee; +package com.goi.erp.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -28,22 +28,10 @@ public class Employee { @Column(name = "emp_uuid", unique = true, nullable = false) private UUID empUuid; // 외부 키로 사용 - @Column(name = "emp_login_id", unique = true, nullable = false) - private String empLoginId; - - @Column(name = "emp_login_password", nullable = false) - private String empLoginPassword; - @Column(name = "emp_first_name") private String empFirstName; @Column(name = "emp_last_name") private String empLastName; - - @Column(name = "emp_dept_id") - private Integer empDeptId; - - @Column(name = "emp_status", columnDefinition = "CHAR(1)") - private String empStatus; } diff --git a/src/main/java/com/goi/erp/permission/PermissionInfo.java b/src/main/java/com/goi/erp/permission/PermissionInfo.java deleted file mode 100644 index 0b9e865..0000000 --- a/src/main/java/com/goi/erp/permission/PermissionInfo.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.goi.erp.permission; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; - -import java.util.UUID; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "permission_info", - uniqueConstraints = @UniqueConstraint(columnNames = {"perm_module", "perm_action", "perm_scope"})) -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class PermissionInfo { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "perm_id") - private Integer permId; - - @Column(name = "perm_uuid", nullable = false, updatable = false) - private UUID permUuid; - - @Column(name = "perm_module", nullable = false) - private String permModule; - - @Column(name = "perm_action", nullable = false, length = 1) - private String permAction; // C/R/U/D - - @Column(name = "perm_scope", nullable = false, length = 10) - private String permScope; // Self / Part / All - - @Column(name = "perm_desc") - private String permDesc; - -} diff --git a/src/main/java/com/goi/erp/permission/PermissionInfoRepository.java b/src/main/java/com/goi/erp/permission/PermissionInfoRepository.java deleted file mode 100644 index 95334dd..0000000 --- a/src/main/java/com/goi/erp/permission/PermissionInfoRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.goi.erp.permission; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; -import java.util.UUID; - -@Repository -public interface PermissionInfoRepository extends JpaRepository { - Optional findByPermUuid(UUID permUuid); - - // 특정 모듈 + 액션 + 범위에 해당하는 권한 조회 - Optional findByPermModuleAndPermActionAndPermScope(String module, String action, String scope); -} \ No newline at end of file diff --git a/src/main/java/com/goi/erp/repository/CustomerRepository.java b/src/main/java/com/goi/erp/repository/CustomerRepository.java new file mode 100644 index 0000000..ec7b37f --- /dev/null +++ b/src/main/java/com/goi/erp/repository/CustomerRepository.java @@ -0,0 +1,13 @@ +package com.goi.erp.repository; + +import com.goi.erp.entity.Customer; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface CustomerRepository extends JpaRepository { + Optional findByCusUuid(UUID uuid); +} diff --git a/src/main/java/com/goi/erp/role/RoleInfo.java b/src/main/java/com/goi/erp/role/RoleInfo.java deleted file mode 100644 index 786400b..0000000 --- a/src/main/java/com/goi/erp/role/RoleInfo.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.goi.erp.role; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; - -import java.util.List; -import java.util.UUID; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "role_info") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class RoleInfo { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "role_id") - private Integer roleId; - - @Column(name = "role_uuid", unique = true, nullable = false) - private UUID roleUuid; - - @Column(name = "role_name", unique = true, nullable = false) - private String roleName; - - @Column(name = "role_desc") - private String roleDesc; - - @Column(name = "role_level") - private Integer roleLevel; - - @OneToMany(mappedBy = "roleInfo", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List rolePermissions; - -} diff --git a/src/main/java/com/goi/erp/role/RoleInfoRepository.java b/src/main/java/com/goi/erp/role/RoleInfoRepository.java deleted file mode 100644 index f1d6b77..0000000 --- a/src/main/java/com/goi/erp/role/RoleInfoRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.goi.erp.role; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; -import java.util.UUID; - -@Repository -public interface RoleInfoRepository extends JpaRepository { - Optional findByRoleUuid(UUID roleUuid); - - Optional findByRoleName(String roleName); -} \ No newline at end of file diff --git a/src/main/java/com/goi/erp/role/RolePermission.java b/src/main/java/com/goi/erp/role/RolePermission.java deleted file mode 100644 index 14d5b0e..0000000 --- a/src/main/java/com/goi/erp/role/RolePermission.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.goi.erp.role; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; - -import com.goi.erp.permission.PermissionInfo; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "role_permission") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class RolePermission { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "rpr_id") - private Integer id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rpr_role_id", nullable = false) - private RoleInfo roleInfo; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rpr_perm_id", nullable = false) - private PermissionInfo permissionInfo; - -} diff --git a/src/main/java/com/goi/erp/role/RolePermissionRepository.java b/src/main/java/com/goi/erp/role/RolePermissionRepository.java deleted file mode 100644 index cd00556..0000000 --- a/src/main/java/com/goi/erp/role/RolePermissionRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.goi.erp.role; - -import java.util.List; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -@Repository -public interface RolePermissionRepository extends JpaRepository { - - // 특정 Role의 모든 권한 조회 - @Query("SELECT r FROM RolePermission r WHERE r.roleInfo.id = :roleId") - List findByRoleId(@Param("roleId") Integer roleId); - - // Role과 Permission 매핑 존재 여부 확인 - @Query(""" - SELECT CASE WHEN COUNT(r) > 0 THEN true ELSE false END - FROM RolePermission r - WHERE r.roleInfo.id = :roleId - AND r.permissionInfo.id = :permId - """) - boolean existsByRoleInfoAndPermissionInfo(@Param("roleId") Integer roleId, - @Param("permId") Integer permId); -} \ No newline at end of file diff --git a/src/main/java/com/goi/erp/service/CustomerService.java b/src/main/java/com/goi/erp/service/CustomerService.java new file mode 100644 index 0000000..f76b4b8 --- /dev/null +++ b/src/main/java/com/goi/erp/service/CustomerService.java @@ -0,0 +1,77 @@ +package com.goi.erp.service; + +import com.goi.erp.dto.CustomerRequestDto; +import com.goi.erp.dto.CustomerResponseDto; +import com.goi.erp.entity.Customer; +import com.goi.erp.repository.CustomerRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class CustomerService { + + private final CustomerRepository customerRepository; + + public CustomerResponseDto createCustomer(CustomerRequestDto dto) { + Customer customer = Customer.builder() + .cusUuid(UUID.randomUUID()) + .cusName(dto.getCusName()) + .cusNo(dto.getCusNo()) + .cusStatus(dto.getCusStatus()) + .cusAddress1(dto.getCusAddress1()) + .cusAddress2(dto.getCusAddress2()) + .cusCity(dto.getCusCity()) + .cusProvince(dto.getCusProvince()) + .build(); + customer = customerRepository.save(customer); + return mapToDto(customer); + } + + public List getAllCustomers() { + return customerRepository.findAll().stream() + .map(this::mapToDto) + .collect(Collectors.toList()); + } + + public CustomerResponseDto getCustomerByUuid(UUID uuid) { + Customer customer = customerRepository.findByCusUuid(uuid) + .orElseThrow(() -> new RuntimeException("Customer not found")); + return mapToDto(customer); + } + + public CustomerResponseDto updateCustomer(UUID uuid, CustomerRequestDto dto) { + Customer customer = customerRepository.findByCusUuid(uuid) + .orElseThrow(() -> new RuntimeException("Customer not found")); + + customer.setCusName(dto.getCusName()); + customer.setCusNo(dto.getCusNo()); + customer.setCusStatus(dto.getCusStatus()); + customer.setCusAddress1(dto.getCusAddress1()); + customer.setCusAddress2(dto.getCusAddress2()); + customer.setCusCity(dto.getCusCity()); + customer.setCusProvince(dto.getCusProvince()); + + customerRepository.save(customer); + return mapToDto(customer); + } + + public void deleteCustomer(UUID uuid) { + Customer customer = customerRepository.findByCusUuid(uuid) + .orElseThrow(() -> new RuntimeException("Customer not found")); + customerRepository.delete(customer); + } + + private CustomerResponseDto mapToDto(Customer customer) { + return CustomerResponseDto.builder() + .cusUuid(customer.getCusUuid()) + .cusName(customer.getCusName()) + .cusNo(customer.getCusNo()) + .cusStatus(customer.getCusStatus()) + .build(); + } +} diff --git a/src/main/java/com/goi/erp/token/ApplicationAuditAware.java b/src/main/java/com/goi/erp/token/ApplicationAuditAware.java new file mode 100644 index 0000000..feb95f1 --- /dev/null +++ b/src/main/java/com/goi/erp/token/ApplicationAuditAware.java @@ -0,0 +1,85 @@ +package com.goi.erp.token; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import org.springframework.data.domain.AuditorAware; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import jakarta.servlet.http.HttpServletRequest; +import java.nio.charset.StandardCharsets; +import java.util.Optional; + +/** + * auth-service에서 발급한 JWT 토큰 기반으로 현재 사용자(empId)를 가져오는 AuditorAware 구현체 + * + * - JPA auditing에서 사용자가 누군지 기록할 때 사용 + * - SecurityContextHolder 없이도 동작 가능 + * - HttpServletRequest에서 Authorization 헤더를 읽어 토큰 파싱 + */ +public class ApplicationAuditAware implements AuditorAware { + + private final String jwtSecret; + + public ApplicationAuditAware(String jwtSecret) { + this.jwtSecret = jwtSecret; + } + + /** + * 현재 요청을 수행하는 사용자의 empId 반환 + * @return Optional - empId가 없거나 토큰이 유효하지 않으면 Optional.empty() + */ + @Override + public Optional getCurrentAuditor() { + HttpServletRequest request = getCurrentHttpRequest(); + if (request == null) { + return Optional.empty(); + } + + String token = resolveToken(request); + if (token == null) { + return Optional.empty(); + } + + try { + // JWT 파싱 + Claims claims = Jwts.parserBuilder() + // HMAC SHA 키 객체 생성 (secret 길이와 안전성 체크) + .setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8))) + .build() + .parseClaimsJws(token) + .getBody(); + + // 토큰에 empId 클레임이 있어야 함 + Integer empId = claims.get("empId", Integer.class); + return Optional.ofNullable(empId); + } catch (Exception e) { + // 토큰 파싱/검증 실패 시 Optional.empty() 반환 + return Optional.empty(); + } + } + + /** + * 현재 스레드의 HttpServletRequest 가져오기 + * @return HttpServletRequest 또는 null + */ + private HttpServletRequest getCurrentHttpRequest() { + ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attrs == null) return null; + return attrs.getRequest(); + } + + /** + * HttpServletRequest에서 Authorization 헤더의 Bearer 토큰 추출 + * @param request 현재 HttpServletRequest + * @return JWT 문자열 또는 null + */ + private String resolveToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (bearerToken != null && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/src/main/java/com/goi/erp/token/JwtService.java b/src/main/java/com/goi/erp/token/JwtService.java new file mode 100644 index 0000000..8f81697 --- /dev/null +++ b/src/main/java/com/goi/erp/token/JwtService.java @@ -0,0 +1,129 @@ +package com.goi.erp.token; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.security.Key; +import java.util.List; +import java.util.function.Function; + +/** + * - DB 접근 없음 + * - JWT에 포함된 empUuid, 이름, roles, permissions 추출 + * - 토큰 유효기간 체크 가능 + */ +@Service +public class JwtService { + + @Value("${application.security.jwt.secret-key}") + private String secretKey; + + @Value("${application.security.jwt.expiration}") + private long jwtExpiration; + + /** + * empUuid(sub) 추출 + */ + public String extractEmpUuid(String token) { + return extractClaim(token, Claims::getSubject); + } + + /** + * firstName 추출 + */ + public String extractFirstName(String token) { + return extractClaim(token, claims -> claims.get("firstName", String.class)); + } + + /** + * lastName 추출 + */ + public String extractLastName(String token) { + return extractClaim(token, claims -> claims.get("lastName", String.class)); + } + + /** + * roles 리스트 추출 + */ + @SuppressWarnings("unchecked") + public List extractRoles(String token) { + return extractClaim(token, claims -> (List) claims.get("roles")); + } + + /** + * permissions 리스트 추출 + */ + @SuppressWarnings("unchecked") + public List extractPermissions(String token) { + return extractClaim(token, claims -> (List) claims.get("permissions")); + } + + /** + * 토큰 만료 여부 확인 + */ + public boolean isTokenExpired(String token) { + return extractClaim(token, Claims::getExpiration).before(new java.util.Date()); + } + + /** + * 토큰 유효성 검사 (만료 체크) + */ + public boolean isTokenValid(String token) { + return !isTokenExpired(token); + } + + /** + * JWT에서 Claims 추출 + */ + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + /** + * JWT 전체 Claims 추출 + */ + private Claims extractAllClaims(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSignInKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + private Key getSignInKey() { + byte[] keyBytes = Decoders.BASE64.decode(secretKey); // auth-service와 동일한 Base64 secret + return Keys.hmacShaKeyFor(keyBytes); + } + + public static void main(String[] args) { + JwtService jwtService = new JwtService(); + jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8="; + + String token = "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdE5hbWUiOiJIeW9KaW4iLCJsYXN0TmFtZSI6IkFobiIsInBlcm1pc3Npb25zIjpbIkFMTCJdLCJyb2xlcyI6WyJBZG1pbiJdLCJzdWIiOiJhMjM4ZWQ0OC03OGRjLTQ2YWEtOWNiMC1hNWYxZGQyZDJmMTMiLCJpYXQiOjE3NjM1NzE2ODYsImV4cCI6MTc2MzY1ODA4Nn0.0fQT-I4dqHMapIEbxfy8X_SdCReYhUy6djnXUzw4gWc"; + + // user 정보 + Claims claims = jwtService.extractAllClaims(token); + + System.out.println("Subject (emp_uuid): " + claims.getSubject()); + System.out.println("Roles: " + claims.get("roles")); + System.out.println("Roles: " + claims.get("permissions")); + System.out.println("IssuedAt: " + claims.getIssuedAt()); + System.out.println("Expiration: " + claims.getExpiration()); + System.out.println("FirstName: " + claims.get("firstName", String.class)); + System.out.println("LastName: " + claims.get("LastName", String.class)); + + // 모든 Claims 확인 +// Claims claims = Jwts.parserBuilder() +// .setSigningKey(Keys.hmacShaKeyFor("".getBytes())) +// .build() +// .parseClaimsJws(token) +// .getBody(); + + System.out.println("Claims: " + claims); + } +} diff --git a/src/main/java/com/goi/erp/token/Token.java b/src/main/java/com/goi/erp/token/Token.java deleted file mode 100644 index 1551330..0000000 --- a/src/main/java/com/goi/erp/token/Token.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.goi.erp.token; - -import com.goi.erp.employee.Employee; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "employee_token") -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class Token { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "emt_id") - private Integer id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "emt_emp_id", nullable = false) - private Employee employee; - - @Column(name = "emt_token", nullable = false) - private String token; - - @Enumerated(EnumType.STRING) - @Column(name = "emt_token_type") - private TokenType tokenType; - - @Column(name = "emt_is_expired") - private boolean expired; - - @Column(name = "emt_is_revoked") - private boolean revoked; -} diff --git a/src/main/java/com/goi/erp/token/TokenRepository.java b/src/main/java/com/goi/erp/token/TokenRepository.java deleted file mode 100644 index 01e2788..0000000 --- a/src/main/java/com/goi/erp/token/TokenRepository.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.goi.erp.token; - -import com.goi.erp.employee.Employee; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; - -import java.util.List; -import java.util.Optional; - -public interface TokenRepository extends JpaRepository { - - @Query(""" - select t from Token t - where t.employee.id = :employeeId - and (t.expired = false or t.revoked = false) - """) - List findAllValidTokenByEmployee(Integer employeeId); - - Optional findByToken(String token); - - List findByEmployee(Employee employee); -} diff --git a/src/main/java/com/goi/erp/token/TokenType.java b/src/main/java/com/goi/erp/token/TokenType.java deleted file mode 100644 index d062f85..0000000 --- a/src/main/java/com/goi/erp/token/TokenType.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.goi.erp.token; - -public enum TokenType { - BEARER -} diff --git a/src/main/java/com/goi/erp/user/ChangePasswordRequest.java b/src/main/java/com/goi/erp/user/ChangePasswordRequest.java deleted file mode 100644 index fbee5c1..0000000 --- a/src/main/java/com/goi/erp/user/ChangePasswordRequest.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.goi.erp.user; - -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@Builder -public class ChangePasswordRequest { - - private String currentPassword; - private String newPassword; - private String confirmationPassword; -} diff --git a/src/main/java/com/goi/erp/user/Permission.java b/src/main/java/com/goi/erp/user/Permission.java deleted file mode 100644 index 99fef3f..0000000 --- a/src/main/java/com/goi/erp/user/Permission.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.goi.erp.user; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public enum Permission { - - ADMIN_READ("admin:read"), - ADMIN_UPDATE("admin:update"), - ADMIN_CREATE("admin:create"), - ADMIN_DELETE("admin:delete"), - MANAGER_READ("management:read"), - MANAGER_UPDATE("management:update"), - MANAGER_CREATE("management:create"), - MANAGER_DELETE("management:delete") - - ; - - @Getter - private final String permission; -} diff --git a/src/main/java/com/goi/erp/user/Role.java b/src/main/java/com/goi/erp/user/Role.java deleted file mode 100644 index 439dd14..0000000 --- a/src/main/java/com/goi/erp/user/Role.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.goi.erp.user; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -import static com.goi.erp.user.Permission.ADMIN_CREATE; -import static com.goi.erp.user.Permission.ADMIN_DELETE; -import static com.goi.erp.user.Permission.ADMIN_READ; -import static com.goi.erp.user.Permission.ADMIN_UPDATE; -import static com.goi.erp.user.Permission.MANAGER_CREATE; -import static com.goi.erp.user.Permission.MANAGER_DELETE; -import static com.goi.erp.user.Permission.MANAGER_READ; -import static com.goi.erp.user.Permission.MANAGER_UPDATE; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@RequiredArgsConstructor -public enum Role { - - USER(Collections.emptySet()), - ADMIN( - Set.of( - ADMIN_READ, - ADMIN_UPDATE, - ADMIN_DELETE, - ADMIN_CREATE, - MANAGER_READ, - MANAGER_UPDATE, - MANAGER_DELETE, - MANAGER_CREATE - ) - ), - MANAGER( - Set.of( - MANAGER_READ, - MANAGER_UPDATE, - MANAGER_DELETE, - MANAGER_CREATE - ) - ) - - ; - - @Getter - private final Set permissions; - - public List getAuthorities() { - var authorities = getPermissions() - .stream() - .map(permission -> new SimpleGrantedAuthority(permission.getPermission())) - .collect(Collectors.toList()); - authorities.add(new SimpleGrantedAuthority("ROLE_" + this.name())); - return authorities; - } -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 68daa74..65aeaac 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,7 +13,8 @@ spring: format_sql: true database: postgresql database-platform: org.hibernate.dialect.PostgreSQLDialect - + autoconfigure: + exclude: org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration application: security: jwt: @@ -22,6 +23,6 @@ application: refresh-token: expiration: 604800000 # 7 days server: - port: 8080 + port: 8082 servlet: - context-path: /auth-service \ No newline at end of file + context-path: /crm-rest-api \ No newline at end of file