@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;
public JwtAuthenticationFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
if (jwtUtil.validateToken(token)) {
String username = jwtUtil.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()));
}
}
filterChain.doFilter(request, response);
}
}
@Component@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
OncePerRequestFilter란?
- 요청당 한 번만 실행되는 필터
- 클라이언트의 모든 요청에서 JWT를 검사할 때 적합함.
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;
public JwtAuthenticationFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
UserDetailsService는 loadUserByUsername(username)을 통해 DB에서 사용자 정보 (UserDetails 객체)를 가져오는 역할을 함.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
ex)
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
"Bearer " 제거 후 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." 만 사용.
if (jwtUtil.validateToken(token)) {* jwtUtil.validateToken(token) → 토큰이 유효한지 검증
* validateToken()에서 서명이 올바르고 만료되지 않았는지 체크
---
7. 토큰에서 사용자 정보 추출
```java
String username = jwtUtil.getUsernameFromToken(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UserDetailsService가 하는 역할?
username을 기반으로 DB에서 사용자 정보를 가져와 UserDetails 객체를 생성함.
UserDetails 객체에는 사용자의 권한 정보 (Roles), 비밀번호 등이 포함됨.
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()));
이 과정이 중요한 이유
SecurityContext에 인증 정보를 저장해야 Spring Security가 "이 요청은 인증된 사용자 요청이다"라고 인식함.
즉, 이 필터를 통과한 후에는 인증이 필요한 API도 접근 가능하게 됨.
filterChain.doFilter(request, response);