From 29a34113dcb8d00f669c57d299201cde38d82a79 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Wed, 24 Dec 2025 23:28:36 +0900 Subject: [PATCH 01/54] =?UTF-8?q?feat=20:=20=EC=9D=BC=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/application/AuthService.java | 4 ++ .../AuthorizationExtractor.java | 9 ++++ .../infrastructure/JwtTokenProvider.java | 43 +++++++++++++++++++ .../roomescape/member/MemberController.java | 25 +++++++++++ .../java/roomescape/member/MemberService.java | 20 ++++++++- .../java/roomescape/member/TokenResponse.java | 7 +++ src/main/resources/application.properties | 13 +++++- 7 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/main/java/roomescape/application/AuthService.java create mode 100644 src/main/java/roomescape/infrastructure/AuthorizationExtractor.java create mode 100644 src/main/java/roomescape/infrastructure/JwtTokenProvider.java create mode 100644 src/main/java/roomescape/member/TokenResponse.java diff --git a/src/main/java/roomescape/application/AuthService.java b/src/main/java/roomescape/application/AuthService.java new file mode 100644 index 000000000..f913a35b2 --- /dev/null +++ b/src/main/java/roomescape/application/AuthService.java @@ -0,0 +1,4 @@ +package roomescape.application; + +public class AuthService { +} diff --git a/src/main/java/roomescape/infrastructure/AuthorizationExtractor.java b/src/main/java/roomescape/infrastructure/AuthorizationExtractor.java new file mode 100644 index 000000000..f2c8b4d98 --- /dev/null +++ b/src/main/java/roomescape/infrastructure/AuthorizationExtractor.java @@ -0,0 +1,9 @@ +package roomescape.infrastructure; + +import jakarta.servlet.http.HttpServletRequest; + +public interface AuthorizationExtractor { + String AUTHORIZATION = "Authorization"; + + T extract(HttpServletRequest request); +} diff --git a/src/main/java/roomescape/infrastructure/JwtTokenProvider.java b/src/main/java/roomescape/infrastructure/JwtTokenProvider.java new file mode 100644 index 000000000..777b7edee --- /dev/null +++ b/src/main/java/roomescape/infrastructure/JwtTokenProvider.java @@ -0,0 +1,43 @@ +package roomescape.infrastructure; + +import io.jsonwebtoken.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Date; + +@Component +public class JwtTokenProvider { + @Value("${security.jwt.token.secret-key:this-is-a-sample-secret-key-at-least-32-bytes-long}") + private String secretKey; + @Value("${security.jwt.token.expire-length:3600000}") + private long validityInMilliseconds; + + public String createToken(String payload) { + Claims claims = Jwts.claims().setSubject(payload); + Date now = new Date(); + Date validity = new Date(now.getTime() + validityInMilliseconds); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); + } + + public String getPayload(String token) { + return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); + } + + public boolean validateToken(String token) { + try { + Jws claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } +} + diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 881ae5e0d..182264cd1 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -19,6 +19,31 @@ public MemberController(MemberService memberService) { this.memberService = memberService; } + + @PostMapping("/login") + public ResponseEntity login( + @RequestBody MemberRequest memberRequest, + HttpServletResponse response) { // 응답 객체를 파라미터로 받습니다. + + // 1. 서비스 호출: 서비스는 토큰 문자열(알맹이)만 반환합니다. + // (이전 답변에서 리팩토링한대로 TokenResponse DTO를 활용하세요) + TokenResponse tokenResponse = memberService.login(memberRequest); + String tokenValue = tokenResponse.accessToken(); + + + Cookie cookie = new Cookie("token", tokenValue); + + + cookie.setHttpOnly(true); + cookie.setPath("/"); + cookie.setMaxAge(3600); + + response.addCookie(cookie); + + + return ResponseEntity.ok().body(tokenResponse); + } + @PostMapping("/members") public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { MemberResponse member = memberService.createMember(memberRequest); diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index ccaa8cba5..fb4361c56 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -1,17 +1,35 @@ package roomescape.member; import org.springframework.stereotype.Service; +import roomescape.infrastructure.JwtTokenProvider; @Service public class MemberService { private MemberDao memberDao; + private JwtTokenProvider jwtTokenProvider; - public MemberService(MemberDao memberDao) { + public MemberService(MemberDao memberDao, JwtTokenProvider jwtTokenProvider) { this.memberDao = memberDao; + this.jwtTokenProvider = jwtTokenProvider; } public MemberResponse createMember(MemberRequest memberRequest) { Member member = memberDao.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER")); return new MemberResponse(member.getId(), member.getName(), member.getEmail()); } + + public TokenResponse login(MemberRequest memberRequest) { + Member member = memberDao.findByEmailAndPassword( + memberRequest.getEmail(), + memberRequest.getPassword() + ); + + if (member == null) { + throw new RuntimeException("이메일 또는 비밀번호가 일치하지 않습니다."); + } + + String accessToken = jwtTokenProvider.createToken(member.getEmail()); + + return new TokenResponse(accessToken); + } } diff --git a/src/main/java/roomescape/member/TokenResponse.java b/src/main/java/roomescape/member/TokenResponse.java new file mode 100644 index 000000000..36c921d10 --- /dev/null +++ b/src/main/java/roomescape/member/TokenResponse.java @@ -0,0 +1,7 @@ +package roomescape.member; + +public record TokenResponse( + String accessToken +) { + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a0f33bbab..0e20cc849 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,9 +3,20 @@ spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.datasource.url=jdbc:h2:mem:database + + + #spring.jpa.show-sql=true #spring.jpa.properties.hibernate.format_sql=true #spring.jpa.ddl-auto=create-drop #spring.jpa.defer-datasource-initialization=true -#roomescape.auth.jwt.secret= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= \ No newline at end of file +#roomescape.auth.jwt.secret= Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E= + + + + + +# ??? ??? ?? ??? ???, ??? ?? ? ???? ??? ????. +security.jwt.token.secret-key=thisismysecretkeyandgreedyzzangandsoftwarefighting +security.jwt.token.expire-length=3600000 \ No newline at end of file From 76e20ba872b11372c70fe9dc12911155dd32e202 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Thu, 25 Dec 2025 01:45:08 +0900 Subject: [PATCH 02/54] =?UTF-8?q?feat(dao)=20:=20=EC=9D=B4=EB=A9=94?= =?UTF-8?q?=EC=9D=BC=EB=A1=9C=20=EB=A9=A4=EB=B2=84=20=EC=B0=BE=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/application/AuthService.java | 4 -- .../roomescape/member/MemberController.java | 7 +-- .../java/roomescape/member/MemberDao.java | 13 +++++ src/test/java/roomescape/MissionStepTest.java | 57 ++++++++++++++++++- 4 files changed, 70 insertions(+), 11 deletions(-) delete mode 100644 src/main/java/roomescape/application/AuthService.java diff --git a/src/main/java/roomescape/application/AuthService.java b/src/main/java/roomescape/application/AuthService.java deleted file mode 100644 index f913a35b2..000000000 --- a/src/main/java/roomescape/application/AuthService.java +++ /dev/null @@ -1,4 +0,0 @@ -package roomescape.application; - -public class AuthService { -} diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 182264cd1..3e7479ce1 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -19,18 +19,14 @@ public MemberController(MemberService memberService) { this.memberService = memberService; } - @PostMapping("/login") public ResponseEntity login( @RequestBody MemberRequest memberRequest, - HttpServletResponse response) { // 응답 객체를 파라미터로 받습니다. + HttpServletResponse response) { - // 1. 서비스 호출: 서비스는 토큰 문자열(알맹이)만 반환합니다. - // (이전 답변에서 리팩토링한대로 TokenResponse DTO를 활용하세요) TokenResponse tokenResponse = memberService.login(memberRequest); String tokenValue = tokenResponse.accessToken(); - Cookie cookie = new Cookie("token", tokenValue); @@ -40,7 +36,6 @@ public ResponseEntity login( response.addCookie(cookie); - return ResponseEntity.ok().body(tokenResponse); } diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java index 81f77f4cd..a55a440db 100644 --- a/src/main/java/roomescape/member/MemberDao.java +++ b/src/main/java/roomescape/member/MemberDao.java @@ -40,6 +40,19 @@ public Member findByEmailAndPassword(String email, String password) { ); } + public Member findByEmail(String email) { + return jdbcTemplate.queryForObject( + "SELECT id, name, email, role FROM member WHERE email = ?", + (rs, rowNum) -> new Member( + rs.getLong("id"), + rs.getString("name"), + rs.getString("email"), + rs.getString("role") + ), + email + ); + } + public Member findByName(String name) { return jdbcTemplate.queryForObject( "SELECT id, name, email, role FROM member WHERE name = ?", diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 6add784bd..bed9fe364 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -1,5 +1,8 @@ package roomescape; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.response.ExtractableResponse; @@ -7,7 +10,9 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; +import roomescape.reservation.ReservationResponse; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -35,4 +40,54 @@ public class MissionStepTest { assertThat(token).isNotBlank(); } -} \ No newline at end of file + + @Test + void 이단계() { + String token = createToken("admin@email.com"); // 일단계에서 토큰을 추출하는 로직을 메서드로 따로 만들어서 활용하세요. + + Map params = new HashMap<>(); + params.put("date", "2024-03-01"); + params.put("time", "1"); + params.put("theme", "1"); + + ExtractableResponse response = RestAssured.given().log().all() + .body(params) + .cookie("token", token) + .contentType(ContentType.JSON) + .post("/reservations") + .then().log().all() + .extract(); + + assertThat(response.statusCode()).isEqualTo(201); + assertThat(response.as(ReservationResponse.class).getName()).isEqualTo("어드민"); + + params.put("name", "브라운"); + + ExtractableResponse adminResponse = RestAssured.given().log().all() + .body(params) + .cookie("token", token) + .contentType(ContentType.JSON) + .post("/reservations") + .then().log().all() + .extract(); + + assertThat(adminResponse.statusCode()).isEqualTo(201); + assertThat(adminResponse.as(ReservationResponse.class).getName()).isEqualTo("브라운"); + } + + public String createToken(String payload) { + Claims claims = Jwts.claims().setSubject(payload); + Date now = new Date(); + long validityInMilliseconds = 3600000; + Date validity = new Date(now.getTime() + validityInMilliseconds); + + String secretKey = "thisismysecretkeyandgreedyzzangandsoftwarefighting"; + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); + } +} + From 68848887c0555ec25098c0d0b2707915e6000f76 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:34:28 +0900 Subject: [PATCH 03/54] =?UTF-8?q?feat(MemberController)=20:=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...thenticationPrincipalArgumentResolver.java | 52 +++++++++++++++++++ .../roomescape/application/WebMvcConfig.java | 22 ++++++++ .../roomescape/member/MemberController.java | 14 +++++ .../reservation/ReservationController.java | 18 ++++--- .../reservation/ReservationService.java | 28 ++++++++-- 5 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java create mode 100644 src/main/java/roomescape/application/WebMvcConfig.java diff --git a/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java b/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java new file mode 100644 index 000000000..de22955d5 --- /dev/null +++ b/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java @@ -0,0 +1,52 @@ +package roomescape.application; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import roomescape.infrastructure.JwtTokenProvider; +import roomescape.member.Member; +import roomescape.member.MemberDao; + +@Component +public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver { + private final JwtTokenProvider jwtTokenProvider; + private final MemberDao memberDao; + + public AuthenticationPrincipalArgumentResolver(JwtTokenProvider jwtTokenProvider, MemberDao memberDao) { + this.jwtTokenProvider = jwtTokenProvider; + this.memberDao = memberDao; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.getParameterType().equals(Member.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + + Cookie[] cookies = request.getCookies(); + String token = ""; + if (cookies != null) { + for (Cookie cookie : cookies) { + if ("token".equals(cookie.getName())) { + token = cookie.getValue(); + } + } + } + + if (!jwtTokenProvider.validateToken(token)) { + throw new RuntimeException("인증되지 않은 사용자입니다."); + } + String email = jwtTokenProvider.getPayload(token); + + return memberDao.findByEmail(email); + } +} \ No newline at end of file diff --git a/src/main/java/roomescape/application/WebMvcConfig.java b/src/main/java/roomescape/application/WebMvcConfig.java new file mode 100644 index 000000000..b2fb692da --- /dev/null +++ b/src/main/java/roomescape/application/WebMvcConfig.java @@ -0,0 +1,22 @@ +package roomescape.application; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + private final AuthenticationPrincipalArgumentResolver authResolver; + + public WebMvcConfig(AuthenticationPrincipalArgumentResolver authResolver) { + this.authResolver = authResolver; + } + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(authResolver); + } +} \ No newline at end of file diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 3e7479ce1..ce61936db 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -39,6 +39,20 @@ public ResponseEntity login( return ResponseEntity.ok().body(tokenResponse); } + @PostMapping("/login/check") + public ResponseEntity check( + @RequestBody MemberRequest memberRequest + ) { + + String adminName = memberRequest.getName(); + TokenResponse tokenResponse = new TokenResponse(adminName); + return ResponseEntity.ok() + .header("Connection", "keep-alive") + .header("Keep-Alive", "timeout=60") + .body(tokenResponse); + } + + @PostMapping("/members") public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { MemberResponse member = memberService.createMember(memberRequest); diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index b3bef3990..f71c7a179 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import roomescape.member.Member; import java.net.URI; import java.util.List; @@ -26,14 +27,15 @@ public List list() { } @PostMapping("/reservations") - public ResponseEntity create(@RequestBody ReservationRequest reservationRequest) { - if (reservationRequest.getName() == null - || reservationRequest.getDate() == null - || reservationRequest.getTheme() == null - || reservationRequest.getTime() == null) { - return ResponseEntity.badRequest().build(); - } - ReservationResponse reservation = reservationService.save(reservationRequest); + public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, Member member) { + + if (reservationRequest.getDate() == null + || reservationRequest.getTheme() == null + || reservationRequest.getTime() == null) { + return ResponseEntity.badRequest().build(); + } + + ReservationResponse reservation = reservationService.save(reservationRequest,member); return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())).body(reservation); } diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index bd3313328..69b075279 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -1,21 +1,41 @@ package roomescape.reservation; +import jdk.jpackage.internal.WinExeBundler; import org.springframework.stereotype.Service; +import roomescape.member.Member; +import roomescape.member.MemberDao; import java.util.List; @Service public class ReservationService { private ReservationDao reservationDao; + private MemberDao memberDao; - public ReservationService(ReservationDao reservationDao) { + public ReservationService(ReservationDao reservationDao, MemberDao memberDao) { this.reservationDao = reservationDao; + this.memberDao = memberDao; } - public ReservationResponse save(ReservationRequest reservationRequest) { - Reservation reservation = reservationDao.save(reservationRequest); + public ReservationResponse save(ReservationRequest reservationRequest, Member member) { + String reservationName = reservationRequest.getName(); - return new ReservationResponse(reservation.getId(), reservationRequest.getName(), reservation.getTheme().getName(), reservation.getDate(), reservation.getTime().getValue()); + + if (reservationName != null && !reservationName.isBlank()) { + + } else { + reservationName = loginMember.getName(); + } + + Reservation reservation = reservationDao.save(reservationRequest, reservationName); + + return new ReservationResponse( + reservation.getId(), + reservation.getName(), + reservation.getTheme().getName(), + reservation.getDate(), + reservation.getTime().getValue() + ); } public void deleteById(Long id) { From b994a63bb8edcf749b0fb31d9e2442ff09b7ce43 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:00:13 +0900 Subject: [PATCH 04/54] =?UTF-8?q?feat=20:=202=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=ED=86=B5=EA=B3=BC~!!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...thenticationPrincipalArgumentResolver.java | 15 +++++------ .../roomescape/infrastructure/AuthMember.java | 11 ++++++++ .../roomescape/member/MemberController.java | 12 ++++----- .../java/roomescape/member/MemberDao.java | 2 ++ .../roomescape/member/MemberResponse.java | 3 +++ .../java/roomescape/member/MemberService.java | 10 ++++++++ .../reservation/ReservationController.java | 5 +++- .../reservation/ReservationDao.java | 6 ++--- .../reservation/ReservationService.java | 25 ++++++++++--------- 9 files changed, 59 insertions(+), 30 deletions(-) create mode 100644 src/main/java/roomescape/infrastructure/AuthMember.java diff --git a/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java b/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java index de22955d5..06766402f 100644 --- a/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java +++ b/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java @@ -8,23 +8,25 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; +import roomescape.infrastructure.AuthMember; import roomescape.infrastructure.JwtTokenProvider; import roomescape.member.Member; -import roomescape.member.MemberDao; +import roomescape.member.MemberService; @Component public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver { private final JwtTokenProvider jwtTokenProvider; - private final MemberDao memberDao; + private final MemberService memberService; - public AuthenticationPrincipalArgumentResolver(JwtTokenProvider jwtTokenProvider, MemberDao memberDao) { + public AuthenticationPrincipalArgumentResolver(JwtTokenProvider jwtTokenProvider, MemberService memberService) { this.jwtTokenProvider = jwtTokenProvider; - this.memberDao = memberDao; + this.memberService = memberService; } @Override public boolean supportsParameter(MethodParameter parameter) { - return parameter.getParameterType().equals(Member.class); + return parameter.hasParameterAnnotation(AuthMember.class) + && Member.class.isAssignableFrom(parameter.getParameterType()); } @Override @@ -45,8 +47,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m if (!jwtTokenProvider.validateToken(token)) { throw new RuntimeException("인증되지 않은 사용자입니다."); } - String email = jwtTokenProvider.getPayload(token); - return memberDao.findByEmail(email); + return memberService.findByToken(token); } } \ No newline at end of file diff --git a/src/main/java/roomescape/infrastructure/AuthMember.java b/src/main/java/roomescape/infrastructure/AuthMember.java new file mode 100644 index 000000000..0ff90e6d5 --- /dev/null +++ b/src/main/java/roomescape/infrastructure/AuthMember.java @@ -0,0 +1,11 @@ +package roomescape.infrastructure; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthMember { +} diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index ce61936db..aac6575c4 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import roomescape.infrastructure.AuthMember; import java.net.URI; @@ -39,17 +40,14 @@ public ResponseEntity login( return ResponseEntity.ok().body(tokenResponse); } - @PostMapping("/login/check") - public ResponseEntity check( - @RequestBody MemberRequest memberRequest + @GetMapping("/login/check") + public ResponseEntity check( + @AuthMember Member member ) { - - String adminName = memberRequest.getName(); - TokenResponse tokenResponse = new TokenResponse(adminName); return ResponseEntity.ok() .header("Connection", "keep-alive") .header("Keep-Alive", "timeout=60") - .body(tokenResponse); + .body(new MemberResponse(null,member.getName(),null)); } diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java index a55a440db..37e35e444 100644 --- a/src/main/java/roomescape/member/MemberDao.java +++ b/src/main/java/roomescape/member/MemberDao.java @@ -65,4 +65,6 @@ public Member findByName(String name) { name ); } + + } diff --git a/src/main/java/roomescape/member/MemberResponse.java b/src/main/java/roomescape/member/MemberResponse.java index b9fa3b97a..dd5eb89b9 100644 --- a/src/main/java/roomescape/member/MemberResponse.java +++ b/src/main/java/roomescape/member/MemberResponse.java @@ -1,5 +1,8 @@ package roomescape.member; +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) public class MemberResponse { private Long id; private String name; diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index fb4361c56..f413ced2b 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -18,6 +18,16 @@ public MemberResponse createMember(MemberRequest memberRequest) { return new MemberResponse(member.getId(), member.getName(), member.getEmail()); } + public Member findByToken(String token) { + if (!jwtTokenProvider.validateToken(token)) { + throw new RuntimeException("유효하지 않은 토큰입니다."); + } + + String email = jwtTokenProvider.getPayload(token); + + return memberDao.findByEmail(email); + } + public TokenResponse login(MemberRequest memberRequest) { Member member = memberDao.findByEmailAndPassword( memberRequest.getEmail(), diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index f71c7a179..7860dbf2c 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -1,5 +1,6 @@ package roomescape.reservation; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -7,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import roomescape.infrastructure.AuthMember; import roomescape.member.Member; import java.net.URI; @@ -27,7 +29,8 @@ public List list() { } @PostMapping("/reservations") - public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, Member member) { + public ResponseEntity create(@AuthMember Member member, + @RequestBody ReservationRequest reservationRequest) { if (reservationRequest.getDate() == null || reservationRequest.getTheme() == null diff --git a/src/main/java/roomescape/reservation/ReservationDao.java b/src/main/java/roomescape/reservation/ReservationDao.java index a4972430c..27999852c 100644 --- a/src/main/java/roomescape/reservation/ReservationDao.java +++ b/src/main/java/roomescape/reservation/ReservationDao.java @@ -43,12 +43,12 @@ public List findAll() { ))); } - public Reservation save(ReservationRequest reservationRequest) { + public Reservation save(ReservationRequest reservationRequest , String name) { KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(connection -> { PreparedStatement ps = connection.prepareStatement("INSERT INTO reservation(date, name, theme_id, time_id) VALUES (?, ?, ?, ?)", new String[]{"id"}); ps.setString(1, reservationRequest.getDate()); - ps.setString(2, reservationRequest.getName()); + ps.setString(2, name); ps.setLong(3, reservationRequest.getTheme()); ps.setLong(4, reservationRequest.getTime()); return ps; @@ -64,7 +64,7 @@ public Reservation save(ReservationRequest reservationRequest) { return new Reservation( keyHolder.getKey().longValue(), - reservationRequest.getName(), + name, reservationRequest.getDate(), time, theme diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index 69b075279..8c87361f2 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -1,30 +1,31 @@ package roomescape.reservation; -import jdk.jpackage.internal.WinExeBundler; import org.springframework.stereotype.Service; +import roomescape.infrastructure.JwtTokenProvider; import roomescape.member.Member; import roomescape.member.MemberDao; +import roomescape.member.MemberService; import java.util.List; @Service public class ReservationService { - private ReservationDao reservationDao; - private MemberDao memberDao; + private final ReservationDao reservationDao; + private final MemberService memberService; - public ReservationService(ReservationDao reservationDao, MemberDao memberDao) { + public ReservationService(ReservationDao reservationDao, MemberService memberService) { this.reservationDao = reservationDao; - this.memberDao = memberDao; + this.memberService = memberService; } - public ReservationResponse save(ReservationRequest reservationRequest, Member member) { - String reservationName = reservationRequest.getName(); + public ReservationResponse save(ReservationRequest reservationRequest,Member member) { - - if (reservationName != null && !reservationName.isBlank()) { - - } else { - reservationName = loginMember.getName(); + String reservationName; + if(reservationRequest.getName()==null){ + reservationName = member.getName(); + } + else{ + reservationName = reservationRequest.getName(); } Reservation reservation = reservationDao.save(reservationRequest, reservationName); From 9234df4652cdabbb924e4b2b3bd67a445c87aef4 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:01:29 +0900 Subject: [PATCH 05/54] =?UTF-8?q?feat=20:=20AdminInterceptor=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AdminInterceptor.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/main/java/roomescape/application/AdminInterceptor.java diff --git a/src/main/java/roomescape/application/AdminInterceptor.java b/src/main/java/roomescape/application/AdminInterceptor.java new file mode 100644 index 000000000..9a5e0431e --- /dev/null +++ b/src/main/java/roomescape/application/AdminInterceptor.java @@ -0,0 +1,53 @@ +package roomescape.application; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import roomescape.infrastructure.JwtTokenProvider; +import roomescape.member.Member; +import roomescape.member.MemberDao; + +import java.util.Arrays; + +@Component +public class AdminInterceptor implements HandlerInterceptor { + private final JwtTokenProvider jwtTokenProvider; + private final MemberDao memberDao; + + public AdminInterceptor(JwtTokenProvider jwtTokenProvider, MemberDao memberDao) { + this.jwtTokenProvider = jwtTokenProvider; + this.memberDao = memberDao; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String token = extractToken(request); + + if (token == null || !jwtTokenProvider.validateToken(token)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return false; + } + + String email = jwtTokenProvider.getPayload(token); + Member member = memberDao.findByEmail(email); + + if (member == null || !"ADMIN".equals(member.getRole())) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return false; + } + + return true; + } + + private String extractToken(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) return null; + return Arrays.stream(cookies) + .filter(c -> "token".equals(c.getName())) + .map(Cookie::getValue) + .findFirst() + .orElse(null); + } +} \ No newline at end of file From 103e6bb5e6b7efc75821dccba9fe569e40e94d4d Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:17:26 +0900 Subject: [PATCH 06/54] =?UTF-8?q?feat(webConfig)=20:=20admin=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=EC=85=89=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/AdminInterceptor.java | 2 +- .../roomescape/application/WebMvcConfig.java | 11 +++++++- src/test/java/roomescape/MissionStepTest.java | 28 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/java/roomescape/application/AdminInterceptor.java b/src/main/java/roomescape/application/AdminInterceptor.java index 9a5e0431e..622c84d67 100644 --- a/src/main/java/roomescape/application/AdminInterceptor.java +++ b/src/main/java/roomescape/application/AdminInterceptor.java @@ -34,7 +34,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons Member member = memberDao.findByEmail(email); if (member == null || !"ADMIN".equals(member.getRole())) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setStatus(401); return false; } diff --git a/src/main/java/roomescape/application/WebMvcConfig.java b/src/main/java/roomescape/application/WebMvcConfig.java index b2fb692da..9f7aa0cdb 100644 --- a/src/main/java/roomescape/application/WebMvcConfig.java +++ b/src/main/java/roomescape/application/WebMvcConfig.java @@ -2,6 +2,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @@ -10,13 +11,21 @@ @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final AuthenticationPrincipalArgumentResolver authResolver; + private final AdminInterceptor adminInterceptor; - public WebMvcConfig(AuthenticationPrincipalArgumentResolver authResolver) { + public WebMvcConfig(AuthenticationPrincipalArgumentResolver authResolver, AdminInterceptor adminInterceptor) { this.authResolver = authResolver; + this.adminInterceptor = adminInterceptor; } @Override public void addArgumentResolvers(List resolvers) { resolvers.add(authResolver); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor) + .addPathPatterns("/admin/**"); + } } \ No newline at end of file diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index bed9fe364..8d4154cea 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -75,6 +75,28 @@ public class MissionStepTest { assertThat(adminResponse.as(ReservationResponse.class).getName()).isEqualTo("브라운"); } + + @Test + void 삼단계() { + String brownToken = createToken("brown@email.com"); + + RestAssured.given().log().all() + .cookie("token", brownToken) + .get("/admin") + .then().log().all() + .statusCode(401); + + String adminToken = createToken("admin@email.com"); + + RestAssured.given().log().all() + .cookie("token", adminToken) + .get("/admin") + .then().log().all() + .statusCode(200); + } + + + public String createToken(String payload) { Claims claims = Jwts.claims().setSubject(payload); Date now = new Date(); @@ -89,5 +111,11 @@ public String createToken(String payload) { .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); } + + + + + + } From ecd0c7f9c282d43fa28f500d87bb4f92cd07e9c4 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:37:08 +0900 Subject: [PATCH 07/54] =?UTF-8?q?fix=20:=20=EA=B0=9C=ED=96=89=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/AuthorizationExtractor.java | 9 --------- src/main/java/roomescape/member/MemberDao.java | 15 --------------- .../java/roomescape/member/MemberService.java | 2 +- .../reservation/ReservationController.java | 1 - .../roomescape/reservation/ReservationDao.java | 2 +- .../reservation/ReservationService.java | 9 +++------ 6 files changed, 5 insertions(+), 33 deletions(-) delete mode 100644 src/main/java/roomescape/infrastructure/AuthorizationExtractor.java diff --git a/src/main/java/roomescape/infrastructure/AuthorizationExtractor.java b/src/main/java/roomescape/infrastructure/AuthorizationExtractor.java deleted file mode 100644 index f2c8b4d98..000000000 --- a/src/main/java/roomescape/infrastructure/AuthorizationExtractor.java +++ /dev/null @@ -1,9 +0,0 @@ -package roomescape.infrastructure; - -import jakarta.servlet.http.HttpServletRequest; - -public interface AuthorizationExtractor { - String AUTHORIZATION = "Authorization"; - - T extract(HttpServletRequest request); -} diff --git a/src/main/java/roomescape/member/MemberDao.java b/src/main/java/roomescape/member/MemberDao.java index 37e35e444..ecca96018 100644 --- a/src/main/java/roomescape/member/MemberDao.java +++ b/src/main/java/roomescape/member/MemberDao.java @@ -52,19 +52,4 @@ public Member findByEmail(String email) { email ); } - - public Member findByName(String name) { - return jdbcTemplate.queryForObject( - "SELECT id, name, email, role FROM member WHERE name = ?", - (rs, rowNum) -> new Member( - rs.getLong("id"), - rs.getString("name"), - rs.getString("email"), - rs.getString("role") - ), - name - ); - } - - } diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index f413ced2b..51641bc37 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -8,7 +8,7 @@ public class MemberService { private MemberDao memberDao; private JwtTokenProvider jwtTokenProvider; - public MemberService(MemberDao memberDao, JwtTokenProvider jwtTokenProvider) { + public MemberService(MemberDao memberDao, JwtTokenProvider jwtTokenProvider) { this.memberDao = memberDao; this.jwtTokenProvider = jwtTokenProvider; } diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index 7860dbf2c..160f17a84 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -1,6 +1,5 @@ package roomescape.reservation; -import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/roomescape/reservation/ReservationDao.java b/src/main/java/roomescape/reservation/ReservationDao.java index 27999852c..b029b348c 100644 --- a/src/main/java/roomescape/reservation/ReservationDao.java +++ b/src/main/java/roomescape/reservation/ReservationDao.java @@ -43,7 +43,7 @@ public List findAll() { ))); } - public Reservation save(ReservationRequest reservationRequest , String name) { + public Reservation save(ReservationRequest reservationRequest, String name) { KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(connection -> { PreparedStatement ps = connection.prepareStatement("INSERT INTO reservation(date, name, theme_id, time_id) VALUES (?, ?, ?, ?)", new String[]{"id"}); diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index 8c87361f2..2fd6665c0 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -1,9 +1,7 @@ package roomescape.reservation; import org.springframework.stereotype.Service; -import roomescape.infrastructure.JwtTokenProvider; import roomescape.member.Member; -import roomescape.member.MemberDao; import roomescape.member.MemberService; import java.util.List; @@ -18,13 +16,12 @@ public ReservationService(ReservationDao reservationDao, MemberService memberSer this.memberService = memberService; } - public ReservationResponse save(ReservationRequest reservationRequest,Member member) { + public ReservationResponse save(ReservationRequest reservationRequest, Member member) { String reservationName; - if(reservationRequest.getName()==null){ + if (reservationRequest.getName() == null) { reservationName = member.getName(); - } - else{ + } else { reservationName = reservationRequest.getName(); } From 334327e1aedc6ac61793ae1b04270663ddb84f0b Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:39:30 +0900 Subject: [PATCH 08/54] =?UTF-8?q?fix=20:=20=EA=B0=9C=ED=96=89=EC=A0=95?= =?UTF-8?q?=EB=A6=AC2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/member/MemberController.java | 3 --- .../java/roomescape/reservation/ReservationService.java | 8 +++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index aac6575c4..e8b72e36e 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -1,7 +1,6 @@ package roomescape.member; import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -30,7 +29,6 @@ public ResponseEntity login( Cookie cookie = new Cookie("token", tokenValue); - cookie.setHttpOnly(true); cookie.setPath("/"); cookie.setMaxAge(3600); @@ -50,7 +48,6 @@ public ResponseEntity check( .body(new MemberResponse(null,member.getName(),null)); } - @PostMapping("/members") public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) { MemberResponse member = memberService.createMember(memberRequest); diff --git a/src/main/java/roomescape/reservation/ReservationService.java b/src/main/java/roomescape/reservation/ReservationService.java index 2fd6665c0..8aedc54f6 100644 --- a/src/main/java/roomescape/reservation/ReservationService.java +++ b/src/main/java/roomescape/reservation/ReservationService.java @@ -9,11 +9,8 @@ @Service public class ReservationService { private final ReservationDao reservationDao; - private final MemberService memberService; - - public ReservationService(ReservationDao reservationDao, MemberService memberService) { + public ReservationService(ReservationDao reservationDao) { this.reservationDao = reservationDao; - this.memberService = memberService; } public ReservationResponse save(ReservationRequest reservationRequest, Member member) { @@ -42,7 +39,8 @@ public void deleteById(Long id) { public List findAll() { return reservationDao.findAll().stream() - .map(it -> new ReservationResponse(it.getId(), it.getName(), it.getTheme().getName(), it.getDate(), it.getTime().getValue())) + .map(it -> new ReservationResponse(it.getId(), it.getName(), + it.getTheme().getName(), it.getDate(), it.getTime().getValue())) .toList(); } } From eeb4f667ca61bf192d66ae5fdb80fbe5e1faecda Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:47:37 +0900 Subject: [PATCH 09/54] =?UTF-8?q?fix=20:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/{infrastructure => auth}/AuthMember.java | 2 +- src/main/java/roomescape/member/MemberController.java | 2 +- .../{application => presentation}/AdminInterceptor.java | 2 +- .../AuthenticationPrincipalArgumentResolver.java | 4 ++-- .../{application => presentation}/WebMvcConfig.java | 2 +- .../java/roomescape/reservation/ReservationController.java | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/roomescape/{infrastructure => auth}/AuthMember.java (88%) rename src/main/java/roomescape/{application => presentation}/AdminInterceptor.java (98%) rename src/main/java/roomescape/{application => presentation}/AuthenticationPrincipalArgumentResolver.java (96%) rename src/main/java/roomescape/{application => presentation}/WebMvcConfig.java (96%) diff --git a/src/main/java/roomescape/infrastructure/AuthMember.java b/src/main/java/roomescape/auth/AuthMember.java similarity index 88% rename from src/main/java/roomescape/infrastructure/AuthMember.java rename to src/main/java/roomescape/auth/AuthMember.java index 0ff90e6d5..a52262a06 100644 --- a/src/main/java/roomescape/infrastructure/AuthMember.java +++ b/src/main/java/roomescape/auth/AuthMember.java @@ -1,4 +1,4 @@ -package roomescape.infrastructure; +package roomescape.auth; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index e8b72e36e..77449e65b 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import roomescape.infrastructure.AuthMember; +import roomescape.auth.AuthMember; import java.net.URI; diff --git a/src/main/java/roomescape/application/AdminInterceptor.java b/src/main/java/roomescape/presentation/AdminInterceptor.java similarity index 98% rename from src/main/java/roomescape/application/AdminInterceptor.java rename to src/main/java/roomescape/presentation/AdminInterceptor.java index 622c84d67..69f63445b 100644 --- a/src/main/java/roomescape/application/AdminInterceptor.java +++ b/src/main/java/roomescape/presentation/AdminInterceptor.java @@ -1,4 +1,4 @@ -package roomescape.application; +package roomescape.presentation; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java b/src/main/java/roomescape/presentation/AuthenticationPrincipalArgumentResolver.java similarity index 96% rename from src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java rename to src/main/java/roomescape/presentation/AuthenticationPrincipalArgumentResolver.java index 06766402f..537080f3a 100644 --- a/src/main/java/roomescape/application/AuthenticationPrincipalArgumentResolver.java +++ b/src/main/java/roomescape/presentation/AuthenticationPrincipalArgumentResolver.java @@ -1,4 +1,4 @@ -package roomescape.application; +package roomescape.presentation; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; @@ -8,7 +8,7 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import roomescape.infrastructure.AuthMember; +import roomescape.auth.AuthMember; import roomescape.infrastructure.JwtTokenProvider; import roomescape.member.Member; import roomescape.member.MemberService; diff --git a/src/main/java/roomescape/application/WebMvcConfig.java b/src/main/java/roomescape/presentation/WebMvcConfig.java similarity index 96% rename from src/main/java/roomescape/application/WebMvcConfig.java rename to src/main/java/roomescape/presentation/WebMvcConfig.java index 9f7aa0cdb..fc1c15718 100644 --- a/src/main/java/roomescape/application/WebMvcConfig.java +++ b/src/main/java/roomescape/presentation/WebMvcConfig.java @@ -1,4 +1,4 @@ -package roomescape.application; +package roomescape.presentation; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; diff --git a/src/main/java/roomescape/reservation/ReservationController.java b/src/main/java/roomescape/reservation/ReservationController.java index 160f17a84..c2c60c025 100644 --- a/src/main/java/roomescape/reservation/ReservationController.java +++ b/src/main/java/roomescape/reservation/ReservationController.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import roomescape.infrastructure.AuthMember; +import roomescape.auth.AuthMember; import roomescape.member.Member; import java.net.URI; From a75257b7627ab2b95c42b9f781134ebad05b8888 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Sat, 27 Dec 2025 01:52:46 +0900 Subject: [PATCH 10/54] =?UTF-8?q?fix=20:=201=EB=8B=A8=EA=B3=84=20login=20?= =?UTF-8?q?=EC=BF=A0=ED=82=A4=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20tokenResp?= =?UTF-8?q?onse=20dto=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/member/MemberController.java | 11 +++++------ src/main/java/roomescape/member/MemberService.java | 4 ++-- src/main/java/roomescape/member/TokenResponse.java | 7 ------- 3 files changed, 7 insertions(+), 15 deletions(-) delete mode 100644 src/main/java/roomescape/member/TokenResponse.java diff --git a/src/main/java/roomescape/member/MemberController.java b/src/main/java/roomescape/member/MemberController.java index 77449e65b..b4aa81b05 100644 --- a/src/main/java/roomescape/member/MemberController.java +++ b/src/main/java/roomescape/member/MemberController.java @@ -20,22 +20,21 @@ public MemberController(MemberService memberService) { } @PostMapping("/login") - public ResponseEntity login( + public ResponseEntity login( @RequestBody MemberRequest memberRequest, HttpServletResponse response) { - TokenResponse tokenResponse = memberService.login(memberRequest); - String tokenValue = tokenResponse.accessToken(); + String tokenValue = memberService.login(memberRequest); Cookie cookie = new Cookie("token", tokenValue); - cookie.setHttpOnly(true); cookie.setPath("/"); cookie.setMaxAge(3600); - response.addCookie(cookie); - return ResponseEntity.ok().body(tokenResponse); + return ResponseEntity.ok() + .header("Keep-Alive", "timeout=60") + .build(); } @GetMapping("/login/check") diff --git a/src/main/java/roomescape/member/MemberService.java b/src/main/java/roomescape/member/MemberService.java index 51641bc37..fe2731f6a 100644 --- a/src/main/java/roomescape/member/MemberService.java +++ b/src/main/java/roomescape/member/MemberService.java @@ -28,7 +28,7 @@ public Member findByToken(String token) { return memberDao.findByEmail(email); } - public TokenResponse login(MemberRequest memberRequest) { + public String login(MemberRequest memberRequest) { Member member = memberDao.findByEmailAndPassword( memberRequest.getEmail(), memberRequest.getPassword() @@ -40,6 +40,6 @@ public TokenResponse login(MemberRequest memberRequest) { String accessToken = jwtTokenProvider.createToken(member.getEmail()); - return new TokenResponse(accessToken); + return accessToken; } } diff --git a/src/main/java/roomescape/member/TokenResponse.java b/src/main/java/roomescape/member/TokenResponse.java deleted file mode 100644 index 36c921d10..000000000 --- a/src/main/java/roomescape/member/TokenResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package roomescape.member; - -public record TokenResponse( - String accessToken -) { - -} From f95bdc5cadf0af4727d7468b1a9d9f1a46fe6b76 Mon Sep 17 00:00:00 2001 From: westnowjin <101540598+nonactress@users.noreply.github.com> Date: Wed, 31 Dec 2025 12:28:53 +0900 Subject: [PATCH 11/54] =?UTF-8?q?feat=20:=20time=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EB=A1=9C=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20repositor?= =?UTF-8?q?y=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +-- src/main/java/roomescape/theme/Theme.java | 8 +++++ src/main/java/roomescape/time/Time.java | 14 ++++++++ .../java/roomescape/time/TimeRepository.java | 36 +++++++++++++++++++ src/main/resources/application.properties | 15 ++++---- 5 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/main/java/roomescape/time/TimeRepository.java diff --git a/build.gradle b/build.gradle index 8d52aebc6..74e7fa8cb 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.0.0' @@ -23,7 +23,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-impl:0.11.2' implementation 'io.jsonwebtoken:jjwt-gson:0.11.2' - testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa' testImplementation 'io.rest-assured:rest-assured:5.3.1' runtimeOnly 'com.h2database:h2' diff --git a/src/main/java/roomescape/theme/Theme.java b/src/main/java/roomescape/theme/Theme.java index 430a6239c..7577957eb 100644 --- a/src/main/java/roomescape/theme/Theme.java +++ b/src/main/java/roomescape/theme/Theme.java @@ -1,7 +1,15 @@ package roomescape.theme; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +@Entity public class Theme { + @Id + @GeneratedValue() private Long id; + private String name; private String description; diff --git a/src/main/java/roomescape/time/Time.java b/src/main/java/roomescape/time/Time.java index 008ed93cf..1634f15b3 100644 --- a/src/main/java/roomescape/time/Time.java +++ b/src/main/java/roomescape/time/Time.java @@ -1,9 +1,19 @@ package roomescape.time; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity public class Time { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; private String value; + private boolean deleted = false; // Soft Delete를 위한 필드 + public Time(Long id, String value) { this.id = id; this.value = value; @@ -24,4 +34,8 @@ public Long getId() { public String getValue() { return value; } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } } diff --git a/src/main/java/roomescape/time/TimeRepository.java b/src/main/java/roomescape/time/TimeRepository.java new file mode 100644 index 000000000..817f70391 --- /dev/null +++ b/src/main/java/roomescape/time/TimeRepository.java @@ -0,0 +1,36 @@ +package roomescape.time; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class TimeRepository { + + @PersistenceContext + private EntityManager em; + + public TimeRepository(EntityManager em) { + this.em = em; + } + + public List