ย ์คํ๋ง ์ํ๋ฆฌํฐ๋ฅผ ๋ณต์ตํ๋ ๋์ค, '์ถํ ํ์ตํด์ผ์ง' ํ๊ณ ๋์ด๊ฐ๋ ๋ถ๋ถ์ ๋ฐ๊ฒฌํ๋ค.
ย ์คํ๋ง ์ํ๋ฆฌํฐ์์ CustomFilter ๋ฅผ ์์ฑํ ๋, OncePerRequestFilter ๋ผ๋ ๊ฒ์ ์์๋ฐ๋๋ค.
์ด๋ฆ๋ง ๋ณด๊ณ ๋ ์์ฒญ๋ง๋ค ๋จ ํ ๋ฒ๋ง ์คํ๋๋ ํํฐ๋ผ๋ ๊ฒ์ ์ ์ ์์ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ด ํํฐ๊ฐ ์ธ์ ์ฃผ๋ก ์ฌ์ฉ๋๋ ๊ฒ์ด๊ณ , ์ ํํ ์ด๋ค ๊ฒ์ธ์ง๋ ํ์คํ ์์ง ๋ชปํ๋ค.
ย ์ด๋ฒ ๊ธฐํ์ ์ด์ ์ ๋๊ฒผ๋ ์ด OncePerRequestFilter ๋ฅผ ๋ฉ์ธ์ผ๋ก, ํํฐ์๋ ์ด๋ค ๊ฒ๋ค์ด ์๊ณ ์ด๋ป๊ฒ ์ฃผ๋ก ์ฌ์ฉ๋๋์ง ๋ฑ์ ์ ๋ฆฌํด๋ณด๋ ์๊ฐ์ ๊ฐ์ ธ๋ณด๊ณ ์ ์ด ํฌ์คํ
์ ์์ฑํ๊ฒ ๋์๋ค.
Spring ์์ ์ ๊ณตํ๋ Filter ๋ก, ํ ์์ฒญ ๋น ํ ๋ฒ๋ง ์คํ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ ํํฐOnceperRequestFilter ์ ๊ฒฝ์ฐ ์ด๋ฌํ ๊ฒ์ ๋ฏธ์ฐ์ ๋ฐฉ์งํ๊ณ , ํ ์์ฒญ์ ๋ํด ๋ฑ ํ ๋ฒ๋ง ์คํ๋๋๋ก ์๋์ผ๋ก ์ฒ๋ฆฌisAsyncDispatch() ์ shouldNotFilter() ๋ฅผ ํ์ฉํ์ฌ ๋น๋๊ธฐ ์์ฒญ ์ด๋ ํน์ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ํํฐ ์คํ ์ ์ธ ๋ ๊ฐ๋ฅpublic abstract class OncePerRequestFilter implements Filter {
@Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// ๋น๋๊ธฐ ์์ฒญ์ ํํฐ๋ฅผ ์คํํ์ง ์๋๋ก ์ค์
if (isAsyncDispatch(httpRequest)) {
filterchain.doFilter(request, response);
return;
}
doFilterInternal(httpRequest, httpResponse, filterChain);
}
}
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
String jwt = token.substring(7);
}
// jwt ํ์ฉ
filterChain.doFilter(request, response);
}
}
@Component
@Slf4j
public class LoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
log.info("ํํฐ ๋ก๊ทธ");
filterChain.doFilter(request, response);
}
}
@Component
public class CustomHeaderFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("newHeader", "header_value")
filterChain.doFilter(request, response);
}
}
CORS ๊ท์น์ ์ ์ฉOncePerRequestFilter ์ฌ์ฉ@Component
public class CustomCorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
filterChain.doFilter(request, response);
}
}
๋ชจ๋ `GET` ์์ฒญ์ ๋ํ `CORS` ์ ์ฑ
์ฌ์ฉ
RequestDispatcher.forward() ๋ include() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ ์์ฒญ์ด ํํฐ๋ฅผ ๋ค์ ํ ์ ์์OncePerRequestFilter ๋ฅผ ์ฌ์ฉSecurityContext ๊ฐ์ ์์ฒญ ๊ด๋ จ ์ ๋ณด๋ฅผ ์ค์ ํ๊ณ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ํํฐ๊ฐ ์ฌ๋ฌ ๋ฒ ์คํ๋ ๊ฒฝ์ฐ ์ ๋ณด๊ฐ ๋ฎ์ด์์์ง ์๋ ์์OncePerRequestFilter ๋ฅผ ์ฌ์ฉํ๋ฉด ํํฐ๊ฐ ๋จ ํ ๋ฒ๋ง ์คํ๋๋ฏ๋ก ์ ๋ณด๋ฅผ ์ผ๊ด๋๊ฒ ์ ์งํ ์ ์์UsernamePasswordAuthenticationFilter ๊ฐ์ ๊ธฐ๋ณธ ํํฐ๋ค์ด ๋ด๋ถ์ ์ผ๋ก OncePerRequestFilter ๋ฅผ ์์๋ฐ์ ์ฌ์ฉServlet ๋ฐ JSP ๋ก ์ ๋ฌํ ๋ ์ฌ์ฉrequest.getRequestDispatcher("/").forward(request, response);
POST ์์ฒญ ํ redirect ๋ฅผ ํตํด GET ์์ฒญ์ผ๋ก ๋ฐํresponse.sendRedirect("/");
forward ์์ ์ฐจ์ด์ ์, ๊ธฐ์กด ํ์ด์ง ์ผ๋ถ์ ๋ค๋ฅธ ์๋ธ๋ฆฟ ๋ด์ฉ์ ํฌํจํ๋ค๋ ์ RequestDispatcher dispatcher = request.getRequestDispatcher("/header.jsp");
dispatcher.include(request, response);
request.setAttribute() ๋ก ์ ์ฅํ ๋ฐ์ดํฐ๋ ์์ฒญ์ด ์ ์ง๋๋ ๋์ ์ฌ์ฉ ๊ฐ๋ฅforward ์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์ ์ฉํจrequest.setAttribute("userRole", "ADMIN");
Bean ์ผ๋ก ๋ฑ๋ก๋์ด DI ๋ฅผ ์ฝ๊ฒ ๊ฐ๋ฅ@Component
public class CustomFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
UTF-8 ์ธ์ฝ๋ฉ์ ์ ์ฉํ ๋ ์ฌ์ฉ@Bean
public FilterRegistrationBean<CharacterEncodingFilter> encodiginFilter() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
FilterRegistrationBean<CharacterEncodingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter);
return registrationBean;
}
CORS ์ค์ ์ ๋ด๋นํ๋ ํํฐ@CrossOrigin ๊ณผ ํจ๊ป ์ฌ์ฉ ๊ฐ๋ฅ@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*") // ๋ชจ๋ ๋๋ฉ์ธ์ ๋ํ ์์ฒญ ํ์ฉ
config.addAllowedMethod("*") // ๋ชจ๋ HTTP ๋ฉ์๋ ์์ฒญ ํ์ฉ
config.addAllowedHeader("*") // ๋ชจ๋ ํค๋ ์์ฒญ ํ์ฉ
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
PUT , DELETE HTTP ๋ฉ์๋๋ฅผ POST ์์ฒญ์์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค<form> ํ๊ทธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก GET ๊ณผ POST ๋ง ์ง์ํ๋ฏ๋ก, ์ด๋ฅผ ํด๊ฒฐํ ๋ ์ ์ฉjavax.servlet.Filter ์ธํฐํ์ด์ค์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ๋ฉ์๋doFilter() ์ ์ง์ ๊ตฌํ์ด ํ์doFilter() ๊ฐ ์คํ๋๊ณ , ๋ค์ ํํฐ๋ก ์ ๋ฌํ๊ธฐ ์ํด์๋ filterChain.doFilter(request, response) ๋ฅผ ํธ์ถํด์ผ ํจFilter ์ธํฐํ์ด์ค๋ฅผ ์ง์ ๊ตฌํํ๋ ๊ฒฝ์ฐ์๋ doFilter() ๋ฉ์๋๋ฅผ ๋ฐ๋์ ์ค๋ฒ๋ผ์ด๋ ํด์ผ ํจOncePerRequestFilter ์์ ์ ๊ณตํ๋ ์ถ์ ๋ฉ์๋doFilter() ์ ๋ด๋ถ์์ doFilterInternal() ์ด ํธ์ถdoFilter() ๋์ doFilterInternal() ๋ง ๊ตฌํํ๋ฉด ๋จdoFilter() ๋ OncePerRequestFilter ๊ฐ ์๋์ผ๋ก ๊ด๋ฆฌํ๋ฉฐ, ์์ฒญ์ด ์ฌ๋ฌ ๋ฒ ํํฐ ์ฒด์ธ์ ํต๊ณผํ๋ ๊ฒ์ ๋ฏธ์ฐ์ ๋ฐฉ์งFilter ์ธํฐํ์ด์ค์์๋ doFilter() ๋ฅผ ๊ตฌํOncePerRequestFilter ๋ฅผ ์์๋ฐ๋๋ค๋ฉด, ๋์ doFilterInternal() ๋ง ๊ตฌํ์ฐธ๊ณ ) OpenAI. (2024).ChatGPT(4o)[Large language model].https://chatgpt.com/