[내일배움캠프_단기심화_8기] Days 4 TIL (Today I Learned)

2026. 6. 25. 15:16부트캠프/TIL(Today I Learned)

오늘 배운 내용

1. Spring Security + JWT 인증/인가 구조

기존에는 로그인 기능을 Controller → Service 에서 직접 처리했지만, Spring Security와 JWT를 사용하면 로그인 자체를 Security Filter Layer에서 처리한다는 점을 배웠다.

기존 로그인 방식

Client
 ↓
LoginController
 ↓
UserService
 ↓
DB 조회
 ↓
JWT 생성
 ↓
응답

JWT + Spring Security 방식

Client
 ↓
JwtAuthenticationFilter
 ↓
AuthenticationManager
 ↓
UserDetailsService
 ↓
DB 조회
 ↓
JWT 생성
 ↓
응답

특히 UsernamePasswordAuthenticationFilter를 상속받아 JwtAuthenticationFilter를 구현하고, 로그인 성공 시 JWT를 생성하여 쿠키에 저장하는 구조를 이해할 수 있었다.

또한 JwtAuthorizationFilter를 통해 매 요청마다 JWT를 검증하고 인증 정보를 SecurityContext에 저장하는 과정도 학습했다.


2. Spring Security 권한(Authorization) 관리

권한은 ROLE_ 접두사를 사용한다.

ROLE_USER
ROLE_ADMIN

UserDetailsImpl에서 권한 정보를 생성하고,

new SimpleGrantedAuthority("ROLE_ADMIN");

@Secured 애너테이션을 활용하여 특정 API 접근을 제한할 수 있다.

@Secured(UserRoleEnum.Authority.ADMIN)
@GetMapping("/products/secured")

또한

@EnableMethodSecurity(securedEnabled = true)

설정을 통해 @Secured 기능을 활성화할 수 있다는 점도 알게 되었다.


3. Bean Validation

사용자 입력값 검증을 위한 Bean Validation을 학습했다.

주요 애너테이션

@NotNull
@NotEmpty
@NotBlank
@Size
@Max
@Min
@Positive
@Negative
@Email
@Pattern

예시

@NotBlank
private String username;

@Email
private String email;

@Positive
private int price;

@Valid를 사용하면 DTO에 대한 검증이 자동으로 수행된다.

@PostMapping
public String signup(
    @Valid SignupRequestDto requestDto,
    BindingResult bindingResult
)

4. BindingResult

Validation 실패 시 발생하는 오류를 처리하기 위해 BindingResult를 사용한다.

if(bindingResult.hasErrors()) {
    ...
}

Validation 오류가 발생했을 때 예외를 발생시키는 대신 오류 정보를 저장해주기 때문에 개발자가 직접 예외 처리를 할 수 있다.

List<FieldError> errors =
        bindingResult.getFieldErrors();

오류 필드명과 메시지를 확인할 수 있다.


5. RestTemplate

Spring에서 서버와 서버 간 통신(Server To Server)을 쉽게 처리하기 위한 기능이다.

예를 들어

우리 서버
 ↓
카카오 API

처럼 외부 API를 호출할 때 사용한다.


GET 요청

ResponseEntity<ItemDto> responseEntity =
        restTemplate.getForEntity(uri, ItemDto.class);

JSON 응답을 DTO로 자동 변환해준다.


POST 요청

ResponseEntity<ItemDto> responseEntity =
        restTemplate.postForEntity(
            uri,
            user,
            ItemDto.class
        );

POST 방식으로 요청을 보낼 수 있다.


Exchange 방식

가장 유연한 방식이다.

ResponseEntity<String> responseEntity =
        restTemplate.exchange(
            requestEntity,
            String.class
        );

Header, Body, Method를 모두 직접 설정할 수 있다.

RequestEntity<User> requestEntity =
    RequestEntity.post(uri)
        .header("X-Authorization", token)
        .body(user);

실무에서는 인증 토큰이나 커스텀 헤더를 함께 보내야 하는 경우가 많기 때문에 자주 사용된다고 한다.


새롭게 알게 된 점

1. 로그인은 Controller가 아닌 Filter에서 처리할 수 있다.

지금까지는 로그인 기능을 Controller에서 처리하는 것이 당연하다고 생각했는데, Spring Security에서는 로그인 자체를 Filter가 처리한다는 점이 인상 깊었다.

특히 /login 요청이 Controller까지 도달하지 않고 Filter에서 바로 인증을 수행한다는 점을 처음 알게 되었다.


2. SecurityContext의 역할

JWT 검증 후 사용자 정보를 SecurityContext에 저장하면 이후 요청에서는 인증된 사용자로 인식된다는 점을 이해하게 되었다.

이를 통해

@AuthenticationPrincipal

로 현재 로그인한 사용자 정보를 쉽게 가져올 수 있다는 점도 알게 되었다.


3. Validation은 단순한 null 체크가 아니다.

Validation을 통해

  • 문자열 길이 검증
  • 이메일 형식 검증
  • 숫자 범위 검증
  • 정규식 검증

등 다양한 검증을 매우 쉽게 수행할 수 있다는 점을 배웠다.


4. RestTemplate의 자동 역직렬화

JSON 응답을 직접 파싱하지 않아도

ItemDto.class

만 지정하면 자동으로 DTO로 변환된다는 점이 매우 편리하다고 느꼈다.


내일 학습 목표

Spring 심화 강의 수강


회고

오늘은 Spring Security와 JWT의 전체 흐름을 조금 더 명확하게 이해할 수 있었던 날이었다.

특히 로그인 처리가 Controller가 아니라 Security Filter에서 이루어진다는 점이 가장 큰 수확이었다. 처음에는 필터의 동작 순서가 복잡하게 느껴졌지만, AuthenticationFilter → AuthenticationManager → UserDetailsService → DB 흐름을 여러 번 따라가며 이해할 수 있었다.

또한 Validation과 BindingResult를 학습하면서 사용자 입력값 검증의 중요성을 다시 한번 느꼈다. 단순히 기능이 동작하는 것보다 잘못된 입력을 안전하게 처리하는 것이 훨씬 중요하다는 점을 알게 되었다.

RestTemplate 실습도 진행하면서 서버 간 통신의 기본 구조를 익힐 수 있었고, 앞으로 외부 API를 연동할 때 어떤 방식으로 요청을 보내고 응답을 받아야 하는지 감을 잡을 수 있었다.

내일은 Spring 심화 강의를 수강하면서 JWT 인증 구조와 Security 흐름을 다시 정리하고, 실습 위주로 복습하여 개념을 확실하게 내 것으로 만드는 것을 목표로 한다.