-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
281 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/main/java/com/srltas/runtogether/adapter/in/web/common/AuthConstants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.srltas.runtogether.adapter.in.web.common; | ||
|
||
import lombok.experimental.UtilityClass; | ||
|
||
@UtilityClass | ||
public class AuthConstants { | ||
public final String AUTHORIZATION = "Authorization"; | ||
public final String BEARER_TOKEN_PREFIX = "Bearer "; | ||
public final int BEARER_TOKEN_LENGTH = 7; | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/com/srltas/runtogether/adapter/in/web/common/SessionAttribute.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.srltas.runtogether.adapter.in.web.common; | ||
|
||
import lombok.experimental.UtilityClass; | ||
|
||
@UtilityClass | ||
public class SessionAttribute { | ||
public final String USER_SESSION = "USER_SESSION"; | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/com/srltas/runtogether/adapter/in/web/common/UrlConstants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.srltas.runtogether.adapter.in.web.common; | ||
|
||
import lombok.experimental.UtilityClass; | ||
|
||
@UtilityClass | ||
public class UrlConstants { | ||
public final String NEIGHBORHOOD_VERIFICATION = "/neighborhood/verification"; | ||
} |
55 changes: 55 additions & 0 deletions
55
src/main/java/com/srltas/runtogether/adapter/in/web/filter/AuthenticationFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.srltas.runtogether.adapter.in.web.filter; | ||
|
||
import static com.srltas.runtogether.adapter.in.web.common.AuthConstants.*; | ||
import static com.srltas.runtogether.adapter.in.web.common.SessionAttribute.USER_SESSION; | ||
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; | ||
import static java.util.Objects.isNull; | ||
|
||
import java.io.IOException; | ||
|
||
import org.springframework.web.filter.OncePerRequestFilter; | ||
|
||
import com.srltas.runtogether.adapter.out.session.SessionStorage; | ||
import com.srltas.runtogether.adapter.out.session.UserSessionDTO; | ||
|
||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import jakarta.servlet.http.HttpSession; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
public class AuthenticationFilter extends OncePerRequestFilter { | ||
|
||
private final SessionStorage sessionStorage; | ||
|
||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) | ||
throws IOException, ServletException { | ||
String authorizationHeader = request.getHeader(AUTHORIZATION); | ||
String token = extractToken(authorizationHeader); | ||
UserSessionDTO userSessionDTO; | ||
|
||
if (isNull(token) || isNullUserSessionDTO(userSessionDTO = sessionStorage.getUserFromSessionId(token))) { | ||
response.sendError(SC_UNAUTHORIZED, "인증되지 않은 사용자입니다."); | ||
return; | ||
} | ||
|
||
HttpSession session = request.getSession(true); | ||
session.setAttribute(USER_SESSION, userSessionDTO); | ||
|
||
filterChain.doFilter(request, response); | ||
} | ||
|
||
private boolean isNullUserSessionDTO(UserSessionDTO userSessionDTO) { | ||
return userSessionDTO == null; | ||
} | ||
|
||
private String extractToken(String authorizationHeader) { | ||
if (authorizationHeader != null && authorizationHeader.startsWith(BEARER_TOKEN_PREFIX)) { | ||
return authorizationHeader.substring(BEARER_TOKEN_LENGTH); | ||
} | ||
return null; | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/srltas/runtogether/adapter/out/session/SessionStorage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.srltas.runtogether.adapter.out.session; | ||
|
||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface SessionStorage { | ||
|
||
UserSessionDTO getUserFromSessionId(String sessionId); | ||
|
||
void saveUserFromSessionId(String sessionId, UserSessionDTO userSessionDTO); | ||
|
||
void removeUserFromSessionId(String sessionId); | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/srltas/runtogether/adapter/out/session/SessionStorageImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.srltas.runtogether.adapter.out.session; | ||
|
||
import org.springframework.stereotype.Repository; | ||
|
||
/** | ||
* 로그인 기능을 개발하기 전까지 사용하는 테스트용 SessionStorage 구현체입니다. | ||
*/ | ||
@Repository | ||
public class SessionStorageImpl implements SessionStorage { | ||
|
||
@Override | ||
public UserSessionDTO getUserFromSessionId(String sessionId) { | ||
return new UserSessionDTO(101L, "user_name"); | ||
} | ||
|
||
@Override | ||
public void saveUserFromSessionId(String sessionId, UserSessionDTO userSessionDTO) { } | ||
|
||
@Override | ||
public void removeUserFromSessionId(String sessionId) { } | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/srltas/runtogether/adapter/out/session/UserSessionDTO.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.srltas.runtogether.adapter.out.session; | ||
|
||
public record UserSessionDTO( | ||
Long userId, | ||
String userName | ||
) { | ||
} |
28 changes: 28 additions & 0 deletions
28
src/main/java/com/srltas/runtogether/config/WebConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.srltas.runtogether.config; | ||
|
||
import static com.srltas.runtogether.adapter.in.web.common.UrlConstants.*; | ||
|
||
import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import com.srltas.runtogether.adapter.in.web.filter.AuthenticationFilter; | ||
import com.srltas.runtogether.adapter.out.session.SessionStorage; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Configuration | ||
@RequiredArgsConstructor | ||
public class WebConfig { | ||
|
||
private final SessionStorage sessionStorage; | ||
|
||
@Bean | ||
public FilterRegistrationBean<AuthenticationFilter> sessionFilterRegistration() { | ||
FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>(); | ||
registrationBean.setFilter(new AuthenticationFilter(sessionStorage)); | ||
registrationBean.addUrlPatterns(NEIGHBORHOOD_VERIFICATION); | ||
registrationBean.setOrder(1); | ||
return registrationBean; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/test/java/com/srltas/runtogether/adapter/in/web/filter/AuthenticationFilterTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package com.srltas.runtogether.adapter.in.web.filter; | ||
|
||
import static com.srltas.runtogether.adapter.in.web.common.AuthConstants.*; | ||
import static com.srltas.runtogether.adapter.in.web.common.SessionAttribute.*; | ||
import static jakarta.servlet.http.HttpServletResponse.*; | ||
import static org.mockito.Mockito.*; | ||
|
||
import java.io.IOException; | ||
|
||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
|
||
import com.srltas.runtogether.adapter.out.session.SessionStorage; | ||
import com.srltas.runtogether.adapter.out.session.UserSessionDTO; | ||
|
||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import jakarta.servlet.http.HttpSession; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
class AuthenticationFilterTest { | ||
|
||
@Mock | ||
private SessionStorage sessionStorage; | ||
|
||
@Mock | ||
private FilterChain filterChain; | ||
|
||
@Mock | ||
private HttpServletRequest request; | ||
|
||
@Mock | ||
private HttpServletResponse response; | ||
|
||
@Mock | ||
private HttpSession session; | ||
|
||
@InjectMocks | ||
private AuthenticationFilter authenticationFilter; | ||
|
||
private static final String VALID_TOKEN = "valid_token"; | ||
private static final String INVALID_TOKEN = "invalid_token"; | ||
|
||
@Test | ||
@DisplayName("유효한 토큰을 통해 사용자가 인증되는지 확인") | ||
void testValidToken_UserAuthenticated() throws ServletException, IOException { | ||
// given | ||
UserSessionDTO userSessionDTO = new UserSessionDTO(123L, "testUserName"); | ||
when(request.getHeader(AUTHORIZATION)).thenReturn(BEARER_TOKEN_PREFIX + VALID_TOKEN); | ||
when(sessionStorage.getUserFromSessionId(VALID_TOKEN)).thenReturn(userSessionDTO); | ||
when(request.getSession(true)).thenReturn(session); | ||
|
||
// when | ||
authenticationFilter.doFilterInternal(request, response, filterChain); | ||
|
||
// then | ||
verify(session).setAttribute(USER_SESSION, userSessionDTO); | ||
verify(filterChain).doFilter(request, response); | ||
verify(response, never()).sendError(anyInt(), anyString()); | ||
} | ||
|
||
@Test | ||
@DisplayName("유효하지 않은 토큰일 때 인증되지 않음을 확인") | ||
void testInvalidToken_UserAuthenticated() throws ServletException, IOException { | ||
// given | ||
when(request.getHeader(AUTHORIZATION)).thenReturn(BEARER_TOKEN_PREFIX + INVALID_TOKEN); | ||
when(sessionStorage.getUserFromSessionId(INVALID_TOKEN)).thenReturn(null); | ||
|
||
// when | ||
authenticationFilter.doFilterInternal(request, response, filterChain); | ||
|
||
verify(response).sendError(SC_UNAUTHORIZED, "인증되지 않은 사용자입니다."); | ||
verify(filterChain, never()).doFilter(request, response); | ||
} | ||
|
||
@Test | ||
@DisplayName("Authorization 헤더가 없는 경우 필터가 인증되지 않음으로 처리하는지 확인") | ||
void testNoAuthorizationHeader() throws ServletException, IOException { | ||
// given | ||
when(request.getHeader(AUTHORIZATION)).thenReturn(null); | ||
|
||
// when | ||
authenticationFilter.doFilterInternal(request, response, filterChain); | ||
|
||
// then | ||
verify(response).sendError(SC_UNAUTHORIZED, "인증되지 않은 사용자입니다."); | ||
verify(filterChain, never()).doFilter(request, response); | ||
} | ||
} |