[패스트캠퍼스X야놀자 : 미니 프로젝트] Spring Security의 AuthenticationProvider 구현하기

꼬마요리사레미·2023년 12월 15일

💡 PasswordEncoder

  • 주로 사용자의 비밀번호를 안전하게 저장하고 검증하기 위한 Spring Security의 인터페이스이다. 구현체들은 다양한 해시 알고리즘을 사용하여 비밀번호를 저장하고, 비교할 수 있도록 도와준다.
  • 일반적으로 BCryptPasswordEncoder를 사용하는 것이 권장된다. BCrypt는 해시 함수 중 하나로, 단방향 암호화를 제공하여 비밀번호를 안전하게 저장할 수 있다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class SignUpRequest {
  
    private String email;
    private String name;
    private String password;

    public User toEntity(PasswordEncoder passwordEncoder) {
        this.password = passwordEncoder.encode(this.password);
        return User.builder()
                .email(email)
                .name(name)
                .password(password)
                .authority(ROLE_USER)
                .build();
    }
}

사용자가 회원가입 시 입력한 비밀번호를 BCryptPasswordEncoder를 사용하여 안전하게 저장한다. 그리고 로그인 시에는 입력된 비밀번호를 같은 알고리즘으로 해싱하여 저장된 해시값과 비교한다.

💡 AuthenticationProvider

  1. supports 메서드를 통해 주어진 Authentication 객체를 지원하는지 여부를 판단한 후 authenticate 메서드를 호출한다.
  2. 지원하는 경우에는 authenticate 메서드를 호출하여 실제로 사용자를 인증한다. 인증에 성공하면 Authentication 객체를 반환한다.
  • authenticate 메서드 내에서 UserDetailsService 클래스의 loadUserByUsername 메서드를 호출하여 입력한 아이디에 해당하는 사용자 정보를 조회하고 UserDetails를 반환한다.
    ( 존재하지 않을 경우 UserNotFoundException이 발생한다. )
  • 이후 matches 메서드를 통해 입력한 비밀번호를 해시화하여 UserDetails의 Credentials( 해시된 비밀번호 )과 비교하여 사용자 인증을 진행한다.
    ( 일치하지 않을 경우 BadCredentialsException이 발생한다. )
@Component
@RequiredArgsConstructor
public class JwtAuthenticationProvider implements AuthenticationProvider {

    private final PrincipalDetailsService principalDetailsService;
    private final PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        UserDetails userDetails = principalDetailsService.loadUserByUsername(username);

        if (passwordEncoder.matches(password, userDetails.getPassword())) {
            return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
        } else {
            throw new SecurityException(SecurityExceptionCode.USER_NOT_FOUND);
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

0개의 댓글