
프론트의 API Client로 서버측에 요청을 보낸 후 데이터를 획득한다. 이때 권한이 필요한 경우 Access 토큰을 요청 헤더에 첨부하는데 Access 토큰 검증은 서버측 JWTFilter에 의해 진행된다. 이때 Access 토큰이 만료된 경우 특정한 상태 코드 및 메시지를 응답해야 한다.
package com.example.securityjwt.jwt;
import com.example.securityjwt.dto.CustomUserDetails;
import com.example.securityjwt.entity.UserEntity;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.io.PrintWriter;
@RequiredArgsConstructor
public class JWTFilter extends OncePerRequestFilter {
private final JWTUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 헤더에서 access키에 담긴 토큰을 꺼냄
String accessToken = request.getHeader("access");
// 토큰이 없다면 다음 필터로 넘김
if (accessToken == null) {
filterChain.doFilter(request, response);
return;
}
// 토큰 만료 여부 확인, 만료시 다음 필터로 넘기지 않음
try {
jwtUtil.isExpired(accessToken);
} catch (ExpiredJwtException e) {
//response body
PrintWriter writer = response.getWriter();
writer.print("access token expired");
//response status code
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// 토큰이 access인지 확인 (발급시 페이로드에 명시)
String category = jwtUtil.getCategory(accessToken);
if (!category.equals("access")) {
//response body
PrintWriter writer = response.getWriter();
writer.print("invalid access token");
//response status code
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// username, role 값을 획득
String username = jwtUtil.getUsername(accessToken);
String role = jwtUtil.getRole(accessToken);
UserEntity userEntity = new UserEntity();
userEntity.setUsername(username);
userEntity.setRole(role);
CustomUserDetails customUserDetails = new CustomUserDetails(userEntity);
Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
filterChain.doFilter(request, response);
}
}
굳이 String accessToken = request.getHeader("access");로 가져오는데 if문으로 category를 검사하는 이유는 다음과 같다.
참고자료: 개발자 유미 스프링 JWT 심화