From d1a4587c218cd6cf9de3d65f149aab8474c5c2ff Mon Sep 17 00:00:00 2001 From: pgsshiho Date: Thu, 6 Mar 2025 17:48:05 +0900 Subject: [PATCH 1/5] task1-2 --- .../auth/Controller/newsignController.java | 61 ++++++++++++++++ .../task12/domain/auth/Entity/NewSign.java | 28 ++++++++ .../task12/domain/auth/HTML/login.html | 18 +++++ .../task12/domain/auth/HTML/signup.html | 19 +++++ .../auth/Repository/UserRepository.java | 10 +++ .../domain/auth/Service/newsignService.java | 64 +++++++++++++++++ .../domain/auth/dto/UserLoginRequest.java | 12 ++++ .../domain/auth/dto/UserSignupRequest.java | 24 +++++++ .../security/JwtAuthenticationFilter.java | 48 +++++++++++++ .../global/security/JwtTokenService.java | 71 +++++++++++++++++++ .../task12/global/security/SecretKey.java | 5 ++ .../global/security/SecurityConfig.java | 40 ++++++----- .../task12/global/security/TokenResponse.java | 11 +++ 13 files changed, 393 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Entity/NewSign.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserLoginRequest.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserSignupRequest.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtTokenService.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/global/security/TokenResponse.java diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java new file mode 100644 index 0000000..8cf5eab --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java @@ -0,0 +1,61 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Controller; + +import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/user") +@RequiredArgsConstructor +public class newsignController { + + private final newsignService authService; + private final UserRepository userRepository; + @PostMapping("/signup") + public ResponseEntity signup(@RequestBody UserSignupRequest request) { + authService.signup(request); + return ResponseEntity.ok("회원가입 성공"); + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody UserLoginRequest request) { + TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); + + if (tokenResponse != null) { + return ResponseEntity.ok(tokenResponse); + } else { + return ResponseEntity.status(401).body("로그인 실패: 아이디 또는 비밀번호가 잘못되었습니다."); + } + } + + @PostMapping("/refresh") + public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { + TokenResponse newTokens = authService.refreshToken(refreshToken); + + if (newTokens != null) { + return ResponseEntity.ok(newTokens); + } else { + return ResponseEntity.status(403).body("유효하지 않은 리프레시 토큰입니다."); + } + } + @DeleteMapping("/delete") + public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { + TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); + + if (tokenResponse != null) { + return userRepository.findByUsername(request.getUsername()) + .map(user -> { + userRepository.delete(user); + return ResponseEntity.ok("계정 삭제 완료"); + }) + .orElse(ResponseEntity.status(404).body("사용자를 찾을 수 없습니다.")); + } else { + return ResponseEntity.status(401).body("로그인 실패: 아이디 또는 비밀번호가 잘못되었습니다."); + } + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Entity/NewSign.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Entity/NewSign.java new file mode 100644 index 0000000..e8181e3 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Entity/NewSign.java @@ -0,0 +1,28 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Entity +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Table(name = "new_sign") +public class NewSign { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String username; + private String password; + private String role; + private String email; +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html new file mode 100644 index 0000000..8ef8b19 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html @@ -0,0 +1,18 @@ + + + + 로그인 + + +

로그인

+
+ + +
+ + +
+ +
+ + diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html new file mode 100644 index 0000000..9aa53a8 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html @@ -0,0 +1,19 @@ + + + + 회원가입 + + +

회원가입

+
+ + +
+ + +
+ +
+로그인 + + diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java new file mode 100644 index 0000000..551392a --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java @@ -0,0 +1,10 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Repository; + +import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + Optional findByUsername(String username); +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java new file mode 100644 index 0000000..ccb349a --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java @@ -0,0 +1,64 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; +import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; +import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class newsignService { + + private final UserRepository userRepository; + private final JwtTokenService jwtTokenService; + private final PasswordEncoder passwordEncoder; + + @Transactional + public void signup(UserSignupRequest request) { + if (userRepository.findByUsername(request.getUsername()).isPresent()) { + throw new RuntimeException("이미 존재하는 사용자입니다."); + } + NewSign newUser = NewSign.builder() + .username(request.getUsername()) + .password(passwordEncoder.encode(request.getPassword())) + .email(request.getEmail()) + .role("ROLE_USER") + .build(); + userRepository.save(newUser); + } + + // 로그인 + public TokenResponse login(String username, String rawPassword) { + Optional userOptional = userRepository.findByUsername(username); + if (userOptional.isPresent()) { + NewSign user = userOptional.get(); + if (passwordEncoder.matches(rawPassword, user.getPassword())) { + String accessToken = jwtTokenService.createAccessToken(username); + String refreshToken = jwtTokenService.createRefreshToken(username); + return new TokenResponse(accessToken, refreshToken); + } + } + return null; // 로그인 실패 + } + // 리프레시 토큰을 통한 JWT 재발급 + public TokenResponse refreshToken(String refreshToken) { + String username = jwtTokenService.getUsernameFromToken(refreshToken); + + if (username != null && jwtTokenService.validateRefreshToken(username, refreshToken)) { + jwtTokenService.revokeRefreshToken(username); // 기존 리프레시 토큰 폐기 Refresh Token Rotation 적용 + + String newAccessToken = jwtTokenService.createAccessToken(username); + String newRefreshToken = jwtTokenService.createRefreshToken(username); + + return new TokenResponse(newAccessToken, newRefreshToken); + } + return null; + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserLoginRequest.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserLoginRequest.java new file mode 100644 index 0000000..9708797 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserLoginRequest.java @@ -0,0 +1,12 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter + +public class UserLoginRequest { + private String username; + private String password; +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserSignupRequest.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserSignupRequest.java new file mode 100644 index 0000000..68cd5d1 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/dto/UserSignupRequest.java @@ -0,0 +1,24 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class UserSignupRequest { + + @NotBlank(message = "사용자 이름은 필수 입력값입니다.") + @Size(min = 3, max = 20, message = "사용자 이름은 3~20자로 입력해야 합니다.") + private String username; + + @NotBlank(message = "비밀번호는 필수 입력값입니다.") + @Size(min = 6, message = "비밀번호는 최소 6자 이상이어야 합니다.") + private String password; + + @NotBlank(message = "이메일은 필수 입력값입니다.") + @Email(message = "올바른 이메일 형식을 입력해주세요.") + private String email; +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..cb70215 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java @@ -0,0 +1,48 @@ +package com.gsm._8th.class4.backend.task12.global.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final JwtTokenService jwtTokenService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + String token = request.getHeader("Authorization"); + + if (token != null && token.startsWith("Bearer ")) { + token = token.substring(7); + if (jwtTokenService.validateToken(token)) { + String username = jwtTokenService.getUsernameFromToken(token); + + // UserDetails 객체 생성 + UserDetails userDetails = User.withUsername(username) + .password("") // JWT는 비밀번호를 검증하지 않음 + .authorities("ROLE_USER") // 기본 역할 부여 + .build(); + + // 인증 객체 생성 + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + // Spring Security 컨텍스트에 저장 + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtTokenService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtTokenService.java new file mode 100644 index 0000000..339deb8 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtTokenService.java @@ -0,0 +1,71 @@ +package com.gsm._8th.class4.backend.task12.global.security; + +import io.jsonwebtoken.*; +import io.jsonwebtoken.security.Keys; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Service +public class JwtTokenService { + + @Value("${jwt.secret}") + private String secretKey; + + private final long accessTokenValidity = 60 * 60 * 1000L; + private final long refreshTokenValidity = 120 * 60 * 1000L; + private final ConcurrentHashMap refreshTokenStore = new ConcurrentHashMap<>(); + private Key getSigningKey() { + return Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); + } + public String createAccessToken(String username) { + return createToken(username, accessTokenValidity); + } + public String createRefreshToken(String username) { + String refreshToken = createToken(username, refreshTokenValidity); + refreshTokenStore.put(username, refreshToken); + return refreshToken; + } + private String createToken(String subject, long validity) { + Date now = new Date(); + return Jwts.builder() + .setSubject(subject) + .setIssuedAt(now) + .setExpiration(new Date(now.getTime() + validity)) + .signWith(getSigningKey(), SignatureAlgorithm.HS256) // 변경됨 + .compact(); + } + public boolean validateToken(String token) { + try { + Jws claims = Jwts.parser() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); // 만료 확인 + } catch (JwtException | IllegalArgumentException e) { + log.error("유효하지 않은 토큰: {}", e.getMessage()); + return false; + } + } + public String getUsernameFromToken(String token) { + return Jwts.parser() // 변경됨 + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody() + .getSubject(); + } + public boolean validateRefreshToken(String username, String refreshToken) { + return refreshToken.equals(refreshTokenStore.get(username)); + } + public void revokeRefreshToken(String username) { + refreshTokenStore.remove(username); + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java new file mode 100644 index 0000000..19a3fd5 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java @@ -0,0 +1,5 @@ +package com.gsm._8th.class4.backend.task12.global.security; + +public class SecretKey { + public static String JWT_SECRET_KEY = "236979CB6F1AD6B6A6184A31E6BE37DB3818CC36871E26235DD67DCFE4041492"; +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java index 457a7f7..216a5f2 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java @@ -1,35 +1,39 @@ package com.gsm._8th.class4.backend.task12.global.security; +import lombok.RequiredArgsConstructor; 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.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.stereotype.Component; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -@Component -@EnableWebSecurity +@Configuration +@RequiredArgsConstructor public class SecurityConfig { - /* - TODO: 해당 클래스를 수정하여주세요! - */ + private final JwtTokenService jwtTokenService; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .cors(AbstractHttpConfigurer::disable) - .csrf(AbstractHttpConfigurer::disable) - .authorizeHttpRequests((authorize) -> { - authorize.anyRequest().permitAll(); - }) - .formLogin(AbstractHttpConfigurer::disable) - .sessionManagement((sessionManagement) -> { - sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS); - }) - .httpBasic(AbstractHttpConfigurer::disable); + .csrf(csrf -> csrf.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/api/user/**").permitAll() + .requestMatchers("/api/v1/order/**").authenticated() + .anyRequest().permitAll() + ) + // 필터 추가 시 순서 지정 (기존 addFilter() → addFilterBefore()로 변경) + .addFilterBefore(new JwtAuthenticationFilter(jwtTokenService), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); } } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/TokenResponse.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/TokenResponse.java new file mode 100644 index 0000000..84a80a7 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/TokenResponse.java @@ -0,0 +1,11 @@ +package com.gsm._8th.class4.backend.task12.global.security; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class TokenResponse { + private final String accessToken; + private final String refreshToken; +} From 00fc3adc8447aae00120051cfe914cc5b187237b Mon Sep 17 00:00:00 2001 From: pgsshiho Date: Wed, 12 Mar 2025 11:40:37 +0900 Subject: [PATCH 2/5] task1-2 --- .../auth/Controller/newsignController.java | 43 +++++++++++-------- .../task12/domain/auth/HTML/login.html | 18 -------- .../task12/domain/auth/HTML/signup.html | 19 -------- .../domain/auth/Service/newsignService.java | 31 +++++++++---- .../task12/global/security/SecretKey.java | 5 --- 5 files changed, 46 insertions(+), 70 deletions(-) delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java index 8cf5eab..ec1dcf9 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java @@ -1,6 +1,5 @@ package com.gsm._8th.class4.backend.task12.domain.auth.Controller; -import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; @@ -15,47 +14,53 @@ public class newsignController { private final newsignService authService; - private final UserRepository userRepository; + @PostMapping("/signup") public ResponseEntity signup(@RequestBody UserSignupRequest request) { authService.signup(request); return ResponseEntity.ok("회원가입 성공"); } - @PostMapping("/login") - public ResponseEntity login(@RequestBody UserLoginRequest request) { + @PostMapping("/api/v1/order/{orderId}/login") + public ResponseEntity login(@RequestBody UserLoginRequest request) { + TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); + + if (tokenResponse != null) { + return ResponseEntity.ok(tokenResponse); + } else { + return ResponseEntity.status(401).body(null); + } + } + + @PostMapping("/api/v1/order/search/login") + public ResponseEntity login2(@RequestBody UserLoginRequest request) { TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); if (tokenResponse != null) { return ResponseEntity.ok(tokenResponse); } else { - return ResponseEntity.status(401).body("로그인 실패: 아이디 또는 비밀번호가 잘못되었습니다."); + return ResponseEntity.status(401).body(null); } } @PostMapping("/refresh") - public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { + public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { TokenResponse newTokens = authService.refreshToken(refreshToken); if (newTokens != null) { return ResponseEntity.ok(newTokens); } else { - return ResponseEntity.status(403).body("유효하지 않은 리프레시 토큰입니다."); + return ResponseEntity.status(403).body(null); } } - @DeleteMapping("/delete") - public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { - TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); - if (tokenResponse != null) { - return userRepository.findByUsername(request.getUsername()) - .map(user -> { - userRepository.delete(user); - return ResponseEntity.ok("계정 삭제 완료"); - }) - .orElse(ResponseEntity.status(404).body("사용자를 찾을 수 없습니다.")); - } else { - return ResponseEntity.status(401).body("로그인 실패: 아이디 또는 비밀번호가 잘못되었습니다."); + @DeleteMapping("/delete") + public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { + try { + authService.deleteUser(request.getUsername()); + return ResponseEntity.ok("계정 삭제 완료"); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(404).body(e.getMessage()); } } } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html deleted file mode 100644 index 8ef8b19..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/login.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - 로그인 - - -

로그인

-
- - -
- - -
- -
- - diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html deleted file mode 100644 index 9aa53a8..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/HTML/signup.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - 회원가입 - - -

회원가입

-
- - -
- - -
- -
-로그인 - - diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java index ccb349a..d744b32 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java @@ -37,28 +37,41 @@ public void signup(UserSignupRequest request) { // 로그인 public TokenResponse login(String username, String rawPassword) { Optional userOptional = userRepository.findByUsername(username); + if (userOptional.isPresent()) { NewSign user = userOptional.get(); if (passwordEncoder.matches(rawPassword, user.getPassword())) { String accessToken = jwtTokenService.createAccessToken(username); String refreshToken = jwtTokenService.createRefreshToken(username); return new TokenResponse(accessToken, refreshToken); + } else { + throw new IllegalArgumentException("비밀번호 또는 사용자 이름이 틀립니다!"); } } - return null; // 로그인 실패 + + throw new IllegalArgumentException("해당 사용자 이름을 찾을 수 없습니다!"); } + // 리프레시 토큰을 통한 JWT 재발급 public TokenResponse refreshToken(String refreshToken) { String username = jwtTokenService.getUsernameFromToken(refreshToken); + if (username == null || !jwtTokenService.validateRefreshToken(username, refreshToken)) { + throw new IllegalArgumentException("유효하지 않은 리프레시 토큰입니다."); + } + jwtTokenService.revokeRefreshToken(username); + String newAccessToken = jwtTokenService.createAccessToken(username); + String newRefreshToken = jwtTokenService.createRefreshToken(username); + return new TokenResponse(newAccessToken, newRefreshToken); + } - if (username != null && jwtTokenService.validateRefreshToken(username, refreshToken)) { - jwtTokenService.revokeRefreshToken(username); // 기존 리프레시 토큰 폐기 Refresh Token Rotation 적용 - - String newAccessToken = jwtTokenService.createAccessToken(username); - String newRefreshToken = jwtTokenService.createRefreshToken(username); - - return new TokenResponse(newAccessToken, newRefreshToken); + // 사용자 삭제 (서비스를 통해 처리) + @Transactional + public void deleteUser(String username) { + Optional userOptional = userRepository.findByUsername(username); + if (userOptional.isPresent()) { + userRepository.delete(userOptional.get()); + } else { + throw new IllegalArgumentException("사용자를 찾을 수 없습니다."); } - return null; } } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java deleted file mode 100644 index 19a3fd5..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecretKey.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gsm._8th.class4.backend.task12.global.security; - -public class SecretKey { - public static String JWT_SECRET_KEY = "236979CB6F1AD6B6A6184A31E6BE37DB3818CC36871E26235DD67DCFE4041492"; -} From a892f910fda5ba3a86ed264385c259588a9d0d57 Mon Sep 17 00:00:00 2001 From: pgsshiho Date: Wed, 12 Mar 2025 14:42:00 +0900 Subject: [PATCH 3/5] feedback,but I don't know about I clear the first feedback --- .../auth/Controller/newsignController.java | 52 +++---------------- .../Controller/newsigndeleteController.java | 27 ++++++++++ .../Controller/newsignloginController.java | 27 ++++++++++ .../newsignloginsearchController.java | 28 ++++++++++ .../Controller/newsignrefreshController.java | 28 ++++++++++ .../domain/auth/Service/newsignService.java | 1 + .../security/JwtAuthenticationFilter.java | 38 ++++++++------ .../global/security/SecurityConfig.java | 41 +++++++++------ 8 files changed, 163 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java index ec1dcf9..eafb193 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java @@ -8,59 +8,21 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.net.URI; +import java.net.URISyntaxException; + @RestController -@RequestMapping("/api/user") +@RequestMapping("/api/v1") @RequiredArgsConstructor public class newsignController { private final newsignService authService; @PostMapping("/signup") - public ResponseEntity signup(@RequestBody UserSignupRequest request) { + public ResponseEntity signup(@RequestBody UserSignupRequest request) throws URISyntaxException { authService.signup(request); - return ResponseEntity.ok("회원가입 성공"); - } - - @PostMapping("/api/v1/order/{orderId}/login") - public ResponseEntity login(@RequestBody UserLoginRequest request) { - TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); - - if (tokenResponse != null) { - return ResponseEntity.ok(tokenResponse); - } else { - return ResponseEntity.status(401).body(null); - } + URI location = new URI("http://localhost:8081/api/v1/order/search/login"); + return ResponseEntity.created(location).build(); } - @PostMapping("/api/v1/order/search/login") - public ResponseEntity login2(@RequestBody UserLoginRequest request) { - TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); - - if (tokenResponse != null) { - return ResponseEntity.ok(tokenResponse); - } else { - return ResponseEntity.status(401).body(null); - } - } - - @PostMapping("/refresh") - public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { - TokenResponse newTokens = authService.refreshToken(refreshToken); - - if (newTokens != null) { - return ResponseEntity.ok(newTokens); - } else { - return ResponseEntity.status(403).body(null); - } - } - - @DeleteMapping("/delete") - public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { - try { - authService.deleteUser(request.getUsername()); - return ResponseEntity.ok("계정 삭제 완료"); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(404).body(e.getMessage()); - } - } } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java new file mode 100644 index 0000000..63c7769 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java @@ -0,0 +1,27 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Controller; + +import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequestMapping("/api/v1") +@RequiredArgsConstructor +@RestController +public class newsigndeleteController { + + private final newsignService authService; + @DeleteMapping("/delete") + public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { + try { + authService.deleteUser(request.getUsername()); + return ResponseEntity.ok("계정 삭제 완료"); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(404).body(e.getMessage()); + } + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java new file mode 100644 index 0000000..3fb7d9c --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java @@ -0,0 +1,27 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Controller; + +import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequestMapping("/api/v1") +@RequiredArgsConstructor +@RestController +public class newsignloginController { + private final newsignService authService; + @PostMapping("/order/{orderId}/login") + public ResponseEntity login(@RequestBody UserLoginRequest request) { + TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); + + if (tokenResponse != null) { + return ResponseEntity.ok(tokenResponse); + } else { + return ResponseEntity.status(401).body(null); + } + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java new file mode 100644 index 0000000..32d2c5d --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java @@ -0,0 +1,28 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Controller; + +import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequestMapping("/api/v1") +@RequiredArgsConstructor +@RestController + +public class newsignloginsearchController { + private final newsignService authService; + @PostMapping("/order/search/login") + public ResponseEntity login2(@RequestBody UserLoginRequest request) { + TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); + + if (tokenResponse != null) { + return ResponseEntity.ok(tokenResponse); + } else { + return ResponseEntity.status(401).body(null); + } + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java new file mode 100644 index 0000000..3fd5e41 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java @@ -0,0 +1,28 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Controller; + +import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequestMapping("/api/v1") +@RequiredArgsConstructor +@RestController + +public class newsignrefreshController { + private final newsignService authService; + @PostMapping("/refresh") + public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { + TokenResponse newTokens = authService.refreshToken(refreshToken); + + if (newTokens != null) { + return ResponseEntity.ok(newTokens); + } else { + return ResponseEntity.status(403).body(null); + } + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java index d744b32..82374e9 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java @@ -25,6 +25,7 @@ public void signup(UserSignupRequest request) { if (userRepository.findByUsername(request.getUsername()).isPresent()) { throw new RuntimeException("이미 존재하는 사용자입니다."); } + String encoredPassword = passwordEncoder.encode(request.getPassword()); NewSign newUser = NewSign.builder() .username(request.getUsername()) .password(passwordEncoder.encode(request.getPassword())) diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java index cb70215..f9f351b 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/JwtAuthenticationFilter.java @@ -6,8 +6,8 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.web.filter.OncePerRequestFilter; @@ -17,32 +17,36 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenService jwtTokenService; + private final UserDetailsService userDetailsService; // 추가 @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - String token = request.getHeader("Authorization"); + String authHeader = request.getHeader("Authorization"); - if (token != null && token.startsWith("Bearer ")) { - token = token.substring(7); - if (jwtTokenService.validateToken(token)) { - String username = jwtTokenService.getUsernameFromToken(token); + // null 체크 + Bearer 형식인지 확인 + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } + + String token = authHeader.substring(7); - // UserDetails 객체 생성 - UserDetails userDetails = User.withUsername(username) - .password("") // JWT는 비밀번호를 검증하지 않음 - .authorities("ROLE_USER") // 기본 역할 부여 - .build(); + if (jwtTokenService.validateToken(token)) { + String username = jwtTokenService.getUsernameFromToken(token); - // 인증 객체 생성 - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + // UserDetailsService를 활용하여 사용자 정보 로드 + UserDetails userDetails = userDetailsService.loadUserByUsername(username); - // Spring Security 컨텍스트에 저장 - SecurityContextHolder.getContext().setAuthentication(authentication); - } + // 인증 객체 생성 + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + + // Spring Security 컨텍스트에 저장 + SecurityContextHolder.getContext().setAuthentication(authentication); } + filterChain.doFilter(request, response); } } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java index 216a5f2..d26512c 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/global/security/SecurityConfig.java @@ -1,39 +1,46 @@ package com.gsm._8th.class4.backend.task12.global.security; -import lombok.RequiredArgsConstructor; 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.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import static org.springframework.security.config.Customizer.withDefaults; @Configuration -@RequiredArgsConstructor public class SecurityConfig { - private final JwtTokenService jwtTokenService; + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) { + UserDetails user = User.builder() + .username("user") + .password(passwordEncoder.encode("password")) + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user); + } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .csrf(csrf -> csrf.disable()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth - .requestMatchers("/api/user/**").permitAll() - .requestMatchers("/api/v1/order/**").authenticated() - .anyRequest().permitAll() + .anyRequest().authenticated() ) - // 필터 추가 시 순서 지정 (기존 addFilter() → addFilterBefore()로 변경) - .addFilterBefore(new JwtAuthenticationFilter(jwtTokenService), UsernamePasswordAuthenticationFilter.class); + .formLogin(withDefaults()) + .httpBasic(withDefaults()); return http.build(); } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } } From 7593d43b90700eff288ad5f48fdb725014f56ac5 Mon Sep 17 00:00:00 2001 From: pgsshiho Date: Wed, 12 Mar 2025 15:59:37 +0900 Subject: [PATCH 4/5] feedback,but I don't know about I clear the first feedback --- .../auth/Controller/newsignController.java | 35 +++++++-- .../Controller/newsigndeleteController.java | 27 ------- .../Controller/newsignloginController.java | 27 ------- .../newsignloginsearchController.java | 28 ------- .../Controller/newsignrefreshController.java | 28 ------- .../auth/Repository/UserRepository.java | 7 +- .../auth/Service/DeleteUserService.java | 5 ++ .../domain/auth/Service/LoginService.java | 7 ++ .../domain/auth/Service/LoginServiceImpl.java | 32 ++++++++ .../domain/auth/Service/NewSignService.java | 7 ++ .../auth/Service/NewsignServiceImpl.java | 36 +++++++++ .../auth/Service/RefreshTokenService.java | 7 ++ .../auth/Service/RefreshTokenServiceImpl.java | 26 +++++++ .../domain/auth/Service/deleteUserImpl.java | 27 +++++++ .../domain/auth/Service/newsignService.java | 78 ------------------- 15 files changed, 183 insertions(+), 194 deletions(-) delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/DeleteUserService.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenService.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java delete mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java index eafb193..30e0cc3 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java @@ -1,6 +1,9 @@ package com.gsm._8th.class4.backend.task12.domain.auth.Controller; -import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.DeleteUserService; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.LoginService; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.NewSignService; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.RefreshTokenService; import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; @@ -12,17 +15,39 @@ import java.net.URISyntaxException; @RestController -@RequestMapping("/api/v1") +@RequestMapping("/api/v1/auth") // ✅ API 명세서에 맞춰 변경 @RequiredArgsConstructor -public class newsignController { +public class newsignController { // ✅ 클래스명 변경 - private final newsignService authService; + private final NewSignService authService; + private final DeleteUserService deleteUserService; + private final LoginService loginService; + private final RefreshTokenService refreshTokenService; + // 회원가입 @PostMapping("/signup") public ResponseEntity signup(@RequestBody UserSignupRequest request) throws URISyntaxException { authService.signup(request); - URI location = new URI("http://localhost:8081/api/v1/order/search/login"); + URI location = new URI("http://localhost:8081/api/v1/auth/signin"); return ResponseEntity.created(location).build(); } + // 회원 삭제 + @DeleteMapping("/delete") + public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { + deleteUserService.deleteUser(request.getUsername()); + return ResponseEntity.ok("계정 삭제 완료"); + } + + // 로그인 + @PostMapping("/signin") // ✅ API 경로 수정 + public ResponseEntity login(@RequestBody UserLoginRequest request) { + return ResponseEntity.ok(loginService.login(request.getUsername(), request.getPassword())); + } + + // 토큰 갱신 + @PostMapping("/refresh") // ✅ API 경로 유지 + public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { + return ResponseEntity.ok(refreshTokenService.refreshToken(refreshToken)); + } } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java deleted file mode 100644 index 63c7769..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsigndeleteController.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gsm._8th.class4.backend.task12.domain.auth.Controller; - -import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; -import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; -import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RequestMapping("/api/v1") -@RequiredArgsConstructor -@RestController -public class newsigndeleteController { - - private final newsignService authService; - @DeleteMapping("/delete") - public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) { - try { - authService.deleteUser(request.getUsername()); - return ResponseEntity.ok("계정 삭제 완료"); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(404).body(e.getMessage()); - } - } -} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java deleted file mode 100644 index 3fb7d9c..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginController.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.gsm._8th.class4.backend.task12.domain.auth.Controller; - -import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; -import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; -import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RequestMapping("/api/v1") -@RequiredArgsConstructor -@RestController -public class newsignloginController { - private final newsignService authService; - @PostMapping("/order/{orderId}/login") - public ResponseEntity login(@RequestBody UserLoginRequest request) { - TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); - - if (tokenResponse != null) { - return ResponseEntity.ok(tokenResponse); - } else { - return ResponseEntity.status(401).body(null); - } - } -} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java deleted file mode 100644 index 32d2c5d..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignloginsearchController.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gsm._8th.class4.backend.task12.domain.auth.Controller; - -import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; -import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; -import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RequestMapping("/api/v1") -@RequiredArgsConstructor -@RestController - -public class newsignloginsearchController { - private final newsignService authService; - @PostMapping("/order/search/login") - public ResponseEntity login2(@RequestBody UserLoginRequest request) { - TokenResponse tokenResponse = authService.login(request.getUsername(), request.getPassword()); - - if (tokenResponse != null) { - return ResponseEntity.ok(tokenResponse); - } else { - return ResponseEntity.status(401).body(null); - } - } -} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java deleted file mode 100644 index 3fd5e41..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignrefreshController.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.gsm._8th.class4.backend.task12.domain.auth.Controller; - -import com.gsm._8th.class4.backend.task12.domain.auth.Service.newsignService; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; -import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; -import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RequestMapping("/api/v1") -@RequiredArgsConstructor -@RestController - -public class newsignrefreshController { - private final newsignService authService; - @PostMapping("/refresh") - public ResponseEntity refreshToken(@RequestHeader("Refresh-Token") String refreshToken) { - TokenResponse newTokens = authService.refreshToken(refreshToken); - - if (newTokens != null) { - return ResponseEntity.ok(newTokens); - } else { - return ResponseEntity.status(403).body(null); - } - } -} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java index 551392a..6e3e3f9 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Repository/UserRepository.java @@ -6,5 +6,10 @@ import java.util.Optional; public interface UserRepository extends JpaRepository { + Optional findByUsername(String username); -} \ No newline at end of file + + boolean existsByUsername(String username); + + void deleteByUsername(String username); +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/DeleteUserService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/DeleteUserService.java new file mode 100644 index 0000000..6279058 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/DeleteUserService.java @@ -0,0 +1,5 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +public interface DeleteUserService { + void deleteUser(String username); +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java new file mode 100644 index 0000000..eb45320 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java @@ -0,0 +1,7 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; + +public interface LoginService { + TokenResponse login(String username, String rawPassword); +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java new file mode 100644 index 0000000..9d00481 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java @@ -0,0 +1,32 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; +import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; +import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class LoginServiceImpl implements LoginService { + private final UserRepository userRepository; + private final JwtTokenService jwtTokenService; + private final PasswordEncoder passwordEncoder; + + @Override + public TokenResponse login(String username, String rawPassword) { + NewSign user = userRepository.findByUsername(username) + .orElseThrow(() -> new IllegalArgumentException("아이디 또는 비밀번호가 틀렸습니다.")); + + if (!passwordEncoder.matches(rawPassword, user.getPassword())) { + throw new IllegalArgumentException("아이디 또는 비밀번호가 틀렸습니다."); + } + + return new TokenResponse( + jwtTokenService.createAccessToken(username), + jwtTokenService.createRefreshToken(username) + ); + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java new file mode 100644 index 0000000..acebd6e --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java @@ -0,0 +1,7 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; + +public interface NewSignService { + void signup(UserSignupRequest request); +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java new file mode 100644 index 0000000..f2e563e --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java @@ -0,0 +1,36 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; +import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; +import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; +import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class NewsignServiceImpl implements NewSignService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + @Override + @Transactional + public void signup(UserSignupRequest request) { + if (userRepository.existsByUsername(request.getUsername())) { + throw new IllegalArgumentException("이미 존재하는 사용자입니다."); + } + + NewSign newUser = NewSign.builder() + .username(request.getUsername()) + .password(passwordEncoder.encode(request.getPassword())) + .email(request.getEmail()) + .role("ROLE_USER") + .build(); + + userRepository.save(newUser); + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenService.java new file mode 100644 index 0000000..0283182 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenService.java @@ -0,0 +1,7 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; + +public interface RefreshTokenService { + TokenResponse refreshToken(String refreshToken); +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java new file mode 100644 index 0000000..2e8c60e --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java @@ -0,0 +1,26 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; +import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class RefreshTokenServiceImpl implements RefreshTokenService { + private final JwtTokenService jwtTokenService; + + @Override + public TokenResponse refreshToken(String refreshToken) { + String username = jwtTokenService.getUsernameFromToken(refreshToken); + if (username == null || !jwtTokenService.validateRefreshToken(username, refreshToken)) { + throw new IllegalArgumentException("유효하지 않은 리프레시 토큰입니다."); + } + + jwtTokenService.revokeRefreshToken(username); + return new TokenResponse( + jwtTokenService.createAccessToken(username), + jwtTokenService.createRefreshToken(username) + ); + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java new file mode 100644 index 0000000..926c954 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java @@ -0,0 +1,27 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + +import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; +import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; + +import java.util.Optional; + +@Service +@Transactional +@RequiredArgsConstructor +public class deleteUserImpl implements DeleteUserService { + private final UserRepository userRepository; + + @Override + @Transactional + public void deleteUser(String username) { + if (!userRepository.existsByUsername(username)) { + throw new IllegalArgumentException("존재하지 않는 사용자입니다."); + } + userRepository.deleteByUsername(username); + } +} diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java deleted file mode 100644 index 82374e9..0000000 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/newsignService.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.gsm._8th.class4.backend.task12.domain.auth.Service; - -import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; -import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; -import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; -import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; -import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; -import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Optional; - -@Service -@RequiredArgsConstructor -public class newsignService { - - private final UserRepository userRepository; - private final JwtTokenService jwtTokenService; - private final PasswordEncoder passwordEncoder; - - @Transactional - public void signup(UserSignupRequest request) { - if (userRepository.findByUsername(request.getUsername()).isPresent()) { - throw new RuntimeException("이미 존재하는 사용자입니다."); - } - String encoredPassword = passwordEncoder.encode(request.getPassword()); - NewSign newUser = NewSign.builder() - .username(request.getUsername()) - .password(passwordEncoder.encode(request.getPassword())) - .email(request.getEmail()) - .role("ROLE_USER") - .build(); - userRepository.save(newUser); - } - - // 로그인 - public TokenResponse login(String username, String rawPassword) { - Optional userOptional = userRepository.findByUsername(username); - - if (userOptional.isPresent()) { - NewSign user = userOptional.get(); - if (passwordEncoder.matches(rawPassword, user.getPassword())) { - String accessToken = jwtTokenService.createAccessToken(username); - String refreshToken = jwtTokenService.createRefreshToken(username); - return new TokenResponse(accessToken, refreshToken); - } else { - throw new IllegalArgumentException("비밀번호 또는 사용자 이름이 틀립니다!"); - } - } - - throw new IllegalArgumentException("해당 사용자 이름을 찾을 수 없습니다!"); - } - - // 리프레시 토큰을 통한 JWT 재발급 - public TokenResponse refreshToken(String refreshToken) { - String username = jwtTokenService.getUsernameFromToken(refreshToken); - if (username == null || !jwtTokenService.validateRefreshToken(username, refreshToken)) { - throw new IllegalArgumentException("유효하지 않은 리프레시 토큰입니다."); - } - jwtTokenService.revokeRefreshToken(username); - String newAccessToken = jwtTokenService.createAccessToken(username); - String newRefreshToken = jwtTokenService.createRefreshToken(username); - return new TokenResponse(newAccessToken, newRefreshToken); - } - - // 사용자 삭제 (서비스를 통해 처리) - @Transactional - public void deleteUser(String username) { - Optional userOptional = userRepository.findByUsername(username); - if (userOptional.isPresent()) { - userRepository.delete(userOptional.get()); - } else { - throw new IllegalArgumentException("사용자를 찾을 수 없습니다."); - } - } -} From 074cb148ffa54e3dcf981f7bfaf075a569e7e179 Mon Sep 17 00:00:00 2001 From: pgsshiho Date: Thu, 13 Mar 2025 19:50:33 +0900 Subject: [PATCH 5/5] feedback,but I don't know about I clear the first feedback --- ...nController.java => newsignUpController.java} | 12 ++++++------ .../auth/Service/GlobalExceptionHandler.java | 16 ++++++++++++++++ .../auth/Service/RefreshTokenServiceImpl.java | 10 ++++++---- .../{NewSignService.java => SignUpService.java} | 2 +- .../domain/auth/Service/deleteUserImpl.java | 13 ++++++++----- ...gnServiceImpl.java => signUpServiceImpl.java} | 5 +---- .../{LoginService.java => signinService.java} | 2 +- ...inServiceImpl.java => signinServiceImpl.java} | 8 ++------ 8 files changed, 41 insertions(+), 27 deletions(-) rename src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/{newsignController.java => newsignUpController.java} (82%) create mode 100644 src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/GlobalExceptionHandler.java rename src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/{NewSignService.java => SignUpService.java} (84%) rename src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/{NewsignServiceImpl.java => signUpServiceImpl.java} (88%) rename src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/{LoginService.java => signinService.java} (86%) rename src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/{LoginServiceImpl.java => signinServiceImpl.java} (82%) diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignUpController.java similarity index 82% rename from src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java rename to src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignUpController.java index 30e0cc3..9f1f0b6 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignController.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Controller/newsignUpController.java @@ -1,8 +1,8 @@ package com.gsm._8th.class4.backend.task12.domain.auth.Controller; import com.gsm._8th.class4.backend.task12.domain.auth.Service.DeleteUserService; -import com.gsm._8th.class4.backend.task12.domain.auth.Service.LoginService; -import com.gsm._8th.class4.backend.task12.domain.auth.Service.NewSignService; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.signinService; +import com.gsm._8th.class4.backend.task12.domain.auth.Service.SignUpService; import com.gsm._8th.class4.backend.task12.domain.auth.Service.RefreshTokenService; import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserLoginRequest; import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; @@ -17,11 +17,11 @@ @RestController @RequestMapping("/api/v1/auth") // ✅ API 명세서에 맞춰 변경 @RequiredArgsConstructor -public class newsignController { // ✅ 클래스명 변경 +public class newsignUpController { // ✅ 클래스명 변경 - private final NewSignService authService; + private final SignUpService authService; private final DeleteUserService deleteUserService; - private final LoginService loginService; + private final signinService signinService; private final RefreshTokenService refreshTokenService; // 회원가입 @@ -42,7 +42,7 @@ public ResponseEntity deleteUser(@RequestBody UserLoginRequest request) // 로그인 @PostMapping("/signin") // ✅ API 경로 수정 public ResponseEntity login(@RequestBody UserLoginRequest request) { - return ResponseEntity.ok(loginService.login(request.getUsername(), request.getPassword())); + return ResponseEntity.ok(signinService.login(request.getUsername(), request.getPassword())); } // 토큰 갱신 diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/GlobalExceptionHandler.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/GlobalExceptionHandler.java new file mode 100644 index 0000000..168a97c --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/GlobalExceptionHandler.java @@ -0,0 +1,16 @@ +package com.gsm._8th.class4.backend.task12.domain.auth.Service; + + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java index 2e8c60e..cf730b8 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/RefreshTokenServiceImpl.java @@ -5,6 +5,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.Optional; + @Service @RequiredArgsConstructor public class RefreshTokenServiceImpl implements RefreshTokenService { @@ -12,10 +14,10 @@ public class RefreshTokenServiceImpl implements RefreshTokenService { @Override public TokenResponse refreshToken(String refreshToken) { - String username = jwtTokenService.getUsernameFromToken(refreshToken); - if (username == null || !jwtTokenService.validateRefreshToken(username, refreshToken)) { - throw new IllegalArgumentException("유효하지 않은 리프레시 토큰입니다."); - } + String username = Optional.ofNullable(jwtTokenService.getUsernameFromToken(refreshToken)) + .filter(u -> jwtTokenService.validateRefreshToken(u, refreshToken)) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 리프레시 토큰입니다.")); + jwtTokenService.revokeRefreshToken(username); return new TokenResponse( diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/SignUpService.java similarity index 84% rename from src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java rename to src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/SignUpService.java index acebd6e..2b6d69d 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewSignService.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/SignUpService.java @@ -2,6 +2,6 @@ import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; -public interface NewSignService { +public interface SignUpService { void signup(UserSignupRequest request); } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java index 926c954..34ccac3 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/deleteUserImpl.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; +import org.springframework.web.bind.annotation.ControllerAdvice; import java.util.Optional; @@ -18,10 +19,12 @@ public class deleteUserImpl implements DeleteUserService { @Override @Transactional + public void deleteUser(String username) { - if (!userRepository.existsByUsername(username)) { - throw new IllegalArgumentException("존재하지 않는 사용자입니다."); - } - userRepository.deleteByUsername(username); - } + userRepository.findByUsername(username) + .ifPresentOrElse( + userRepository::delete, + () -> { throw new IllegalArgumentException("존재하지 않는 사용자입니다."); } + ); +} } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signUpServiceImpl.java similarity index 88% rename from src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java rename to src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signUpServiceImpl.java index f2e563e..b5b33ca 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/NewsignServiceImpl.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signUpServiceImpl.java @@ -3,17 +3,14 @@ import com.gsm._8th.class4.backend.task12.domain.auth.dto.UserSignupRequest; import com.gsm._8th.class4.backend.task12.domain.auth.Entity.NewSign; import com.gsm._8th.class4.backend.task12.domain.auth.Repository.UserRepository; -import com.gsm._8th.class4.backend.task12.global.security.JwtTokenService; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - @Service @RequiredArgsConstructor -public class NewsignServiceImpl implements NewSignService { +public class signUpServiceImpl implements SignUpService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signinService.java similarity index 86% rename from src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java rename to src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signinService.java index eb45320..39fbd80 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginService.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signinService.java @@ -2,6 +2,6 @@ import com.gsm._8th.class4.backend.task12.global.security.TokenResponse; -public interface LoginService { +public interface signinService { TokenResponse login(String username, String rawPassword); } diff --git a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signinServiceImpl.java similarity index 82% rename from src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java rename to src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signinServiceImpl.java index 9d00481..2db7644 100644 --- a/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/LoginServiceImpl.java +++ b/src/main/java/com/gsm/_8th/class4/backend/task12/domain/auth/Service/signinServiceImpl.java @@ -10,7 +10,7 @@ @Service @RequiredArgsConstructor -public class LoginServiceImpl implements LoginService { +public class signinServiceImpl implements signinService { private final UserRepository userRepository; private final JwtTokenService jwtTokenService; private final PasswordEncoder passwordEncoder; @@ -18,12 +18,8 @@ public class LoginServiceImpl implements LoginService { @Override public TokenResponse login(String username, String rawPassword) { NewSign user = userRepository.findByUsername(username) + .filter(u -> passwordEncoder.matches(rawPassword, u.getPassword())) .orElseThrow(() -> new IllegalArgumentException("아이디 또는 비밀번호가 틀렸습니다.")); - - if (!passwordEncoder.matches(rawPassword, user.getPassword())) { - throw new IllegalArgumentException("아이디 또는 비밀번호가 틀렸습니다."); - } - return new TokenResponse( jwtTokenService.createAccessToken(username), jwtTokenService.createRefreshToken(username)