μ€νλ§ λΆνΈ νν°μ λμ ꡬ쑰
μ λ°μ μΈ νλ¦
1. ν΄λΌμ΄μΈνΈ μμ²μ΄ λ°μνλ©΄, ν΄λΉ μμ²μ μλΈλ¦Ώ 컨ν μ΄λ(Tomcat, Jetty λ±)μ μ λ¬λλ€.
2. μλΈλ¦Ώ 컨ν μ΄λλ μμ²μ μ²λ¦¬νκΈ° μ μ λ±λ‘λ <<νν° μ²΄μΈ(filter chain)>> μ ν΅ν΄ μμ²μ νν°λ§νλ€.
3. νν° μ²΄μΈμ λ±λ‘λ νν°λ€μ λ±λ‘λ μμλλ‘ μμ²μ κ°λ‘μ±κ³ , κ° νν°λ νμμ λ°λΌ μμ²μ μμ νκ±°λ, νΉμ 쑰건μμ μμ²μ μ°¨λ¨ν μλ μλ€.
4. λͺ¨λ νν°λ₯Ό ν΅κ³Όν νμμΌ, μλΈλ¦Ώ λλ μ€νλ§ MVCμ μμ²μ΄ λλ¬νλ€.
μ€νλ§μμ νν°λ₯Ό ꡬννλ λ°©μ
μ€νλ§μμ νν°λ λ κ°μ§ λ°©μμΌλ‘ μ¬μ©ν μ μλ€.
1. μλΈλ¦Ώ νν° (Servlet Filter)
- javax.servlet.Filter μΈν°νμ΄μ€λ₯Ό ꡬννλ νν°
- μ€νλ§ λΆνΈμμ <<FilterRegistrationBean>> μ μ¬μ©νμ¬ νν°λ₯Ό λ±λ‘ν μ μλ€.
2. μ€νλ§ μνλ¦¬ν° νν° (Spring Security Filter)
- μΈμ¦ λ° μΈκ°λ₯Ό μ²λ¦¬νκΈ° μν μ€νλ§ μν리ν°μ νν° μ²΄μΈ
- μ¬λ¬ κ°μ μνλ¦¬ν° νν°λ€μ΄ μμ²μ κ²μ¦ν ν μμ²μ΄ μ²λ¦¬λλ€.
νν° μ¬μ© μμ (μλΈλ¦Ώ νν°)
1. κΈ°λ³Έ νν° κ΅¬ν
1.1 LoggingFilter.java
package com.example.demo.filter;
import javax.servlet.*;
import java.io.IOException;
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoggingFilter initialized");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("LoggingFilter: Request is being filtered");
chain.doFilter(request, response);
System.out.println("LoggingFilter: Response is being filtered");
}
@Override
public void destroy() {
System.out.println("LoggingFilter destroyed");
}
}
1.2 AuthenticationFilter.java
package com.test.test1.filter;
import com.test.test1.wrapper.CharResponseWrapper;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class AuthenticationFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("AuthnticationFilter initialized");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// μμ² λ°μ΄ν°λ₯Ό μ½μ
String requestData = request.getParameter("body");
System.out.println("Request data: " + requestData); // μμ² λ°μ΄ν° μΆλ ₯ (μ: ν΄λΌμ΄μΈνΈκ° λ³΄λΈ 'body' νλΌλ―Έν°)
// μλ΅μ μμ νκΈ° μν΄ responseλ₯Ό λν, μ΄λ κ² νλ©΄ λ²νΌμ μ μ₯μ΄ λκ³ μ€μ λ°μ΄ν°λ₯Ό μμ ν μ μλ€.
CharResponseWrapper wrappedResponse = new CharResponseWrapper((HttpServletResponse) response);
// λ€μ νν° λλ μλΈλ¦Ώ(컨νΈλ‘€λ¬) νΈμΆ -> μ΅μ’
νν°κΉμ§ κ°μ μ΅μ’
νν°μ μλ΅κ°μ λ³ννλ©΄μ μ΅μ΄ μ¬κΈ° κΉμ§ μ΄
chain.doFilter(request, wrappedResponse);
// μλ μλ΅ λ°μ΄ν°λ₯Ό κ°μ Έμ΄
String originalResponseContent = wrappedResponse.getCapturedResponse();
System.out.println("Original Response: " + originalResponseContent);
// μλ΅ λ°μ΄ν°λ₯Ό μμ (μ: μλ΅ λ³Έλ¬Έμ μμ² λ°μ΄ν°λ₯Ό μΆκ°)
String modifiedResponseContent = originalResponseContent + "\nModified response with request data: " + requestData;
byte[] responseBytes = modifiedResponseContent.getBytes("UTF-8");
// content-lengthλ λ°μ΄νΈ μλ₯Ό μꡬνλ€. μμ΄, λμ΄μ°κΈ°λ μ λΆ 1λ°μ΄νΈμ§λ§, νκΈμ κ°λΉ 3λ°μ΄νΈμ΄κΈ° λλ¬Έμ λ¨μ κΈμ κΈΈμ΄λ‘ νμ κ²½μ° μ λΆ λͺ» μ½μ΄ λΈλ€.
// UTF-8μ μ°Έκ³ νμλ©΄ νΉμ μΈμ΄λ₯Ό μ»΄ν¨ν° μΈμ΄ λΉνΈμΈ μ κΈμΈμ΄λ‘ λ³ννλ μ¦, μΈμ½λ© λ°©μμ΄λ€.
response.setContentLength(responseBytes.length);
System.out.println(responseBytes.length); // -> νκΈλ‘ μΈν΄μ μμ΄λ‘λ§ λμ΄ μλ€λ©΄ 52λ°μ΄νΈκ° 56λ°μ΄νΈκ° λλ€.
// μμ λ μλ΅μ ν΄λΌμ΄μΈνΈμκ² μ μ‘
//λ¬Έμμ΄μ μ§μ λ΄μμ 보λ΄κ³ , μ΄ λ¬Έμμ΄μ λ΄λΆμ μΌλ‘ λ°μ΄νΈ λ°°μ΄λ‘ λ³νλμ΄ μ μ‘νλ€. κ·Έλ¬λ©΄ ν΄λΌμ΄μΈνΈλ μ΄ λ°μ΄νΈ λ°°μ΄μ λ€μ λ¬Έμμ΄λ‘ λμ½λ©νμ¬ μ¬μ©μκ°
//λ³Ό μ μλ ννλ‘ νμ
// μ΅μ’
νν°κΉμ§ κ° λ€, μμμΌλ‘ λμμ€λ©΄μ response λ°μ΄ν°κ° λ³νμ΄ μΌμ΄λ ν
λ°, μ΄λ λ²νΌμ μ μ₯ν΄λλ©΄μ λ³ννκ³ μ΅μ’
λ³νν λ€, λ²νΌμμ ν΄λΌμ΄μΈνΈλ‘ μλ΅
response.getWriter().write(modifiedResponseContent);
// response.getOutputStream().write(responseBytes); -> μ΄κ±°λ λ°λ‘ λ°μ΄νΈ λ¨μλ‘ μ μ‘
}
@Override
public void destroy() {
System.out.println("AuthenticationFilter destroyed");
}
}
μ μ½λ μ²λΌ μλ΅ λ°μ΄ν°λ₯Ό κ°μ Έμμ νμ§ λ±μ νκ±°λ λ³μ‘°λ₯Ό ν λ€ μλ΅κ°μΌλ‘ λ³΄λΌ μ μλ€.
2. νν° λ±λ‘
μ¬λ¬ νν°λ₯Ό λ±λ‘νλ €λ©΄ <<FilterRegistrationBean>> μ μ¬μ©νμ¬ κ°κ°μ νν°λ₯Ό μ€μ ν΄μΌ νλ€.
package com.example.demo.config;
import com.example.demo.filter.LoggingFilter;
import com.example.demo.filter.AuthenticationFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilter() {
FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LoggingFilter());
registrationBean.addUrlPatterns("/api/*"); // νν°κ° μ μ©λ URL ν¨ν΄
registrationBean.setOrder(1); // νν° μ€ν μμ μ€μ
return registrationBean;
}
@Bean
public FilterRegistrationBean<AuthenticationFilter> authenticationFilter() {
FilterRegistrationBean<AuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new AuthenticationFilter());
registrationBean.addUrlPatterns("/api/*"); // νν°κ° μ μ©λ URL ν¨ν΄
registrationBean.setOrder(2); // νν° μ€ν μμ μ€μ
return registrationBean;
}
}
3. νν° μ€ν μμ
setOrder(int order) : νν°μ μ€ν μμλ₯Ό μ€μ νλ€. μ«μκ° μμμλ‘ λ¨Όμ μ€νλλ€. μμ μμμλ LoggingFilterκ° λ¨Όμ μ€νλκ³ , κ·Έ λ€μμ AuthenticationFilter κ° μ€νλλ€.
3.5 Controller μ€μ
package com.test.test1.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/api/hello")
public String hello() {
return "Hello, World";
}
}
4. μ ν리μΌμ΄μ μ€ν
μ΄μ μ ν리μΌμ΄μ μ μ€ννκ³ /api/ λ‘ μμνλ μμ²μ 보λ΄λ©΄, λ±λ‘λ νν°κ° μ°¨λ‘λ‘ μ€νλλ€.
μμ Controllerλ₯Ό μ¬μ©ν΄μ Postmanμ urlμΈ http://localhost:8080/api/hello λ₯Ό μμ²νλ©΄ ν΄λΉ νν°λ₯Ό μ ν΄μ€ μμλλ‘ κ±°μΉλ€.
LoggingFilter initialized
AuthenticationFilter initialized
LoggingFilter: Request is being filtered
AuthenticationFilter: Checking authentication
AuthenticationFilter: Response is being filtered
LoggingFilter: Response is being filtered
5. μ λ°μ μΈ νλ¦
ν΄λΌμ΄μΈνΈ -> νν° -> 컨νΈλ‘€λ¬ -> νν° -> ν΄λΌμ΄μΈνΈ
μμ¦ λ§μ΄ μ νκ³ μλ νν° λΆλΆ ν λ² μ λ¦¬ν΄ λ³΄μλ€. μ΄λ²μλ Spring Bootλ₯Ό μ¬μ©ν λλ€ λ³΄λ Gradleλ₯Ό νμ©ν νν° κ΅¬μ‘°μλ€.
λ€μ λ²μλ μ ν΅μ μΈ νν° μ μ© λ°©μμΈ web.xmlλ₯Ό νμ©ν΄μ ν΄λ³΄λ €κ³ νλ€.