1. 상황

Untitled

초기 에러 메시지는 이런식으로 나오는데 우리팀은 에러상황일 때 code, message만 보내주기로 했고 메시지도 따로 정한 상황이라 커스텀이 필요했다

2. 해결

case 1) 아이디가 잘못된 경우

InternalAuthenticationServiceException 을 던진다.

이 경우, UserDetailsService를 상속받은 클래스의 loadUserByUsername 메소드를 수정하면 된다(우리 프로젝트의 경우, PrincipalDetailsService를 수정)

public class PrincipalDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    @Override
    @Transactional
    public PrincipalDetails loadUserByUsername(String email){
        User user = userRepository.findByEmail(email).orElseThrow(
                () -> new NotJoinedUserException(ErrorMessage.USER_EMAIL_INCORRET)
        );
        return new PrincipalDetails(user);
    }
}

case 2) 아이디는 일치하는데 비밀번호가 잘못된 경우

BadCredentialException 을 던진다.

→ CustomAuthenticationProvider를 만들기

@RequiredArgsConstructor
@Log4j2
public class CustomAuthenticationProvider implements AuthenticationProvider {
    private final UserDetailsService userDetailsService;
    private final BCryptPasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; // AuthenticaionFilter에서 생성된 토큰으로부터 아이디와 비밀번호를 조회함
        String userEmail = token.getName();
        String userPw = (String) token.getCredentials(); // UserDetailsService를 통해 DB에서 아이디로 사용자 조회
        PrincipalDetails userDetailsVO = (PrincipalDetails) userDetailsService.loadUserByUsername(userEmail);
        if (!passwordEncoder.matches(userPw, userDetailsVO.getPassword())) {
            throw new NotJoinedUserException(ErrorMessage.USER_PASSWORD_INCORRET);
        }
        return new UsernamePasswordAuthenticationToken(userDetailsVO, userPw, userDetailsVO.getAuthorities());
    }

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

→ SecurityConfig에도 빈으로 등록해준다

@EnableWebSecurity //해당 파일로 시큐리티를 활성화
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) //@PreAuthorize 어노테이션을 메소드 단위로 추가하기 위해
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
		@Bean
    public CustomAuthenticationProvider customAuthenticationProvider() {
        return new CustomAuthenticationProvider(principalDetailsService, encode());
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                .authenticationProvider(customAuthenticationProvider());
    }
...
}