Skip to content

Commit 16ad2d7

Browse files
authored
Merge pull request #344 from TaskFlow-CLAP/CLAP-282
CLAP-282 토큰 검증이 필요하지 않은 경로에 대해 필터를 우회하도록 수정
2 parents b15a0cd + dd20fd8 commit 16ad2d7

File tree

6 files changed

+46
-19
lines changed

6 files changed

+46
-19
lines changed

src/main/java/clap/server/adapter/inbound/security/SecurityConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exceptio
5757
.authorizeHttpRequests(
5858
auth ->
5959
defaultAuthorizeHttpRequest(auth)
60-
.requestMatchers(SWAGGER_ENDPOINTS).permitAll()
61-
.requestMatchers(LOGIN_ENDPOINT).permitAll()
6260
.anyRequest().authenticated()
6361
).build();
6462
}
@@ -83,8 +81,10 @@ private AbstractRequestMatcherRegistry<AuthorizeHttpRequestsConfigurer<HttpSecur
8381
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
8482
.requestMatchers(HttpMethod.OPTIONS, "*").permitAll()
8583
.requestMatchers(HttpMethod.GET, READ_ONLY_PUBLIC_ENDPOINTS).permitAll()
84+
.requestMatchers(SWAGGER_ENDPOINTS).permitAll()
85+
.requestMatchers(LOGIN_ENDPOINT).permitAll()
8686
.requestMatchers(HEALTH_CHECK_ENDPOINT).permitAll()
87-
.requestMatchers(REISSUANCE_ENDPOINTS).permitAll()
87+
.requestMatchers(REISSUANCE_ENDPOINT).permitAll()
8888
.requestMatchers(SWAGGER_ENDPOINTS).permitAll();
8989
}
9090

src/main/java/clap/server/adapter/inbound/security/WebSecurityUrl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ private WebSecurityUrl() {
1212
"/swagger/api-docs/**", "/swagger/v3/api-docs/**",
1313
"/swagger-ui/**", "/swagger"
1414
};
15-
public static final String REISSUANCE_ENDPOINTS = "/api/auths/reissuance";
16-
public static final String[] PUBLIC_ENDPOINTS = {LOGIN_ENDPOINT, REISSUANCE_ENDPOINTS};
15+
public static final String REISSUANCE_ENDPOINT = "/api/auths/reissuance";
1716
public static final String TEMPORARY_TOKEN_ALLOWED_ENDPOINT = "/api/members/initial-password";
1817
}

src/main/java/clap/server/adapter/inbound/security/filter/JwtAuthenticationFilter.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import clap.server.adapter.outbound.jwt.access.AccessTokenClaimKeys;
55
import clap.server.application.port.outbound.auth.ForbiddenTokenPort;
66
import clap.server.application.port.outbound.auth.JwtProvider;
7-
import clap.server.exception.AuthException;
87
import clap.server.exception.JwtException;
98
import clap.server.exception.code.AuthErrorCode;
109
import io.jsonwebtoken.Claims;
@@ -24,11 +23,13 @@
2423
import org.springframework.security.web.access.AccessDeniedHandler;
2524
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
2625
import org.springframework.stereotype.Component;
26+
import org.springframework.util.AntPathMatcher;
2727
import org.springframework.util.StringUtils;
2828
import org.springframework.web.filter.OncePerRequestFilter;
2929

3030
import java.io.IOException;
3131
import java.util.Arrays;
32+
import java.util.stream.Stream;
3233

3334
import static clap.server.adapter.inbound.security.WebSecurityUrl.*;
3435

@@ -42,13 +43,22 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
4243
private final AccessDeniedHandler accessDeniedHandler;
4344
private final ForbiddenTokenPort forbiddenTokenPort;
4445

46+
public static final String[] PUBLIC_ENDPOINTS = Stream.of(
47+
HEALTH_CHECK_ENDPOINT,
48+
READ_ONLY_PUBLIC_ENDPOINTS,
49+
SWAGGER_ENDPOINTS
50+
).flatMap(Arrays::stream).toArray(String[]::new);
51+
52+
public static final String[] ANONYMOUS_ENDPOINTS = {LOGIN_ENDPOINT, REISSUANCE_ENDPOINT};
53+
4554
@Override
4655
protected void doFilterInternal(
4756
@NotNull HttpServletRequest request,
4857
@NotNull HttpServletResponse response,
4958
@NotNull FilterChain filterChain
5059
) throws ServletException, IOException {
5160
try {
61+
5262
if (isAnonymousRequest(request)) {
5363
filterChain.doFilter(request, response);
5464
return;
@@ -66,10 +76,19 @@ protected void doFilterInternal(
6676
}
6777

6878
private boolean isAnonymousRequest(HttpServletRequest request) {
69-
String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION);
70-
return accessToken == null;
79+
boolean isAnonymousURI = Arrays.stream(ANONYMOUS_ENDPOINTS)
80+
.anyMatch(endpoint -> new AntPathMatcher().match(endpoint, request.getRequestURI()));
81+
boolean isAnonymous = request.getHeader(HttpHeaders.AUTHORIZATION) == null;
82+
return isAnonymousURI && isAnonymous;
7183
}
7284

85+
@Override
86+
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
87+
return Arrays.stream(PUBLIC_ENDPOINTS)
88+
.anyMatch(endpoint -> new AntPathMatcher().match(endpoint, request.getRequestURI()));
89+
}
90+
91+
7392
private String resolveAccessToken(
7493
HttpServletRequest request
7594
) throws ServletException {
@@ -106,6 +125,8 @@ private String resolveAccessToken(
106125
}
107126

108127

128+
129+
109130
private boolean isTemporaryTokenAllowed(String requestUrl) {
110131
return requestUrl.equals(TEMPORARY_TOKEN_ALLOWED_ENDPOINT);
111132
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package clap.server.adapter.inbound.web.dto.member.request;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
5+
public record VerifyPasswordRequest(
6+
@NotBlank
7+
String password
8+
) {
9+
}

src/main/java/clap/server/adapter/inbound/web/member/ResetPasswordController.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@
33
import clap.server.adapter.inbound.security.service.SecurityUserDetails;
44
import clap.server.adapter.inbound.web.dto.member.request.UpdateInitialPasswordRequest;
55
import clap.server.adapter.inbound.web.dto.member.request.UpdatePasswordRequest;
6+
import clap.server.adapter.inbound.web.dto.member.request.VerifyPasswordRequest;
67
import clap.server.application.port.inbound.member.ResetInitialPasswordUsecase;
78
import clap.server.application.port.inbound.member.ResetPasswordUsecase;
89
import clap.server.application.port.inbound.member.VerifyPasswordUseCase;
910
import clap.server.common.annotation.architecture.WebAdapter;
1011
import io.swagger.v3.oas.annotations.Operation;
1112
import io.swagger.v3.oas.annotations.tags.Tag;
12-
import jakarta.validation.constraints.NotBlank;
13+
import jakarta.validation.Valid;
1314
import lombok.RequiredArgsConstructor;
1415
import org.springframework.security.core.annotation.AuthenticationPrincipal;
15-
import org.springframework.web.bind.annotation.GetMapping;
16-
import org.springframework.web.bind.annotation.PatchMapping;
17-
import org.springframework.web.bind.annotation.RequestBody;
18-
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.*;
1917

2018
@Tag(name = "01. Member [비밀번호 관련]")
2119
@WebAdapter
@@ -29,22 +27,22 @@ public class ResetPasswordController {
2927
@Operation(summary = "초기 로그인 후 비밀번호 재설정 API")
3028
@PatchMapping("/members/initial-password")
3129
public void resetPasswordAndActivateMember(@AuthenticationPrincipal SecurityUserDetails userInfo,
32-
@RequestBody UpdateInitialPasswordRequest request) {
30+
@RequestBody @Valid UpdateInitialPasswordRequest request) {
3331
resetInitialPasswordUsecase.resetPasswordAndActivateMember(userInfo.getUserId(),request.password());
3432
}
3533

3634
@Operation(summary = "비밀번호 재설정 API")
3735
@PatchMapping("/members/password")
3836
public void resetPassword(@AuthenticationPrincipal SecurityUserDetails userInfo,
39-
@RequestBody UpdatePasswordRequest request) {
37+
@RequestBody @Valid UpdatePasswordRequest request) {
4038
resetPasswordUsecase.resetPassword(userInfo.getUserId(), request.password());
4139
}
4240

4341

4442
@Operation(summary = "비밀번호 검증 API")
45-
@GetMapping("/members/password")
43+
@PostMapping("/members/password")
4644
public void verifyPassword(@AuthenticationPrincipal SecurityUserDetails userInfo,
47-
@RequestBody @NotBlank String password) {
48-
verifyPasswordUseCase.verifyPassword(userInfo.getUserId(), password);
45+
@RequestBody @Valid VerifyPasswordRequest request) {
46+
verifyPasswordUseCase.verifyPassword(userInfo.getUserId(), request.password());
4947
}
5048
}

src/main/java/clap/server/exception/code/AuthErrorCode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public enum AuthErrorCode implements BaseErrorCode {
1010
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "AUTH_001", "인증 과정에서 오류가 발생하였습니다."),
1111
FORBIDDEN(HttpStatus.FORBIDDEN, "AUTH_002", "접근이 거부되었습니다"),
1212
EMPTY_ACCESS_KEY(HttpStatus.FORBIDDEN, "AUTH_003", "AccessToken 이 비어있습니다."),
13-
LOGOUT_ERROR(HttpStatus.FORBIDDEN, "AUTH_004", "로그 아웃된 사용자입니다."),
13+
// LOGOUT_ERROR(HttpStatus.FORBIDDEN, "AUTH_004", "로그 아웃된 사용자입니다."),
1414
EXPIRED_TOKEN(HttpStatus.FORBIDDEN, "AUTH_005", "사용기간이 만료된 토큰입니다."),
1515
TAKEN_AWAY_TOKEN(HttpStatus.FORBIDDEN, "AUTH_006", "탈취당한 토큰입니다. 다시 로그인 해주세요."),
1616
WITHOUT_OWNER_REFRESH_TOKEN(HttpStatus.FORBIDDEN, "AUTH_007", "소유자가 아닌 RefreshToken 입니다."),

0 commit comments

Comments
 (0)