본문으로 건너뛰기
Advertisement

11.4 인증 처리 흐름과 실전 예제

스프링 시큐리티의 인증 과정은 여러 컴포넌트가 협력하여 이루어집니다. 여기서는 가장 일반적인 폼 로그인(ID/PW) 방식의 전체 라이프사이클을 추적하며 상세히 알아봅니다.

1. 전체 인증 프로세스 (Mermaid)

sequenceDiagram
participant User as 사용자(클라이언트)
participant Filter as AuthenticationFilter
participant Manager as AuthenticationManager
participant Provider as AuthenticationProvider
participant Service as UserDetailsService
participant DB as Database

User->>Filter: 1. 로그인 요청 (username, password)
Filter->>Filter: 2. UsernamePasswordAuthenticationToken 생성 (미인증 상태)
Filter->>Manager: 3. authenticate(token) 호출
Manager->>Provider: 4. 지원하는 Provider에게 인증 위임
Provider->>Service: 5. loadUserByUsername(username)
Service->>DB: 6. 사용자 정보 조회
DB-->>Service: 사용자 엔티티 반환
Service-->>Provider: 7. UserDetails 객체 반환
Provider->>Provider: 8. 비밀번호 검증 (BCrypt 비교)
Provider-->>Manager: 9. 인증된 Authentication 객체 반환
Manager-->>Filter: 10. 인증 완료
Filter->>Filter: 11. SecurityContextHolder에 인증 정보 저장
Filter-->>User: 12. 로그인 성공 응발/리다이렉트

2. 핵심 컴포넌트 역할

  1. AuthenticationFilter: HTTP 요청을 낚아채서 Authentication 객체(미인증)를 만들고 Manager에게 전달합니다.
  2. AuthenticationManager: 실제 인증을 총괄하는 인터페이스입니다. (일반적으로 ProviderManager 구현체 사용)
  3. AuthenticationProvider: 실제 비즈니스 로직(ID/PW 검증 등)을 수행합니다. 여러 개를 등록하여 다중 인증(LDAP, DB, Social 등)을 처리할 수 있습니다.
  4. UserDetailsService: DB에서 사용자 정보를 가져오는 "데이터 제공자" 역할만 수행합니다.
  5. SecurityContextHolder: 인증이 완료된 정보를 애플리케이션 전역에서 참조할 수 있도록 보관하는 저장소입니다.

3. 실전 예제: 로그인 API 구현 (JWT 방식)

최근 추세에 맞춰, 인증 완료 후 JWT 토큰을 발급하는 간단한 컨트롤러 예시입니다.

LoginRequest DTO

public record LoginRequest(String email, String password) {}

AuthController

@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

private final AuthenticationManager authenticationManager;
private final TokenProvider tokenProvider;

@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest request) {
// 1. 미인증 토큰 생성
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(request.email(), request.password());

// 2. 실제 인증 시작 (Manager -> Provider -> Service 흐름 작동)
// 인증 실패 시 Exception 발생
Authentication authentication = authenticationManager.authenticate(authenticationToken);

// 3. 인증 정보를 Context에 저장 (생략 가능하나 권장)
SecurityContextHolder.getContext().setAuthentication(authentication);

// 4. 인증된 정보를 바탕으로 JWT 토큰 생성 및 반환
String jwt = tokenProvider.createToken(authentication);
return ResponseEntity.ok(jwt);
}
}

4. 인증 정보 활용 (@AuthenticationPrincipal)

로그인한 사용자의 정보를 컨트롤러에서 바로 꺼내 쓰고 싶을 때 사용합니다.

@GetMapping("/api/me")
public ResponseEntity<String> getMyInfo(@AuthenticationPrincipal UserDetails userDetails) {
return ResponseEntity.ok("현재 접속 유저: " + userDetails.getUsername());
}

🎯 핵심 요점

  • 인증은 Filter -> Manager -> Provider -> Service 단계를 거칩니다.
  • AuthenticationManager 는 인증의 중심 역할을 하며, 실제 검증은 Provider 가 담당합니다.
  • 인증이 성공하면 유저 정보는 SecurityContextHolder 에 담겨 전역에서 접근 가능해집니다.
Advertisement