Skip to content

Commit d355a26

Browse files
authored
Merge pull request #183 from checkmo2025/feat/182/getWithdrawal
[Feat] 신고 목록 조회 기능 추가
2 parents 29923ae + a8aa45b commit d355a26

30 files changed

Lines changed: 329 additions & 19 deletions

src/main/java/checkmo/authentication/AuthenticationAPI.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package checkmo.authentication;
22

3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
36
public interface AuthenticationAPI {
47

58
/**
@@ -12,7 +15,7 @@ public interface AuthenticationAPI {
1215
/**
1316
* 특정 회원의 인증 계정을 비활성화하고 세션을 만료시킵니다.
1417
*/
15-
void deactivateMember(String memberId);
18+
void deactivateMember(String memberId, HttpServletRequest request, HttpServletResponse response);
1619

1720
/**
1821
* 특정 회원의 인증 관련 데이터(계정 정보, 권한, 토큰 등)를 완전히 삭제합니다.

src/main/java/checkmo/authentication/AuthenticationEvent.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ public record SendVerificationEmail(String email, String verificationCode, Verif
1616
public record SendTempPassword(String email, String tempPassword){
1717
}
1818

19+
@Builder
20+
public record ReactivateMember(String id) {
21+
}
22+
1923
public enum VerificationType {
2024
SIGN_UP, UPDATE_EMAIL
2125
}

src/main/java/checkmo/authentication/internal/AuthenticationAPIImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import checkmo.authentication.AuthenticationAPI;
44
import checkmo.authentication.internal.repository.AuthRepository;
55
import checkmo.authentication.internal.security.jwt.TokenCacheService;
6+
import checkmo.authentication.internal.service.command.AuthSessionCommandService;
67
import checkmo.authentication.internal.service.command.AuthUserCommandService;
8+
import jakarta.servlet.http.HttpServletRequest;
9+
import jakarta.servlet.http.HttpServletResponse;
710
import lombok.RequiredArgsConstructor;
811
import org.springframework.stereotype.Service;
912

@@ -12,6 +15,7 @@
1215
public class AuthenticationAPIImpl implements AuthenticationAPI {
1316

1417
private final AuthUserCommandService authUserCommandService;
18+
private final AuthSessionCommandService authSessionCommandService;
1519
private final TokenCacheService tokenCacheService;
1620
private final AuthRepository authRepository;
1721

@@ -27,8 +31,8 @@ public void completeProfile(String memberId) {
2731
}
2832

2933
@Override
30-
public void deactivateMember(String memberId) {
31-
tokenCacheService.deleteRefreshToken(memberId);
34+
public void deactivateMember(String memberId, HttpServletRequest request, HttpServletResponse response) {
35+
authSessionCommandService.logout(request, response);
3236
authUserCommandService.deactivateMember(memberId);
3337
}
3438

src/main/java/checkmo/authentication/internal/config/SecurityConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
4848
.requestMatchers(HttpMethod.GET, "/api/books/**").permitAll()
4949
.requestMatchers(HttpMethod.GET, "/api/book-stories/me", "/api/book-stories/following", "/api/book-stories/clubs/**").authenticated()
5050
.requestMatchers(HttpMethod.GET, "/api/book-stories", "/api/book-stories/*", "/api/book-stories/search/*", "/api/book-stories/members/*").permitAll()
51+
.requestMatchers(HttpMethod.GET, "/api/news/me").authenticated()
5152
.requestMatchers(HttpMethod.GET, "/api/news/**").permitAll()
5253
.requestMatchers(HttpMethod.GET, "/api/members/me", "/api/members/me/**").authenticated()
5354
.requestMatchers(HttpMethod.GET, "/api/members/*").permitAll()

src/main/java/checkmo/authentication/internal/entity/AuthUser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public void deactivate() {
3434
this.deactivatedAt = LocalDateTime.now();
3535
}
3636

37+
public void reactivate() {
38+
this.deactivatedAt = null;
39+
}
40+
3741
public void completeProfile() {
3842
this.profileCompleted = true;
3943
}

src/main/java/checkmo/authentication/internal/repository/AuthRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
public interface AuthRepository extends JpaRepository<AuthUser, String> {
88

99
Optional<AuthUser> findByEmail(String email);
10+
Optional<AuthUser> findByIdAndDeactivatedAtIsNotNull(String id);
1011

1112
boolean existsByEmail(String email);
1213
}

src/main/java/checkmo/authentication/internal/security/auth/CustomUserDetailsService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ public UserDetails loadUserByUsername(String email) throws UsernameNotFoundExcep
2727
.orElseThrow(() -> new UsernameNotFoundException(
2828
"해당 이메일을 가진 사용자를 찾을 수 없습니다: " + email));
2929

30-
// 비활성화된 계정, 탈퇴한 계정 등의 상태 검증
31-
validateMemberStatus(user);
30+
// 로그인 성공 시점 자동 복구 정책 때문에 로그인 단계에서는 비활성 상태를 차단하지 않는다.
3231
return new PrincipalDetails(user);
3332
}
3433

src/main/java/checkmo/authentication/internal/security/auth/PrincipalDetails.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public boolean isCredentialsNonExpired() {
6060

6161
@Override
6262
public boolean isEnabled() {
63-
return user.getDeactivatedAt() == null;
63+
return true;
6464
}
6565

6666
// OAuth2User methods

src/main/java/checkmo/authentication/internal/security/jwt/JwtAuthenticationFilter.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package checkmo.authentication.internal.security.jwt;
22

33
import checkmo.authentication.internal.exception.AuthErrorStatus;
4+
import checkmo.authentication.internal.exception.AuthException;
45
import checkmo.authentication.internal.repository.AuthRepository;
56
import checkmo.common.apiPayload.ApiResponse;
67
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -99,6 +100,10 @@ protected void doFilterInternal(
99100
SecurityContextHolder.getContext().setAuthentication(authentication);
100101
log.info("[JWT 필터] Access Token 유효성 검사 통과");
101102
}
103+
} catch (AuthException e) {
104+
log.warn("[JWT 필터] 비활성/유효하지 않은 회원 토큰 감지: {}", e.getMessage());
105+
clearInvalidSession(response, accessToken);
106+
SecurityContextHolder.clearContext();
102107
} catch (ExpiredJwtException e) { // Access Token이 존재하지만 만료된 경우
103108
log.warn("[JWT 필터] Access Token 만료됨: {}", e.getMessage());
104109
reissueAccessToken(request, response); // Refresh Token을 사용해 재발급 시도
@@ -107,6 +112,14 @@ protected void doFilterInternal(
107112
filterChain.doFilter(request, response);
108113
}
109114

115+
private void clearInvalidSession(HttpServletResponse response, String accessToken) {
116+
if (StringUtils.hasText(accessToken)) {
117+
tokenCacheService.saveBlacklistToken(accessToken);
118+
}
119+
jwtCookieUtil.deleteTokenFromCookie(response, "accessToken");
120+
jwtCookieUtil.deleteTokenFromCookie(response, "refreshToken");
121+
}
122+
110123
// Access Token이 만료된 경우, Refresh Token을 사용해 재발급
111124
private void reissueAccessToken(HttpServletRequest request, HttpServletResponse response) {
112125
// 쿠키에서 Refresh Token 추출

src/main/java/checkmo/authentication/internal/security/jwt/JwtLoginProcessor.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package checkmo.authentication.internal.security.jwt;
22

33
import checkmo.authentication.internal.security.auth.PrincipalDetails;
4+
import checkmo.authentication.internal.service.command.AuthReactivationCommandService;
45
import jakarta.servlet.http.HttpServletResponse;
56
import lombok.RequiredArgsConstructor;
67
import org.springframework.security.core.Authentication;
@@ -13,9 +14,15 @@ public class JwtLoginProcessor {
1314
private final JwtTokenProvider jwtTokenProvider;
1415
private final JwtCookieUtil jwtCookieUtil;
1516
private final TokenCacheService tokenCacheService;
17+
private final AuthReactivationCommandService authReactivationCommandService;
1618

1719
// 로그인 성공 시 JWT 토큰 생성 및 쿠키 설정
1820
public void processLogin(HttpServletResponse response, Authentication authentication) {
21+
String userId = ((PrincipalDetails) authentication.getPrincipal()).getUser().getId();
22+
23+
// 인증 성공 시점에만 계정 자동 복구
24+
authReactivationCommandService.reactivateIfDeactivated(userId);
25+
1926
// JWT 토큰 생성
2027
JwtToken jwtToken = jwtTokenProvider.generateToken(authentication);
2128

@@ -26,8 +33,6 @@ public void processLogin(HttpServletResponse response, Authentication authentica
2633
jwtCookieUtil.addTokenToCookie(response, "refreshToken", jwtToken.getRefreshToken(), refreshTokenMaxAge);
2734

2835
// RefreshToken Redis에 저장
29-
String userId = ((PrincipalDetails) authentication.getPrincipal()).getUser().getId();
3036
tokenCacheService.saveRefreshToken(userId, jwtToken.getRefreshToken());
3137
}
3238
}
33-

0 commit comments

Comments
 (0)