Skip to content

Commit

Permalink
fix: 요청 발생 시 HttpSession 제거하도록 변경 (#453)
Browse files Browse the repository at this point in the history
fix: 요청 발생 시 HttpSession 제거
  • Loading branch information
Kim0914 authored and hozzijeong committed Oct 20, 2023
1 parent 7251b8b commit 01d0ca6
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
public class AuthController {

private static final String SESSION_KEY = "KAKAO_ID";
private static final int SESSION_EXPIRE_SECOND = 86400 * 30;

private final AuthService authService;
private final SessionGroupService sessionGroupService;
Expand All @@ -32,7 +31,6 @@ public ResponseEntity<Void> login(
Member loginMember = authService.login(code);

HttpSession session = request.getSession();
session.setMaxInactiveInterval(SESSION_EXPIRE_SECOND);
sessionGroupService.add(session.getId(), SESSION_KEY, loginMember.getKakaoId().toString());
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import com.official.pium.exception.AuthenticationException;
import com.official.pium.repository.MemberRepository;
import com.official.pium.service.SessionGroupService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
Expand All @@ -17,7 +15,11 @@
@RequiredArgsConstructor
public class MemberArgumentResolver implements HandlerMethodArgumentResolver {

private static final int VALUE_INDEX = 1;
private static final String SESSION_DELIMITER = "=";
private static final String SESSION_KEY = "KAKAO_ID";
private static final String COOKIE_HEADER = "cookie";
private static final int MIN_SESSION_SIZE = 2;

private final MemberRepository memberRepository;
private final SessionGroupService sessionGroupService;
Expand All @@ -31,14 +33,7 @@ public boolean supportsParameter(MethodParameter parameter) {
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
throws AuthenticationException {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
HttpSession session = request.getSession(false);

if (session == null) {
throw new AuthenticationException("로그인이 필요합니다");
}

String sessionValue = sessionGroupService.findOrExtendsBySessionIdAndKey(session.getId(), SESSION_KEY);
String sessionValue = getSessionId(webRequest);
try {
Long kakaoId = Long.valueOf(sessionValue);
return memberRepository.findByKakaoId(kakaoId)
Expand All @@ -47,4 +42,21 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m
throw new AuthenticationException("잘못된 세션 정보로 인해 사용자 인증에 실패하였습니다.");
}
}

private String getSessionId(NativeWebRequest webRequest) {
String sessionCookie = webRequest.getHeader(COOKIE_HEADER);
String sessionId = parseSessionCookie(sessionCookie);
return sessionGroupService.findOrExtendsBySessionIdAndKey(sessionId, SESSION_KEY);
}

private String parseSessionCookie(String sessionCookie) {
if (sessionCookie == null || sessionCookie.isBlank()) {
return null;
}
String[] keyAndValue = sessionCookie.split(SESSION_DELIMITER);
if (keyAndValue.length < MIN_SESSION_SIZE) {
return null;
}
return keyAndValue[VALUE_INDEX];
}
}
3 changes: 2 additions & 1 deletion backend/pium/src/test/java/com/official/pium/UITest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.official.pium;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
Expand Down Expand Up @@ -41,7 +42,7 @@ void setUp() {
admin = new Admin("admin", "1234", "12345");

session.setAttribute(ADMIN_SESSION_KEY, admin);
given(sessionGroupService.findOrExtendsBySessionIdAndKey(anyString(), anyString()))
given(sessionGroupService.findOrExtendsBySessionIdAndKey(any(), anyString()))
.willReturn("12345");
given(memberRepository.findByKakaoId(anyLong()))
.willReturn(Optional.of(member));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class 정원_식물_등록_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -177,7 +177,8 @@ class 정원_식물_조회_ {
.statusCode(HttpStatus.OK.value())
.extract();

List<SingleGardenResponse> singleGardenResponses = response.jsonPath().getList("data", SingleGardenResponse.class);
List<SingleGardenResponse> singleGardenResponses = response.jsonPath()
.getList("data", SingleGardenResponse.class);

assertSoftly(
softly -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class 반려_식물_단건_히스토리_조회_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class 반려_식물_등록_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -185,7 +185,7 @@ class 반려_식물_단건_조회_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -345,7 +345,7 @@ class 반려_식물_전체_조회_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -422,7 +422,7 @@ class 반려_식물_수정_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -723,7 +723,7 @@ class 반려_식물_삭제_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class 리마인더_조회_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -119,7 +119,7 @@ class 물주기_수행_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down Expand Up @@ -327,7 +327,7 @@ class 날짜_변경_수행_시_ {
.then()
.log().all()
.statusCode(HttpStatus.UNAUTHORIZED.value())
.assertThat().body("message", containsString("로그인이 필요합니다"));
.assertThat().body("message", containsString("일치하는 세션을 찾을 수 없습니다."));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.official.pium.controller;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
Expand All @@ -17,6 +18,7 @@

import com.official.pium.UITest;
import com.official.pium.domain.Member;
import com.official.pium.exception.AuthenticationException;
import com.official.pium.service.AuthService;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
Expand All @@ -27,7 +29,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.web.servlet.MockMvc;

@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
Expand Down Expand Up @@ -94,23 +95,25 @@ class 로그아웃_ {

@Test
void 세션_정보_없이_요청_시_401_반환() throws Exception {
given(sessionGroupService.findOrExtendsBySessionIdAndKey(any(), anyString()))
.willThrow(new AuthenticationException("일치하는 세션을 찾을 수 없습니다."));

mockMvc.perform(post("/logout")
.contentType(APPLICATION_JSON_VALUE))
.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.message").value("로그인이 필요합니다"))
.andExpect(jsonPath("$.message").value("일치하는 세션을 찾을 수 없습니다."))
.andDo(print());
}

@Test
void 만료된_세션으로_요청_시_401_반환() throws Exception {
MockHttpSession expiredSession = new MockHttpSession();
expiredSession.invalidate();
given(sessionGroupService.findOrExtendsBySessionIdAndKey(any(), anyString()))
.willThrow(new AuthenticationException("일치하는 세션을 찾을 수 없습니다."));

mockMvc.perform(post("/logout")
.session(expiredSession)
.contentType(APPLICATION_JSON_VALUE))
.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.message").value("로그인이 필요합니다"))
.andExpect(jsonPath("$.message").value("일치하는 세션을 찾을 수 없습니다."))
.andDo(print());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willDoNothing;
import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies;
Expand All @@ -21,6 +22,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.official.pium.UITest;
import com.official.pium.domain.Member;
import com.official.pium.exception.AuthenticationException;
import com.official.pium.fixture.GardenFixture;
import com.official.pium.fixture.GardenFixture.REQUEST;
import com.official.pium.service.GardenService;
Expand Down Expand Up @@ -86,6 +88,8 @@ class 정원_식물_등록 {
void 로그인_없이_요청하면_401_반환() throws Exception {
willDoNothing().given(gardenService)
.create(any(GardenCreateRequest.class), any(Member.class));
given(sessionGroupService.findOrExtendsBySessionIdAndKey(any(), anyString()))
.willThrow(new AuthenticationException("일치하는 세션을 찾을 수 없습니다."));

mockMvc.perform(post("/garden")
.content(objectMapper.writeValueAsString(REQUEST.정원_게시글_등록_요청))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.official.pium.controller;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doNothing;
import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
Expand All @@ -17,6 +19,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.official.pium.UITest;
import com.official.pium.domain.Member;
import com.official.pium.exception.AuthenticationException;
import com.official.pium.service.MemberService;
import com.official.pium.service.dto.NotificationSubscribeRequest;
import org.junit.jupiter.api.DisplayNameGeneration;
Expand Down Expand Up @@ -66,14 +69,14 @@ class 회원_탈퇴_ {

@Test
void 만료된_세션으로_요청_시_401_반환() throws Exception {
MockHttpSession expiredSession = new MockHttpSession();
expiredSession.invalidate();
given(sessionGroupService.findOrExtendsBySessionIdAndKey(any(), anyString()))
.willThrow(new AuthenticationException("일치하는 세션을 찾을 수 없습니다."));

mockMvc.perform(delete("/members/withdraw")
.session(expiredSession)
.session(new MockHttpSession())
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.message").value("로그인이 필요합니다"))
.andExpect(jsonPath("$.message").value("일치하는 세션을 찾을 수 없습니다."))
.andDo(print());
}
}
Expand Down

0 comments on commit 01d0ca6

Please sign in to comment.