1) Filter
: 요청과 응답이 서버, 클라이언트에게 가기 전 그 사이에서 특정 작업을 수행하는 도구
- 웹 애플리케이션에서 관리되는 영역
- 클라이언트로부터 오는 요청과 응답에 대해서 최초, 최종 단계에 위치해 응답의 어떤 정보를 변경하거나 부가적인 기능 추가할 수 있음.
- 범용적으로 처리되는 작업들에 활용됨 (ex; Logging, 보안 처리, 인증/인가와 관련된 로직 처리)
- filter를 사용하면 인증, 인가와 관련된 로직들을 처리함으로써 비즈니스 로직과 인증/인가 로직을 분리하여 관리할 수 있다는 것이 장점.
- 필터는 하나만 있는 게 아니라 아래의 그림과 같은 형태로 여러 개가 체인 형식으로 묶여 처리되고 있음.
LoggingFilter
@Slf4j(topic = "LoggingFilter")
@Component
@Order(1)
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 전처리
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String url = httpServletRequest.getRequestURI();
log.info(url);
chain.doFilter(request, response); // 다음 Filter 로 이동
// 후처리
log.info("비즈니스 로직 완료");
}
}
- @Order(1) - 필터 순서 지정
- Filter의 역할 수행을 위해 Filter 인터페이스를 implements
- chain.doFilter(request, response); - 다음 Filter로 이동
- log.info("비즈니스 로직 완료"); - 모든 작업이 완료된 후 Client에 응답 전 로그가 작성된 것을 확인할 수 있음.
AuthFilter
@Slf4j(topic = "AuthFilter")
@Component
@Order(2)
public class AuthFilter implements Filter {
private final UserRepository userRepository;
private final JwtUtil jwtUtil;
public AuthFilter(UserRepository userRepository, JwtUtil jwtUtil) {
this.userRepository = userRepository;
this.jwtUtil = jwtUtil;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String url = httpServletRequest.getRequestURI();
if (StringUtils.hasText(url) &&
(url.startsWith("/api/user") || url.startsWith("/css") || url.startsWith("/js"))
) {
// 회원가입, 로그인 관련 API 는 인증 필요없이 요청 진행
chain.doFilter(request, response); // 다음 Filter 로 이동
} else {
// 나머지 API 요청은 인증 처리 진행
// 토큰 확인
String tokenValue = jwtUtil.getTokenFromRequest(httpServletRequest);
if (StringUtils.hasText(tokenValue)) { // 토큰이 존재하면 검증 시작
// JWT 토큰 substring
String token = jwtUtil.substringToken(tokenValue);
// 토큰 검증
if (!jwtUtil.validateToken(token)) {
throw new IllegalArgumentException("Token Error");
}
// 토큰에서 사용자 정보 가져오기
Claims info = jwtUtil.getUserInfoFromToken(token);
User user = userRepository.findByUsername(info.getSubject()).orElseThrow(() ->
new NullPointerException("Not Found User")
);
request.setAttribute("user", user);
chain.doFilter(request, response); // 다음 Filter 로 이동
} else {
throw new IllegalArgumentException("Not Found Token");
}
}
}
}
- httpServletRequest.getRequestURI() - 요청 URL을 가져와 구분 (인가)
- 위의 코드의 경우, /api/user, /css, /js 로 시작하는 URL은 인증 처리에서 제외
- tokenValue가 존재하면 토큰 파싱, 검증을 진행하고 사용자 정보 가져옴
- 가져온 사용자 username을 사용해 DB에 사용자가 존재하는지 확인 후 존재하면 인증 완료
- 사용자 정보가 필요한 Controller API에 인증 완료된 User 객체 전달.
토큰 확인
// JwtUtil.java
// HttpServletRequest 에서 Cookie Value : JWT 가져오기
public String getTokenFromRequest(HttpServletRequest req) {
Cookie[] cookies = req.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(AUTHORIZATION_HEADER)) {
try {
return URLDecoder.decode(cookie.getValue(), "UTF-8"); // Encode 되어 넘어간 Value 다시 Decode
} catch (UnsupportedEncodingException e) {
return null;
}
}
}
}
return null;
}
- httpServletRequest 에서 Cookie 목록을 가져와 그 중 이름이 Authoraization인지 아닌지 체크해서 맞다면 가져오는 것.
'내일배움캠프(Sparta) > Spring' 카테고리의 다른 글
[Spring] RestTemplate (0) | 2023.11.10 |
---|---|
[Spring] Spring Security / Validation (1) | 2023.11.09 |
[Spring] JWT / 패스워드 암호화 (0) | 2023.11.08 |
[Spring] Authentication / Authorization / Cookie / Session (1) | 2023.11.08 |
[Spring] Bean (0) | 2023.11.08 |