✅ Security Config + Jwt Filter추가
//JwtFilter 추가
.addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class)
Security설정에서 JwtFilter를 설정한다 Security를 타기전에 먼저 JwtFilter를 먼저 타서 로그인후에 토큰을 받으면
해당 토큰으로 Jwt 인증과 인가를 제공한다.
✅ UsernamePasswordAuthenticationFilter
로그인 요청은 가장 먼저 Application Filters 로 들어오고, 그 필터들 중 AuthenticationFilter 로 들어온다.
그리고 AuthenticationFilter 필터들 중 최종적으로 UsernamePasswordAuthenticationFilter 에 도착하게 된다.
이를 위해 AuthenticationFilter 가 UsernamePasswordAuthenticationFilter 를 상속받도록 했다.
(JWT 토큰을 이용하므로, 클래스 명을 JwtAuthenticationFilter 로 했다.)
✅JwtFilter
@Slf4j
@RequiredArgsConstructor
public class JwtFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String path = request.getRequestURI();
log.info("check uri: " + path);
// Pre-flight 요청은 필터를 타지 않도록 설정
if (request.getMethod().equals("OPTIONS")) {
return true;
}
// /api/member/로 시작하는 요청은 필터를 타지 않도록 설정
if (path.startsWith("/api/member/*")) {
return true;
}
// todo book만들떄 url체크 수정필요 바뀌면
if (path.startsWith("/api/book/view/")) {
return true;
}
// Swagger UI 경로 제외 설정
if (path.startsWith("/swagger-ui/") || path.startsWith("/v3/api-docs")) {
return true;
}
// h2-console 경로 제외 설정
if (path.startsWith("/h2-console")) {
return true;
}
return false;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
log.info("------------------JWTCheckFilter.................");
log.info("request.getServletPath(): {}", request.getServletPath());
log.info("..................................................");
//cookie들을 불러온 뒤 Authorization Key에 담긴 쿠키를 찾음
String authorization = null;
Cookie[] cookies = request.getCookies();
if(cookies !=null ) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName());
if (cookie.getName().equals("AccessToken")) {
if ("AccessToken".equals(cookie.getName())) {
authorization = cookie.getValue();
break;
}
}
}
}
// 헤더에서도 읽기 (Bearer 토큰)
if (authorization == null || authorization.isBlank()) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
authorization = bearerToken.substring(7);
}
}
//Authorization 헤더 검증
if (authorization == null) {
System.out.println("token null");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
//토큰
String token = authorization;
//토큰 소멸 시간 검증
if (jwtUtil.isExpired(token)) {
System.out.println("token expired");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
//토큰에서 email 획득
Member member = jwtUtil.getMember(token);
//UserDetails에 회원 정보 객체 담기
CustomUserDetails customOAuth2User = new CustomUserDetails(member);
//스프링 시큐리티 인증 토큰 생성
Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2User, null, customOAuth2User.getAuthorities());
//세션에 사용자 등록
SecurityContextHolder.getContext().setAuthentication(authToken);
filterChain.doFilter(request, response);
}
}
✅ doFilterInternal
if(cookies !=null ) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName());
if (cookie.getName().equals("AccessToken")) {
if ("AccessToken".equals(cookie.getName())) {
authorization = cookie.getValue();
break;
}
}
}
}
쿠키에서 AccessToken이있을 경우 해당 토큰을 가져온다
if (authorization == null || authorization.isBlank()) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
authorization = bearerToken.substring(7);
}
}
그다음에 헤더의 Authorzation에서 토크값을 가져온다
//토큰 소멸 시간 검증
if (jwtUtil.isExpired(token)) {
System.out.println("token expired");
filterChain.doFilter(request, response);
//조건이 해당되면 메소드 종료 (필수)
return;
}
JwtUtil에서 현재 시간하고 비교해서 소멸시간을 검증한다.
CustomUserDetails customOAuth2User = new CustomUserDetails(member);
Authentication authToken = new UsernamePasswordAuthenticationToken(
customOAuth2User,
null,
customOAuth2User.getAuthorities()
);
- CustomUserDetails는 UserDetails를 구현한 커스텀 객체.
- UsernamePasswordAuthenticationToken을 사용해 인증 객체 생성:
- 첫 번째 인자: 사용자 정보
- 두 번째 인자: 비밀번호 (우리는 JWT 기반이므로 null)
- 세 번째 인자: 권한 리스트 (ROLE_...)
SecurityContextHolder.getContext().setAuthentication(authToken);
- 생성한 인증 객체를 Spring Security의 SecurityContext에 저장.
- 이후 컨트롤러나 서비스에서 @AuthenticationPrincipal 또는 SecurityContextHolder.getContext().getAuthentication()로 사용자 정보 접근 가능.
'Back-end > Spring Security' 카테고리의 다른 글
| [Spring Security] Security + JWT 설정 (JwtUtil편) (1) | 2025.05.27 |
|---|---|
| [Spring Security] 기본 동작과정, 필터 구조 (0) | 2025.05.22 |