|
| 1 | +package com.knoc.auth.jwt; |
| 2 | + |
| 3 | +import jakarta.servlet.FilterChain; |
| 4 | +import jakarta.servlet.ServletException; |
| 5 | +import jakarta.servlet.http.Cookie; |
| 6 | +import jakarta.servlet.http.HttpServletRequest; |
| 7 | +import jakarta.servlet.http.HttpServletResponse; |
| 8 | +import lombok.RequiredArgsConstructor; |
| 9 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
| 10 | +import org.springframework.security.core.context.SecurityContextHolder; |
| 11 | +import org.springframework.security.core.userdetails.UserDetails; |
| 12 | +import org.springframework.security.core.userdetails.UserDetailsService; |
| 13 | +import org.springframework.web.filter.OncePerRequestFilter; |
| 14 | + |
| 15 | +import java.io.IOException; |
| 16 | +import java.util.Arrays; |
| 17 | + |
| 18 | +@RequiredArgsConstructor |
| 19 | +public class JwtAuthenticationFilter extends OncePerRequestFilter { |
| 20 | + |
| 21 | + private final JwtTokenProvider jwtTokenProvider; |
| 22 | + private final UserDetailsService userDetailsService; |
| 23 | + |
| 24 | + @Override |
| 25 | + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
| 26 | + throws ServletException, IOException { |
| 27 | + |
| 28 | + String accessToken = getCookieValue(request, "accessToken"); |
| 29 | + String refreshToken = getCookieValue(request, "refreshToken"); |
| 30 | + |
| 31 | + // access token 살아있으면 통과 |
| 32 | + if(accessToken != null && jwtTokenProvider.validateToken(accessToken)) { |
| 33 | + setAuthentication(jwtTokenProvider.getEmailFromToken(accessToken)); |
| 34 | + } |
| 35 | + // access token 만료, refresh token이 유효하면 access token 재발급 |
| 36 | + else if(refreshToken != null && jwtTokenProvider.validateToken(refreshToken)) { |
| 37 | + String email = jwtTokenProvider.getEmailFromToken(refreshToken); |
| 38 | + UserDetails userDetails = userDetailsService.loadUserByUsername(email); |
| 39 | + String role = userDetails.getAuthorities().iterator().next().getAuthority(); |
| 40 | + |
| 41 | + String newAccessToken = jwtTokenProvider.createAccessToken(email, role); |
| 42 | + Cookie newCookie = new Cookie("accessToken", newAccessToken); |
| 43 | + newCookie.setPath("/"); |
| 44 | + newCookie.setHttpOnly(true); |
| 45 | + newCookie.setMaxAge(60 * 30); |
| 46 | + response.addCookie(newCookie); |
| 47 | + |
| 48 | + setAuthentication(email); |
| 49 | + |
| 50 | + } |
| 51 | + filterChain.doFilter(request, response); |
| 52 | + |
| 53 | + } |
| 54 | + @Override |
| 55 | + protected boolean shouldNotFilter(HttpServletRequest request) { |
| 56 | + String path = request.getRequestURI(); |
| 57 | + // /ws 로 시작하는 웹소켓 연결 요청은 HTTP 단계에서 토큰 검사를 하지 않도록 예외 처리 |
| 58 | + return path.startsWith("/ws"); |
| 59 | + } |
| 60 | + |
| 61 | + // 쿠키 배열에서 원하는 쿠키를 가져옴 |
| 62 | + private String getCookieValue(HttpServletRequest request, String cookieName) { |
| 63 | + if(request.getCookies() == null) return null; |
| 64 | + return Arrays.stream(request.getCookies()) |
| 65 | + .filter(c -> c.getName().equals(cookieName)) |
| 66 | + .map(Cookie::getValue) |
| 67 | + .findFirst() |
| 68 | + .orElse(null); |
| 69 | + |
| 70 | + } |
| 71 | + |
| 72 | + private void setAuthentication(String email) { |
| 73 | + UserDetails userDetails = userDetailsService.loadUserByUsername(email); |
| 74 | + UsernamePasswordAuthenticationToken authentication = |
| 75 | + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); |
| 76 | + SecurityContextHolder.getContext().setAuthentication(authentication); |
| 77 | + } |
| 78 | + |
| 79 | +} |
0 commit comments