Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spring MVC] 김수현 미션 제출합니다 #3

Open
wants to merge 4 commits into
base: joamksh
Choose a base branch
from

Conversation

joamksh
Copy link

@joamksh joamksh commented Apr 30, 2024

No description provided.

request
 /login에 email, password 값을 body에 포함하세요.
response
 Cookie에 "token"값으로 토큰이 포함되도록 하세요
상단바 우측 로그인 상태를 표현해주기 위해 사용자의 정보를 조회하는 API를 구현하세요.
Cookie를 이용하여 로그인 사용자의 정보확인하세요.
@joamksh
Copy link
Author

joamksh commented Apr 30, 2024

현재 1단계만 통과된 상태이고 2단계는 에러를 너무 많이 만나서 다시 정리하고 있습니다.
어떠한 방식으로 진행하셨는지 궁금하네요!

@joamksh joamksh changed the title Mvc(인증) [Spring MVC] 김수현 미션 제출합니다 Apr 30, 2024
@joamksh
Copy link
Author

joamksh commented Apr 30, 2024

안녕하세요! 확실히 입문보다는 기초로 바뀌면서 난이도가 급상승한 느낌이 듭니다. 저번보다 더 많은 시간을 투자해야겠다는 생각이 들어요. 어떠셨는지 궁금하고, 솔직히 개념이 너무 부족한 것 같아서 이번 내용을 금요일 전까지 더 뜯어보고 2단계 3단계도 진행해야하는데 조금 막막하네요..

@joamksh
Copy link
Author

joamksh commented May 7, 2024

2단계 수행 중에 계속 test에서 에러가 나는데 사실 전체적인 로직의 이해가 잘 되지 않는 상황이라서 어디서 오류를 잡아야 할지 찾는 부분이 어려운 것 같습니다! 혹시 제 코드에서 오류나 바꿔야 될 부분에 대한 의견을 주시면 큰 도움이 될 것 같아요
아무래도 완성하고 의견 주고받기가 어려울 것 같고 이번 주 스터디 전까지 코드를 분석하고 2단계 & 3단계 수행을 하기 위해서 조금 더 시간을 보내야 할 것 같습니다

@dlrkdus
Copy link

dlrkdus commented May 8, 2024

수현님 혹시 어떤 오류인지 오류 코드 중요한 부분만 복사해서 보여주실 수 있나요?

@joamksh
Copy link
Author

joamksh commented May 8, 2024

테스트2단계 진행했을 때 오류 결과 내용 전부 올립니다.

Task :compileJava UP-TO-DATE
Task :processResources UP-TO-DATE
Task :classes UP-TO-DATE
Task :compileTestJava UP-TO-DATE
Task :processTestResources NO-SOURCE
Task :testClasses UP-TO-DATE
Task :test
5월 08, 2024 11:32:42 오후 org.junit.platform.launcher.core.EngineDiscoveryOrchestrator lambda$logTestDescriptorExclusionReasons$7
INFO: 0 containers and 1 tests were Method or class mismatch
23:32:43.021 [Test worker] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [roomescape.MissionStepTest]: MissionStepTest does not declare any static, non-private, non-final, nested classes annotated with @configuration.
23:32:43.156 [Test worker] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration roomescape.RoomescapeApplication for test class roomescape.MissionStepTest

. ____ _ __ _ _
/\ / ' __ _ () __ __ _ \ \ \
( ( )_
_ | '_ | '| | ' / ` | \ \ \
\/ )| |)| | | | | || (| | ) ) ) )
' |
| .__|| ||| |_, | / / / /
=========|
|==============|/=////
:: Spring Boot :: (v3.1.0)

2024-05-08T23:32:43.724+09:00 INFO 23240 --- [ Test worker] roomescape.MissionStepTest : Starting MissionStepTest using Java 17.0.10 with PID 23240 (started by one in C:\Users\one\Documents\sompring\기초\spring-basic-roomescape-playground)
2024-05-08T23:32:43.727+09:00 INFO 23240 --- [ Test worker] roomescape.MissionStepTest : No active profile set, falling back to 1 default profile: "default"
2024-05-08T23:32:46.888+09:00 INFO 23240 --- [ Test worker] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2024-05-08T23:32:46.910+09:00 INFO 23240 --- [ Test worker] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-05-08T23:32:46.911+09:00 INFO 23240 --- [ Test worker] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.8]
2024-05-08T23:32:47.185+09:00 INFO 23240 --- [ Test worker] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-05-08T23:32:47.188+09:00 INFO 23240 --- [ Test worker] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3082 ms
2024-05-08T23:32:47.242+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2024-05-08T23:32:47.604+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:database user=SA
2024-05-08T23:32:47.610+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2024-05-08T23:32:47.632+09:00 INFO 23240 --- [ Test worker] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:database'
2024-05-08T23:32:48.309+09:00 INFO 23240 --- [ Test worker] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2024-05-08T23:32:48.894+09:00 INFO 23240 --- [ Test worker] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2024-05-08T23:32:48.913+09:00 INFO 23240 --- [ Test worker] roomescape.MissionStepTest : Started MissionStepTest in 5.539 seconds (process running for 6.992)
2024-05-08T23:32:48.965+09:00 INFO 23240 --- [ Test worker] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2024-05-08T23:32:48.976+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2024-05-08T23:32:48.980+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.

. ____ _ __ _ _
/\ / ' __ _ () __ __ _ \ \ \
( ( )_
_ | '_ | '| | ' / ` | \ \ \
\/ )| |)| | | | | || (| | ) ) ) )
' |
| .__|| ||| |_, | / / / /
=========|
|==============|/=////
:: Spring Boot :: (v3.1.0)

2024-05-08T23:32:49.041+09:00 INFO 23240 --- [ Test worker] roomescape.MissionStepTest : Starting MissionStepTest using Java 17.0.10 with PID 23240 (started by one in C:\Users\one\Documents\sompring\기초\spring-basic-roomescape-playground)
2024-05-08T23:32:49.041+09:00 INFO 23240 --- [ Test worker] roomescape.MissionStepTest : No active profile set, falling back to 1 default profile: "default"
2024-05-08T23:32:49.621+09:00 INFO 23240 --- [ Test worker] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2024-05-08T23:32:49.623+09:00 INFO 23240 --- [ Test worker] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-05-08T23:32:49.623+09:00 INFO 23240 --- [ Test worker] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.8]
2024-05-08T23:32:49.684+09:00 INFO 23240 --- [ Test worker] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-05-08T23:32:49.685+09:00 INFO 23240 --- [ Test worker] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 638 ms
2024-05-08T23:32:49.709+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Starting...
2024-05-08T23:32:49.712+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.pool.HikariPool : HikariPool-2 - Added connection conn10: url=jdbc:h2:mem:database user=SA
2024-05-08T23:32:49.712+09:00 INFO 23240 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Start completed.
2024-05-08T23:32:49.713+09:00 INFO 23240 --- [ Test worker] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:database'
2024-05-08T23:32:49.852+09:00 INFO 23240 --- [ Test worker] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2024-05-08T23:32:49.985+09:00 INFO 23240 --- [ Test worker] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2024-05-08T23:32:49.992+09:00 INFO 23240 --- [ Test worker] roomescape.MissionStepTest : Started MissionStepTest in 1.007 seconds (process running for 8.071)
Request method: POST
Request URI: http://localhost:8080/reservations
Proxy:
Request params:
Query params:
Form params:
Path params:
Headers: Accept=/
Content-Type=application/json
Cookies: token=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbkBlbWFpbC5jb20iLCJpYXQiOjE3MTUxNzg3NzEsImV4cCI6MTcxNTE4MjM3MX0.raNyhjQSo7ybvWUzBZ9YA7H3Hwqxh5QzTE179u0Ci-gPcME0pJcYU7uC07RMTW2SubX-ZclDO2gZfa-Hf9Y65A
Multiparts:
Body:
{
"date": "2024-03-01",
"theme": "1",
"time": "1"
}
2024-05-08T23:32:53.058+09:00 INFO 23240 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-05-08T23:32:53.059+09:00 INFO 23240 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-05-08T23:32:53.060+09:00 INFO 23240 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
java.lang.IllegalStateException: No primary or single unique constructor found for class roomescape.member.Member
at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:268)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:221)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:85)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:149)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:181)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:148)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at dev.akkinoc.spring.boot.logback.access.tomcat.LogbackAccessTomcatValve.invoke(LogbackAccessTomcatValve.kt:55)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:842)
POST /reservations HTTP/1.1
accept: /
accept-encoding: gzip,deflate
connection: Keep-Alive
content-length: 44
content-type: application/json
cookie: token=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbkBlbWFpbC5jb20iLCJpYXQiOjE3MTUxNzg3NzEsImV4cCI6MTcxNTE4MjM3MX0.raNyhjQSo7ybvWUzBZ9YA7H3Hwqxh5QzTE179u0Ci-gPcME0pJcYU7uC07RMTW2SubX-ZclDO2gZfa-Hf9Y65A
host: localhost:8080
user-agent: Apache-HttpClient/4.5.13 (Java/17.0.10)

HTTP/1.1 400 Bad Request
Connection: close
Content-Length: 0
Date: Wed, 08 May 2024 14:32:53 GMT

Copy link
Author

@joamksh joamksh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 보니 전체적인 코드 이해가 부족한 것 같네요... 제가 내일 중으로 좀 더 코드를 다듬고 해석해서 정리하고 2단계 오류를 해결해보도록 하겠습니다!

void 이단계() {
//토큰 생성
String token = createToken("admin@email.com", "password");

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createToken을 어떻게 할지 몰라서
@Autowired
private JwtTokenProvider jwtTokenProvider;
private String createToken(String email, String password) {
return jwtTokenProvider.generateToken(email);
}

이렇게 임의로 제가 적었는데 이 부분을 확신을 갖고 적은 게 아니라서 문제인 것 같네요
그냥 테스트만 적었을 때 createToken이 부분을 정의하라고 에러가 뜨는데 가연님은 어떤식으로 하셨는지 궁금합니다!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

내일 리뷰하려다 확인했다 하셔서 봤는데 이건 바로 대답 드릴 수 있을 것 같아서 답변 남겨요 ! ㅎㅎ 저도 이 부분에 대해서 이해가 잘 안 가서 많이 고민했는데 결론은

public String createToken( String email, String password) {
        Map<String, String> params = new HashMap<>();
        params.put("email", "admin@email.com");
        params.put("password", "password");
        ExtractableResponse<Response> response = RestAssured.given().log().all()
                .contentType(ContentType.JSON)
                .body(params)
                .when().post("/login")
                .then().log().all()
                .statusCode(200)
                .extract();
        String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1];
        return token;
    }

이런식으로 테스트코드 일단계에서 로직을 떼와서 새로운 메소드를 테스트 클래스 내에 선언하는 식으로 풀었습니다. 테스트코드 내에 테스트 메소드 외의 메소드를 선언해본 적은 없어서 설마 하면서 해봤는데 돼서 굉장히 허무했다죠 .. ㅎㅎ 아직 오류 코드 안 읽어봤긴 했는데 혹시 이 오류와 밀접한 관련이 있다면 고쳐보시고 다시 실행시켜보세요 !

Copy link
Author

@joamksh joamksh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가연님이 알려주신대로 수정했고, 테스트를 한 줄씩 실행시켜봤는데
쿠키관련 문제가 있는 것 같아서 우선 통과라도 해보자하고 테스트 코드를 수정했습니다
그 과정에서 "어드민"이름 관련된 문제가 있는 것 같아요 가연님은 어떤 방식으로 하셨는지 궁금합니다!

.extract();

// API응답 검증
assertThat(adminResponse.statusCode()).isEqualTo(201);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.cookie("token", token)
쿠키값이 예상값과 결과값이 계속 다르다는 식으로 오류가 떠서
.header("Authorization", "Bearer " + token)이런식으로 임의로 바꿔서 진행했는데 이후에
assertThat(response.as(ReservationResponse.class).getName()).isEqualTo("어드민");이 코드에서 진행이 안되는 것을 확인했습니다
로그인이 되면 어드민이란 이름을 저장해야할 것 같은데 제가 authloing에다가 생성했는데 여기에서는 사용하지 않고 있어서 어떻게 해야할 지 모르겠네요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package roomescape.Auth;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AuthController {

@GetMapping("/login/check")
public ResponseEntity<UserInfoResponse> checkLoginStatus(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();
    String token = null;
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("token")) {
                token = cookie.getValue();
                break;
            }
        }
    }

    if (token == null) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null);
    }

    String userInfo = extractUserInfoFromToken(token);
    if (userInfo != null) {
        return ResponseEntity.ok(new UserInfoResponse(userInfo));
    } else {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }
}

private String extractUserInfoFromToken(String token) {
    return "어드민";
}

}

Copy link

@dlrkdus dlrkdus May 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

흠 이거 UserInfoResponse 새로 파셔서 하셨네요? 우선 저는 login check에 대한 api의 흐름을

  1. HttpServletRequest를 받는다 .
  2. 받은 요청에서 쿠키를 추출한다.
  3. 쿠키에서 토큰을 추출한다. //여기까진 잘하셨네요.
  4. 추출한 토큰으로 멤버 아이디를 찾는다.
  5. 멤버 아이디로 멤버를 찾아 멤버 정보로 MemberResponse를 만들어 반환한다.

이런 로직으로 이해했습니다.

이미 cookie.getValue()로 토큰을 추출하셨기 때문에 extractUserInfoFromToken 이 메소드는 필요 없어보여요.

그럼 토큰을 추출했으니 여기에 담긴 멤버 정보를 빼내야합니다.

        Long memberId = Long.valueOf(Jwts.parserBuilder()
                .setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes()))
                .build()
                .parseClaimsJws(token)
                .getBody().getSubject());

스터디 자료에 잘 나와있더라고요.
여기서 얻은 멤버아이디로 데이터베이스에서 멤버를 조회해와 MemberResponse로 만드는 것으로 이해했습니다.
제 생각에는 MemberResponse를 제공해주고 있기 때문에 같은 역할을 하는 UserInfoResponse는 필요없어보여요.

이건 일단 올려주신 checkLoginStatus 코드에 대한 피드백이지만 사실 이건 일단계 로직인데 이단계 테스트와는 무슨 상관인지 잘 모르겠네요 ?-?

public ResponseEntity<UserInfoResponse> checkLoginStatus(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
String token = null;
if (cookies != null) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

참고로 전 이 로직을 서비스 파일로 분리했습니다! 컨트롤러에는 최대한 처리 로직을 넣지 않는 프로그래밍을 추구하려고요.

    public String extractTokenFromCookie(Cookie[] cookies) {
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("token")) { //쿠키 배열에서 원하는 토큰을 추출합니다.
                return cookie.getValue();
            }
        }

        return "";
    }

import java.security.Key;
import java.util.Date;

@Component
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@component 등록 좋아요 bb
혹시 Component는 왜 달아야 하는지 아시나요 ?

private final Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512);
public String generateToken(String email) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + 3600000);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

우와 만료 날짜까지는 생각못했어요.. 완전 좋은 것 같아요 저는 코드복붙하기 바빴던 것 같군요 반성합니다 ..

public class JwtTokenProvider {

private final Key secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512);
public String generateToken(String email) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 파라미터로 email만 받으면 Token에 넣을 정보가 email로 한정되지 않을까요?
참고로 저는 Member 로 받아서 id, name, email, role을 추출해 토큰에 담았습니다.

Date expiryDate = new Date(now.getTime() + 3600000);

return Jwts.builder()
.setSubject(email)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subject에 email 정보를 넣으셨군요 ! Subject는 주로 토큰이 발급된 사용자 또는 주체를 식별하는 데 사용된다고 해요. 따라서 email보단 앞서 언급한대로 파라미터를 MemberRequest나 Member로 받아서 멤버 아이디를 넣는게 좋을 것 같아요 !

.setSubject(email)
.setIssuedAt(new Date())
.setExpiration(expiryDate)
.signWith(secretKey)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스터디에서 제공해준 코드에는

 .signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))

이런식으로 사용하던데 그냥 이렇게 넣어도 되는걸까요 ?!


@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest loginRequest, HttpServletResponse response) {
String token = tokenProvider.generateToken(loginRequest.getEmail());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 이 부분을

Member member = memberService.findMember(memberRequest.getEmail(),memberRequest.getPassword()); //멤버조회
String token=memberService.createToken(member); //조회된 멤버 정보로 토큰 생성

이렇게 멤버를 찾아서 해당 멤버 정보로 토큰을 만들었습니다!

Copy link

@dlrkdus dlrkdus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요!
전체적으로 스스로 고민해서 짠 노력의 흔적이 보이는 코드였어요 잘 봤습니다 😊
우선 저는 이번 주차에서 가장 생소했던 부분이 HandlerMethodArgumentResolver였는데, 쉽게 말해 공통로직을 하나의 클래스에 구현해놓는 것으로 주로 인증/인가 처리와 같은 로그인 구현에 많이 쓰인다고 해요 !
저는 이 링크를 참고했습니다 :) 수현님도 헷갈리셨다면 한 번 봐보셔도 좋을 것 같아요

말씀하신대로

.cookie("token", token)
쿠키값이 예상값과 결과값이 계속 다르다는 식으로 오류가 떠서

이 오류를 중점적으로 고민하면서 코드를 살펴봤는데
보다보니 WebMvcConfigurer이 없네요 ?
WebMvcConfigurer에서 addArgumentResolvers를 이용해 LoginMemberArgumentResolver를 resolver에 추가해주어야 하는데, 관련 로직이 없어서 문제가 된 걸 수도 있을 것 같아요. 한 번 디버깅 해보면서 resolveArgument가 실행되고 있는지 확인해보세요!

만약 그래도 오류가 뜬다면 어쨌든 토큰이 기대한 토큰과 맞지 않다는 거니까 resolveArgument에서 토큰 생성하는 부분을 검토해보세요!


assertThat(token).isNotBlank();
@Test
void 중간단계(){
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 중간단계는 역할이 뭘까요 ??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants