-
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.
[fix] #17 JwtAuthenticationFilter 수정, Member 수정, MemberRepository 수정
- Loading branch information
Showing
3 changed files
with
79 additions
and
25 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
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
80 changes: 56 additions & 24 deletions
80
src/main/java/com/wedit/weditapp/global/security/jwt/JwtAuthenticationFilter.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 |
---|---|---|
@@ -1,58 +1,90 @@ | ||
package com.wedit.weditapp.global.security.jwt; | ||
|
||
import com.wedit.weditapp.domain.member.domain.Member; | ||
import com.wedit.weditapp.domain.member.domain.repository.MemberRepository; | ||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.util.StringUtils; | ||
import org.springframework.web.filter.OncePerRequestFilter; | ||
import java.io.IOException; | ||
import java.util.Optional; | ||
|
||
|
||
@Slf4j | ||
@Component | ||
@RequiredArgsConstructor | ||
public class JwtAuthenticationFilter extends OncePerRequestFilter { | ||
|
||
private static final String NO_CHECK_URL = "/login"; // "/login" 요청은 필터 제외 | ||
|
||
private final JwtProvider jwtProvider; | ||
private final MemberRepository memberRepository; | ||
|
||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, | ||
HttpServletResponse response, | ||
FilterChain filterChain) | ||
throws ServletException, IOException { | ||
|
||
// 헤더에서 토큰 추출 | ||
String token = resolveToken(request); | ||
|
||
// 토큰 검증 | ||
if (token != null && jwtProvider.validateToken(token)) { | ||
// 토큰에서 사용자 정보 추출 | ||
String email = jwtProvider.getEmail(token); | ||
FilterChain filterChain) throws ServletException, IOException { | ||
// "/login" 요청은 필터 제외 | ||
if (request.getRequestURI().equals(NO_CHECK_URL)) { | ||
filterChain.doFilter(request, response); | ||
return; | ||
} | ||
|
||
// 임시로 Role없이 Authentication 객체 생성 -> 추후 추가 예정 | ||
UsernamePasswordAuthenticationToken authentication = | ||
new UsernamePasswordAuthenticationToken(email, null, null); | ||
// RefreshToken 처리 | ||
String refreshToken = jwtProvider.extractRefreshToken(request) | ||
.filter(jwtProvider::validateToken) | ||
.orElse(null); | ||
|
||
// SecurityContext에 저장 | ||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
if (refreshToken != null) { | ||
reIssueAccessToken(response, refreshToken); | ||
return; // AccessToken 재발급 후 인증 진행 중단 | ||
} | ||
|
||
// 다음 필터로 진행 | ||
// AccessToken 처리 | ||
jwtProvider.extractAccessToken(request) | ||
.filter(jwtProvider::validateToken).ifPresent(this::authenticate); | ||
|
||
filterChain.doFilter(request, response); | ||
} | ||
|
||
// "Authorization: Bearer <token>" 헤더에서 token만 파싱 | ||
private String resolveToken(HttpServletRequest request) { | ||
String bearerToken = request.getHeader("Authorization"); | ||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { | ||
return bearerToken.substring(7); | ||
} | ||
return null; | ||
// RefreshToken을 사용하여 AccessToken 재발급 | ||
private void reIssueAccessToken(HttpServletResponse response, String refreshToken) { | ||
memberRepository.findByRefreshToken(refreshToken) | ||
.ifPresentOrElse( | ||
member -> { | ||
String newAccessToken = jwtProvider.createAccessToken(member.getEmail()); | ||
String newRefreshToken = jwtProvider.createRefreshToken(); | ||
member.updateRefreshToken(newRefreshToken); | ||
memberRepository.save(member); | ||
jwtProvider.sendAccessAndRefreshToken(response, newAccessToken, newRefreshToken); | ||
log.info("AccessToken 및 RefreshToken 재발급 완료"); | ||
}, | ||
() -> log.error("유효하지 않은 RefreshToken으로 재발급 시도") | ||
); | ||
} | ||
|
||
// AccessToken을 사용하여 사용자 인증 | ||
private void authenticate(String accessToken) { | ||
jwtProvider.extractEmail(accessToken).ifPresent(email -> { | ||
Optional<Member> memberOptional = memberRepository.findByEmail(email); | ||
if (memberOptional.isPresent()) { | ||
Member member = memberOptional.get(); | ||
|
||
Authentication authentication = new UsernamePasswordAuthenticationToken( | ||
member, null, member.getAuthorities()); | ||
|
||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
log.info("사용자 인증 완료: {}", email); | ||
} else { | ||
log.error("AccessToken의 이메일 정보와 일치하는 사용자가 없습니다."); | ||
} | ||
}); | ||
} | ||
} |