Spring Security 흐름
1. User enters credentials
사용자가 로그인 폼에 정보와 함께 인증 요청
2. Spring Security Filters
모든 인증/인가 요청은 Filter Chain을 통과
AbstractAuthenticationProcessingFilter를 구현한 UsernamePasswordAuthenticationFilter를 활용.
Role
- 인증 요청 감지
/login POST UsernamePasswordAuthenticationToken인증용 객체 생성,ProviderManager에 전달- 요청으로 받은
username,password를 담음.
- 요청으로 받은
AuthenticationManager호출 -> 실제 인증 로직 위임
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
username = (username != null) ? username.trim() : "";
String password = obtainPassword(request);
password = (password != null) ? password : "";
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
3. AuthenticationManager
인증 요청을 실제 인증 로직으로 위임한다.
AuthenticationManager를 구현한 ProviderManager로 위임
Role
UsernamePasswordAuthenticationToken을 입력 받는다.- 등록된
AuthenticationProvider에게 인증 요청 전달 - 인증 성공 시,
Authentication객체 반환, 실패 시AuthenticationException발생
4. AuthenticationProvider
실제 인증 로직을 수행
AuthenticationProvider 인터페이스를 실제로 구현한다.
Role
AuthenticationManager로부터 인증 요청을 받음UserDetailsService로 사용자 정보 조회PasswordEncoder로 비밀번호 검증- 인증 성공 시,
Authentication객체 반환
SomeAuthenticationProvider
@Component
@RequiredArgsConstructor
public class SomeAuthenticationProvider implements AuthenticationProvider {
private final SomeUserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
userDetailsService.loadUserByUsername(username);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (passwordEncoder.matches(password, userDetails.getPassword())) {
return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
} else {
throw new BadCredentialsException("Invalid password!");
}
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
5. UserDetailsService / UserDetailsManager
SomeAuthenticationProvider 에서 사용하기 위한 사용자 정보를 조회하는 서비스
Role
AuthenticationProvider가username을 전달- DB 또는 저장소에서 사용자 정보조회
- UserDetails 객체 반환
SomeUserDetailsService
@Service
@RequiredArgsConstructor
public class SomeUserDetailsService implements UserDetailsService {
private final CustomerRepository customerRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Customer customer = customerRepository.findByEmail(username).orElseThrow(() -> new
UsernameNotFoundException("User not found: " + username));
List<GrantedAuthority> authorities = customer.getAuthorities().stream().map(authority -> new
SimpleGrantedAuthority(authority.getName())).collect(Collectors.toList());
return new User(customer.getEmail(), customer.getPwd(), authorities);
}
}
6. PasswordEncoder
비밀번호 암호화 및 검증 수행
PasswordEncoder를 구현한 구현체를 주로 사용한다.
BCryptPasswordEncoderPbkdf2PasswordEncoder- 그 외 등등등..
password를encode하거나, 저장된password와 비교하여 일치 여부를 확인한다.
7. Authentication Token
인증 요청 및 인증 결과를 담는 객체
UsernamePasswordAuthenticationToken (폼 로그인 기본) or JwtAuthenticationToken (JWT 기반 인증)
- 인증 요청 시 ->
UsernameAuthenticationToken(isAuthenticated=false) - 인증 성공 후 ->
Authentication객체 (isAuthenticated=true)
8. AuthenticationManager 결과 반환
- 인증 성공 시 ->
Authentication객체 반환 - 인증 실패 시 ->
AuthenticationException발생
9. Security Context
현재 인증된 사용자 정보 저장
SecurityContextSecurityContextHolder인증 성공 시,SecurityContextHolder에Authentication저장
10. Filter Chain 종료 & 응답 반환
인증 / 인가 결과에 따라 Controller 호출 또는 예외 처리
ExceptionTranslationFilterAccessDeniedHandlerAuthenticationEntryPoint