트러블이 너무 많다.... ..... 문제덩어리 인간이 된거같은 느낌
트러블 슈팅
문제1
Schedule Request DTO 를 작성할 때 user_id 를 넣어야하는가?
로그인에 성공하기만 하면 그 정보를 저장하고 있을테니까 알아서 저장해줄 수 있는 거 아닌가
해결과정
로그인에 성공하면 어디 정보를 저장하고 있는지 다시 생각해볼 필요가 있을 것 같다...
| 세션/쿠키로 로그인을 구현하는게 목표 -> 서버의 메모리나 DB에 세션 ID 를 저장해둠/ 브라우저는 세션 ID를 쿠키에 저장 -> 브라우저가 서버에 세션ID 만 보냄 -> 서버에서 세션 ID 비교 |
서버에서 세션 ID를 비교하고 저장해둬야한다.
저장 방법: HttpSession session 을 가져오고 아래코드처럼 Controller 에서 sessionUser Entity 형태로 저장
session.setAttribute("loginUser", sessionUser);
@Getter
public class SessionUser {
private final Long id;
private final String name;
private final String email;
public SessionUser(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
}
그럼 세션ID를 저장해두는 공간을 만들어야하나?
-> 따로 설정하지 않으면 "TOMCAT" 이라는 서버 메모리에 아래처럼 저장됨
KEY { VALUE }
sessionId1 { loginUser: (SessionUser1) }
sessionId2 { loginUser: (SessionUser2) }
sessionId3 { loginUser: (SessionUser3) }
약간 이중 MAP 이라고 생각하면 편할듯하다
sessionId 가 TOMCAT 레벨에서의 KEY 가 되고
그 안에서 loginUser 라는 String 이 다시 KEY 가 되어 SessionUser 를 찾을 수 있게 된다.
결론
request 에 userId를 넣을 필요는 없고 로그인 하면 쿠키에 JSESSIONID 가 오기때문에 이 쿠키에서 ID 를 기준으로 user 찾기

문제2
login에 성공하면 자동으로 jpa 가 로그인된 유저인지 확인을 해주나..?
아닐거같음
어떻게 컨트롤러에서 SessionId를 확인해줄 수 있는가
해결과정
생각해보면 Session ID 만 보내는게 아닌데 바로 확인을 해주지 않는다.
SessionUser 를 HttpSession 으로부터 getAttribute 를 사용해서 가져오기
만약에 sessionUser (로그인 목록) 에 보낸 JSESSIONID 가 존재하지 않는다면 (null) 예외처리
ResponseEntity<ResponseDTO> methodName(@Valid @RequestBody RequestDTO request, HttpSession session){
SessionUser sessionUser = (SessionUser) session.getAttribute("loginUser");
if( sessionUser == null){
throw new BeforeLoginUserException();
}
# method 내용 후략
}
결론
JPA 가 자동으로 로그인 되었는지 확인 불가능, sessionID만 들어오니까 확인을 해줘야한다.
컨트롤러에서는 getAttribute 를 사용해서 SessionUser 를 가져오고 로그인 가능한지 직접 확인
문제3
근데 그럼 생성 수정 삭제 (login 이 필요한 행동) 할 때 마다 SessionId를 확인해줘야하는가...
해결과정
함수를 만들어서 Controller 에서 확인하는게 나을까 해서 함수를 작성해봤다.
SessionUser checkAuthorizeUser(HttpSession session){
SessionUser sessionUser = (SessionUser) session.getAttribute("loginUser");
if( sessionUser == null){
throw new BeforeLoginUserException();
}
return sessionUser;
}
하지만 저렇게 구현하면 어쨌든 Controller 에서 매번 checkAuthorizedUser 함수를 호출해줘야하기 때문에 번거로워지고 InterCeptor 를 실무에서 사용한다고 한다.
Interceptor 가 뭔지 더 검색해봤다.
너무 깊게 들어가는 것 같아서 튜터님께 여쭤보니 이후에 이 부분은 Spring Security 와 함께 배운다고 넘어가라고 하셨습니다. . 언젠가 해보는걸로 !! 했다.
아래는 intercepter 구현해본것... 무시하면 됨
interceptor 는 우리가 알고있던 요청 - Controller - Service - Repository - Service - View 순서에서 중간중간 intercept (가로채다, 차단하다 의미) 하여 다음단계로 넘어갈지 말지 결정할 수 있게한다.

내가 사용할건 preHandle() 로 Controller 안에서 getAttribute 로 다 체크해주고 있었던 부분을 Interceptor 로 구현하여 매번 getAttribute 하지 않을 수 있게 할 수 있다.
여기서 고민이 되었던 부분이
POST 요청같은 경우 -> 로그인이 되어있는지만 확인하면 됨
PUT, DELETE 요청같은 경우 -> 로그인이 되어있는지 + 현재 접근하려는 글의 작성자인지도 확인해야함
이었다
일단 공통적으로 로그인이 되어있는 상태인지는 확인해야하므로 interceptor 코드를 작성했다.
참고자료
https://just-joat.tistory.com/4
[Spring] 스프링 Interceptor를 간단한 MVC 예제에 적용해보기
'로그인 된 사용자만 이 페이지를 볼 수 있게 해야할텐데..?' 라고 생각하면서 어떻게 구현해야할지 모르겠다면,스프링에서 제공해주는 Interceptor라는 인터페이스를 사용하면 된다. 먼저, Interc
just-joat.tistory.com
CustomInterceptor 를 만들고 HandlerInterceptor 를 구현하게 만듦
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpSession session = request.getSession(false);
if(session == null){
throw new BeforeLoginUserException();
}
SessionUser user = (SessionUser) session.getAttribute("loginUser");
if (user == null) {
throw new BeforeLoginUserException();
}
return true;
}
}

참고로 request 만 쓰길래 response 와 handler 는 지웠더니 오류가 났다
원래부터 인터페이스가 아래 형태로 지정되어있어서 override 하는 입장에선 바꾸면 안 된다.
# 매개변수: create
# true: session 이 존재하지 않으면 새 세션을 생성하여 반환
# false: session 이 존재하지 않으면 null 반환
HttpSession getSession(boolean create);
원래는 getSession 뒤 인수를 default (true) 로 했었는데 현재 로그인이 되어있는지 확인하는게 목적이니까 새 세션을 만드는것이 아니라 null 을 반환해줘야한다. -> session 이 null 인지도 확인
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
private final LoginCheckInterceptor loginCheckInterceptor;
public MvcConfig(LoginCheckInterceptor loginCheckInterceptor) {
this.loginCheckInterceptor = loginCheckInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/signup")
.excludeHttpMethods(HttpMethod.GET);
}
}
열심히 만든 loginCheckInterceptor 를 실행시키기 위해 MvcConfig 클래스를 만들고 WebMvcConfigurer 를 구현하게 했다.
addInterceptors 를 사용해서 무슨 interceptor 를 언제 실행시키고 언제 실행시키지 않을지 설정해줬다.
추가로 우리는 sessionUser 의 ID 를 Service 계층으로 보내야하는 문제가 남아있다...
Controller 에서 세션을 바로 분석해서 썼을때는 안 해도 됐지만 이젠 create 의 매개변수로 sessionId 를 넘겨줘야한다.
결론
아직까지의 단계에서는 Controller 에서 하나하나 확인해줘도 괜찮다는 튜터님의 답변을 들었습니다!
문제4
SessionUser 를 보낼까 SessionUser ID 를 보낼까
sessionUser 로 받아온 값을 service 에서 새로운 객체 user 로 만들어서 넣는다고 하면 다른 객체가 되어버리면 어쩌지 id만 받아와서 찾아서 넣는게 맞는거겠지
해결과정
ID 만 보내는 게 좋을 것 같다는 생각을 했다
상관없을거같긴한데 ... 왜냐면 객체 자체를 저장하는거니까
그래도 왜 그렇게 생각했냐면 SessionUser 자체는 어차피 User table 에서 가져오기 때문



하지만 이후 User 의 이름이나 닉네임등 (지금 프로젝트엔 없지만) 필드가 업데이트 되었을 때 SessionID 가 담긴 곳도 업데이트가 될 지 정확하게 모르겠어서 업데이트 되지 않는 고유한 값인 ID 만 넘겨서 이후 요청 (일정 생성) 등에 User name 을 ID 를 사용해서 넣어주는게 좋을 거 같다
추가로 Session User 클래스에 들어가는 필드는 내가 지정해줄 수 있었는데 (지금 프로젝트는 User class 와 똑같은 필드 정보를 가짐 (Auditing 제외) 정보의 일부만 저장하는것도 가능하기 때문에 JPA 가 관리해주지 않는다
하지만 ID 만 넘겨주면 JPA 가 관리하는 DB 에서 가져오기 때문에 (@Entity 를 달았음) 늘 최신 + 모든 정보니까 ID 만 넘겨주기
결론
SessionUser 의 ID 만 보내기
근데 그냥 SessionUser Entity 에 ID 만 저장해도 될 것 같다 수정해주기
@Getter
public class SessionUser {
private final Long id;
public SessionUser(Long id) {
this.id = id;
}
}
문제5
수정할때 로그인된 사용자가 쓴 글이 맞는지 확인을 해야하는데
그럼 사용자 ID 와 SESSION USER 정보만 있어서 글 내부까진 접근이 안 되는데 그럼 service 로 체크하는걸 미뤄도 되나?
해결과정
service 로 미루는게 맞다. 왜냐하면 궁금증에서도 알 수 있다시피 Schedule 엔티티에 접근을 해야하는데 Controller에서는 엔티티를 직접 사용하면 안 됨
작성자 검증은 비즈니스 규칙과 조금 더 가까우니까 service 계층에서 처리해주기
글의 작성자와 현재 로그인한 사용자를 비교하려면 엔티티 조회가 필요하고 이런 과정이 비즈니스 로직
결론
Service 로 미루는게 맞다
오히려 Controller 에서 처리하는게 역할이 섞이는 개념
문제6
로그아웃 기능을 user Controller 에 만들어줘야하나
해결과정
왜 이런 질문을 적었는지 기억이 안나는데 다시 보니까 어차피 세션만료가 자동으로 되지 않는가? 에 대한 고민이었던 것 같다.
마침 튜터님께서 세션 만료에 관한 설명을 해주셔서 간단히 요약하자면
세션은 시간이 지나서 만료가 되거나, 우리가 메모리에서 강제로 삭제시킬 수 있음
이 때 시간이 지나서 만료가 되는건 톰캣세팅이나, application.properties 에서 할 수 있고
강제 삭제는 로그아웃 기능을 userController 에 직접 작성해주면 된다.
# 1. 시간이 지나 자동으로 세션 만료, 메모리에서 삭제됨
# login 기능 (in controller)
session.setMaxInactiveInterval(120); # 이 때 매개변수의 단위는 (s)
# 2. 직접 로그아웃 (강제 세션삭제)
@DeleteMapping("/logout")
public ResponseEntity<String> logout(HttpSession session){
SessionUser sessionUser = (SessionUser) session.getAttribute("loginUser");
if( sessionUser == null){
throw new BeforeLoginUserException();
}
session.invalidate();
return ResponseEntity.status(HttpStatus.NO_CONTENT).body("로그아웃 되었습니다.");
}
근데 이렇게 작성하니까 logout 했을 때

작성해둔 로그아웃 되었습니다. 가 출력되지 않네요 NO_CONTENT 가 이름만 있는게 아니라 진짜 CONTENT 가 출력이 안 되는 거였나봐요 ... ㅎㅎ 저는 그냥 401 402 처럼 204 표시만 해주는줄 알았습니다 ,,,
OK 로 수정

정상적으로 출력되네요
결론
당연히 만들어주어야함...
'SPARTA 과제 > SPRING' 카테고리의 다른 글
| 숙련) 일정관리앱 트러블슈팅 (3) (0) | 2026.02.12 |
|---|---|
| 숙련) 일정관리앱 트러블슈팅 (2) (0) | 2026.02.11 |
| 숙련) 일정관리앱 업그레이드 초기설정 (1) | 2026.02.10 |
| Schedule README (0) | 2026.02.05 |
| 유저 입력 검증 (0) | 2026.02.04 |