1. Filter
1. FilterConfig

package org.example.springv3.core.config;
import jakarta.servlet.FilterRegistration;
import org.example.springv3.core.filter.JwtAuthorizationFilter;
import org.example.springv3.user.User;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
IoC: 제어의역전
@Controller , @RestController, @Repository , @Component, @Configuration
*/
@Configuration //스프링 실행될때
public class FilterConfig {
@Bean //리퀘스트 요청이 들어왔을 때
public FilterRegistrationBean<JwtAuthorizationFilter> jwtAuthenticationFilter() {
FilterRegistrationBean<JwtAuthorizationFilter> bean
= new FilterRegistrationBean<>(new JwtAuthorizationFilter());
bean.addUrlPatterns("/api/*");// ** 두개는 안 된다!!
bean.setOrder(0);
return bean;
}
}
- 코드설명
코드 분석
이 코드는 필터를 Spring의 IoC(제어의 역전) 컨테이너에 등록하여 실행 중인 애플리케이션에 필터를 적용하는 방법을 보여줍니다.
1) @Configuration
@Configuration
- 이 클래스가 Spring의 설정 클래스임을 나타냅니다. 즉, 이 클래스에서 정의된 빈(bean)은 Spring IoC 컨테이너에 의해 관리됩니다.
2) @Bean
@Bean
public FilterRegistrationBean<JwtAuthorizationFilter> jwtAuthenticationFilter
- @Bean: 이 메서드의 반환 값인
FilterRegistrationBean
객체는 Spring IoC 컨테이너에 등록됩니다.
- 이 메서드는 JWT 인증 필터를 설정하기 위한
FilterRegistrationBean
을 생성합니다.
3) FilterRegistrationBean
FilterRegistrationBean<JwtAuthorizationFilter> bean = new FilterRegistrationBean<>(new JwtAuthorizationFilter());
FilterRegistrationBean
은 필터를 등록하기 위한 Spring의 클래스입니다.
- 여기서
new JwtAuthorizationFilter()
는 JWT 인증 필터를 인스턴스화하여 필터로 등록하는 부분입니다. 이 필터는 들어오는 HTTP 요청을 가로채 JWT 토큰을 확인하여 인증 및 권한을 처리합니다.
4) addUrlPatterns
bean.addUrlPatterns("/api/*
- 이 메서드는 필터가 적용될 URL 패턴을 지정합니다.
- 여기서는
/api/*
경로로 시작하는 모든 요청에 대해 JWT 인증 필터를 적용하겠다는 의미입니다.
- 주의할 점은
/*
는 하위 경로까지 포함하지만,*
는 Spring Security에서 사용되는 패턴이므로 필터에서 사용할 수 없습니다.
5) setOrder
bean.setOrder(0);
- 필터의 우선순위를 설정하는 부분입니다. 숫자가 작을수록 우선순위가 높습니다.
- 여러 개의 필터가 있을 경우, 어떤 필터가 먼저 실행될지 정할 수 있습니다.
3. 코드 동작 설명
- FilterConfig 클래스는 Spring Boot 애플리케이션이 시작될 때 실행되며,
JwtAuthorizationFilter
를 필터로 등록합니다.
/api/*
경로로 들어오는 모든 HTTP 요청은 JwtAuthorizationFilter에 의해 먼저 처리됩니다.
- 필터는 요청의 JWT 토큰을 검사하고, 토큰이 유효하면 요청을 컨트롤러로 넘깁니다. 그렇지 않으면 인증 실패로 처리합니다.
4. 필터의 역할
JwtAuthorizationFilter
와 같은 필터는 다음과 같은 역할을 할 수 있습니다:- 인증: 요청에 포함된 JWT 토큰이 유효한지 확인하고, 사용자를 인증합니다.
- 권한 검증: 특정 API 요청에 대한 사용자의 권한을 확인하여, 권한이 없는 사용자의 접근을 차단합니다.
- 요청 로깅: 요청에 대한 메타 데이터를 로깅하거나 모니터링 목적으로 활용할 수 있습니다.
- 요청 변환: 요청 데이터를 변환하거나 추가 작업을 처리할 수 있습니다.
5. 실제 요청 흐름
- 클라이언트가
/api/*
경로로 요청을 보냅니다.
- JwtAuthorizationFilter가 요청을 가로채 JWT 토큰을 확인합니다.
- 토큰이 유효하면 요청을 컨트롤러로 넘기고, 유효하지 않으면 에러 응답을 반환합니다.
- 요청이 컨트롤러에 도달하고, 정상적으로 처리됩니다.
이렇게 필터는 보안 및 요청 전처리에서 중요한 역할을 합니다.
2. JwtAuthorizationFilter

package org.example.springv3.core.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.example.springv3.core.util.JwtUtil;
import org.example.springv3.core.util.Resp;
import org.example.springv3.user.User;
import java.io.IOException;
import java.io.PrintWriter;
// 책임 : 인가!!
public class JwtAuthorizationFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain Chain) throws IOException, ServletException {
HttpServletRequest rq = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) response;
String accessToken = rq.getHeader("Authorization");
if(accessToken == null || accessToken.isBlank()){
// resp 해줘야 함
resp.setHeader( "Content-Type","application/json; charset=utf-8");
PrintWriter out = resp.getWriter();
//통신은 객체를 던지면 안된다. fail은 자바객체이다! 필터에서는 인식을 못 한다.
Resp fail = Resp.fail(401, "Token이 없습니다.");
String responseBody = new ObjectMapper().writeValueAsString(fail);
out.print(responseBody);
out.flush();
return;
}
//try catch 를 쓴 이유는 항상 동일의 형태로 담아주기 위해서..
try{
User sessionUser = JwtUtil.verify(accessToken); // 서명이 위조, 만료
HttpSession session = rq.getSession();
session.setAttribute("sessionUser", sessionUser);
Chain.doFilter(rq,resp); // 다음 필터로 가!! 없으면 DS로 감.
} catch (Exception e){
resp.setHeader( "Content-Type","application/json; charset=utf-8");
PrintWriter out = resp.getWriter();
//통신은 객체를 던지면 안된다. fail은 자바객체이다! 필터에서는 인식을 못 한다.
Resp fail = Resp.fail(401, e.getMessage());
String responseBody = new ObjectMapper().writeValueAsString(fail);
out.print(responseBody);
out.flush();
}
}
}
- 코드설명
이 코드는 Spring 애플리케이션에서 JWT(토큰 기반 인증)를 이용해 사용자의 “인가” (authorization)를 처리하는 필터 클래스입니다. 이 필터는 HTTP 요청의 헤더에서 JWT 토큰을 추출하여 인증을 수행하고, 유효하지 않은 토큰일 경우 적절한 오류 응답을 반환합니다.
클래스 개요
public class JwtAuthorizationFilter implements Filter
JwtAuthorizationFilter
는 Servlet 필터를 구현한 클래스입니다. 이 클래스는Filter
인터페이스를 구현하고 있으며, 클라이언트의 HTTP 요청을 가로채 JWT 토큰을 검사하고 처리합니다.
2. doFilter 메서드
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException
- 이 메서드는 필터의 핵심 동작을 정의하는 부분입니다. HTTP 요청이 들어올 때 필터가 요청을 가로채 처리한 후, 조건에 따라 요청을 계속해서 다른 필터나 컨트롤러로 넘깁니다.
1) JWT 토큰 추출
String accessToken = rq.getHeader("Authorization");
- 요청 헤더에서
Authorization
값을 가져옵니다. 이 값이 JWT 토큰으로 예상됩니다.
Authorization
헤더는 보통Bearer <token>
형식으로 토큰을 전달합니다.
2) 토큰 검증 - 없는 경우 처리
if (accessToken == null || accessToken.isBlank()) {
resp.setHeader("Content-Type", "application/json; charset=utf-8");
PrintWriter out = resp.getWriter();
Resp fail = Resp.fail(401, "Token이 없습니다.");
String responseBody = new ObjectMapper().writeValueAsString(fail);
out.print(responseBody);
out.flush();
return;
}
- 만약
Authorization
헤더에 토큰이 없거나 비어 있다면, HTTP 401 응답(Unauthorized)을 반환합니다.
Resp.fail(401, "Token이 없습니다.")
: HTTP 401 상태 코드와 함께 "Token이 없습니다"라는 오류 메시지를 JSON 형식으로 응답합니다.
- *
ObjectMapper
*를 사용해 Java 객체를 JSON으로 변환하고, 응답에 출력합니다.
3) JWT 검증 및 세션 설정
try {
User sessionUser = JwtUtil.verify(accessToken); // JWT 토큰 검증
HttpSession session = rq.getSession();
session.setAttribute("sessionUser", sessionUser);
chain.doFilter(rq, resp); // 다음 필터 또는 컨트롤러로 요청 전달
} catch (Exception e) {
resp.setHeader("Content-Type", "application/json; charset=utf-8");
PrintWriter out = resp.getWriter();
Resp fail = Resp.fail(401, e.getMessage());
String responseBody = new ObjectMapper().writeValueAsString(fail);
out.print(responseBody);
out.flush();
}
JwtUtil.verify(accessToken)
: 전달된 JWT 토큰을 검증합니다. 여기서는 토큰의 서명이 올바른지, 토큰이 만료되지 않았는지를 확인하는 작업이 이루어집니다. 검증이 성공하면, 토큰에서 추출한 사용자의 정보를User
객체로 반환합니다.
- 세션을 생성하고,
sessionUser
라는 이름으로 사용자 정보를 세션에 저장합니다. 이렇게 하면 이후 요청에서도 이 세션을 통해 사용자 정보를 활용할 수 있습니다.
- 토큰 검증에 실패하면, 예외를 발생시키고 해당 메시지를 포함한 401 응답을 반환합니다.
4) 다음 필터 또는 디스패처 서블릿으로 이동
chain.doFilter(rq, resp);
- 필터 체인의 다음 단계로 요청을 넘깁니다. 필터 체인에 더 이상 필터가 없으면 DispatcherServlet으로 요청이 전달되어 컨트롤러로 이동하게 됩니다.
3. 예외 처리
catch (Exception e) {
resp.setHeader("Content-Type", "application/json; charset=utf-8");
PrintWriter out = resp.getWriter();
Resp fail = Resp.fail(401, e.getMessage());
String responseBody = new ObjectMapper().writeValueAsString(fail);
out.print(responseBody);
out.flush();
}
- JWT 토큰 검증 과정에서 예외가 발생하면(예: 토큰이 만료되었거나 서명이 잘못된 경우), 예외 메시지를 담아 401 응답을 반환합니다.
- 클라이언트에게 JSON 형식으로 오류 메시지를 반환하여, 왜 인증에 실패했는지 알 수 있도록 합니다.
5. 필터의 역할 요약
이 필터는 JWT 토큰 기반 인증을 처리하는 데 사용됩니다. 요청이 들어올 때마다
Authorization
헤더에서 토큰을 추출하고, 해당 토큰이 유효한지 확인합니다. 토큰이 유효하면 사용자 정보를 세션에 저장하고, 이후 다른 필터나 컨트롤러로 요청을 전달합니다. 반대로 토큰이 없거나 유효하지 않은 경우 적절한 오류 응답을 반환하여 인증되지 않은 요청을 차단합니다.이 필터는 주로 보안을 강화하고 인가 절차를 자동화하는 데 중요한 역할을 합니다.
3. UserController REST API로 변경해보기!
@PostMapping("/login")
public ResponseEntity<?> login(@Valid @RequestBody UserRequest.LoginDTO loginDTO, Errors errors) {
String accessToken = userService.로그인(loginDTO);
return ResponseEntity.ok()
//header를 넣으면 body를 꼭 써줘야한다. Bearer 띄우고 accessToken을 넣어야한다.
.header("Authorization","Bearer"+accessToken)
- 코드설명
이 코드는 Spring Boot에서 로그인 기능을 처리하는 REST API의 일부입니다. 사용자가 로그인 요청을 하면, 서버는 사용자의 인증 정보를 검증한 후 JWT 토큰을 생성하여 클라이언트에게 반환합니다. 코드의 각 부분을 설명하겠습니다.
1. @PostMapping("/login")
@PostMapping("/login")
- 이 애너테이션은 HTTP POST 요청을 처리하는 메서드를 정의합니다.
- 클라이언트가
/login
경로로 POST 요청을 보내면 이 메서드가 실행됩니다.
- POST 요청은 일반적으로 데이터를 서버에 전송하는 데 사용되며, 여기서는 로그인 요청을 처리합니다.
2. 메서드 시그니처
public ResponseEntity<?> login(@Valid @RequestBody UserRequest.LoginDTO loginDTO, Errors errors)
@RequestBody
: 클라이언트로부터 전송된 요청의 **본문(body)**을 읽어 Java 객체로 변환합니다. 여기서는loginDTO
라는 객체로 변환되며, 이 객체에는 사용자의 로그인 정보(아이디, 비밀번호)가 담겨 있을 것입니다.
@Valid
: 요청 본문에 대해 유효성 검사를 수행합니다. 만약loginDTO
의 필드가 유효하지 않으면,Errors
객체에 오류 정보가 저장됩니다.
Errors
: 유효성 검사에서 발생한 오류를 처리할 수 있는 객체입니다. 유효성 검사 실패 시 이 객체를 통해 클라이언트에 적절한 오류 응답을 보낼 수 있습니다.
ResponseEntity<?>
: HTTP 응답을 커스터마이징할 수 있는 객체입니다. 응답 상태 코드, 헤더, 본문을 모두 설정할 수 있습니다.
3. 로그인 처리: userService.로그인(loginDTO)
String accessToken = userService.로그인(loginDTO);
userService.로그인(loginDTO)
: 이 메서드는 로그인 처리의 핵심입니다.loginDTO
에는 사용자가 입력한 로그인 정보가 담겨 있으며, 이 정보로 유저의 자격을 확인합니다.- 인증이 성공하면, JWT 토큰을 생성하여 반환합니다. 반환된 값은
accessToken
변수에 저장됩니다. - 이 토큰은 이후 클라이언트가 인증이 필요한 요청을 할 때 사용됩니다.
4. ResponseEntity 설정
return ResponseEntity.ok()
.header("Authorization", "Bearer " + accessToken)
.body(Resp.ok(null));
ResponseEntity.ok()
: HTTP 응답 상태 코드 200 (OK)을 설정합니다. 이는 요청이 성공적으로 처리되었음을 의미합니다.
header("Authorization", "Bearer " + accessToken)
:- 응답 헤더에
Authorization
값을 추가합니다. - 여기서
"Bearer " + accessToken
은 Bearer 토큰을 의미하며,Bearer
는 JWT 토큰을 사용할 때 일반적으로 사용하는 방식입니다. - 클라이언트는 이 헤더를 통해 받은 토큰을 이후의 요청에서 인증 수단으로 사용합니다. 예를 들어, 클라이언트는 이후 API 호출 시 이 토큰을
Authorization
헤더에 포함하여 서버에 보냅니다.
body(Resp.ok(null))
: 응답 본문을 설정합니다.- 여기서 **
Resp.ok(null)
*는 성공적인 응답을 나타냅니다.Resp
는 커스텀 응답 객체로, 일반적으로 API에서 응답의 형식을 통일하기 위해 사용하는 클래스로 보입니다. null
은 응답 본문에 특별한 데이터를 포함하지 않음을 나타냅니다. 여기서는 주로 헤더에 토큰이 포함되기 때문에 본문에 별다른 데이터가 필요하지 않습니다.
5. 코드 흐름 요약
- 클라이언트가
/login
경로로 POST 요청을 보냅니다. 요청에는 사용자의 로그인 정보(예: 이메일, 비밀번호)가 포함됩니다.
- 서버는
userService.로그인()
메서드를 호출하여 사용자를 인증하고, 성공하면 JWT 토큰을 생성합니다.
- 서버는 응답으로 HTTP 200 OK 상태 코드와 함께
Authorization
헤더에Bearer <토큰>
을 포함시킵니다.
- 클라이언트는 이 토큰을 저장하고, 이후 인증이 필요한 요청에서 이 토큰을 헤더에 포함하여 서버에 전송합니다.
6. Authorization
헤더의 역할
- 클라이언트가 이
Authorization
헤더에 포함된 토큰을 추후 서버로 요청할 때마다 JWT 토큰을 사용하여 인증이 이루어집니다.
- 서버는 해당 토큰을 검증하여 요청한 사용자가 인증된 사용자임을 확인하고, 적절한 리소스에 접근을 허용합니다.
이 방식은 무상태(stateless) 인증 메커니즘을 사용하므로, 서버가 세션 정보를 따로 유지할 필요가 없고, 클라이언트가 요청할 때마다 JWT 토큰을 보내 인증이 가능합니다.
4. Postman 이용해서 결과보기
1. 그냥 호출해보기

2. Jwt Token 넣어서 결과보기


- H2에 username, password 정보가 있기 때문에 성공하였다.
3. Jwt Token 넣고 Board에 정보 넣어서 보기

- Board에 정보를 넣었더니 성공하였다.
Share article