최근에 스프링 시큐리티를 이용하여 기본 로그인을 구현한 후 에러 메시지를 더 자세히 분기처리하여 화면단으로 리턴하는 코드를 작성한 후 코드리뷰를 받게 되었습니다.
이 코드에 대해서 코드 리뷰 시 아래와 같은 수정 사항이 나왔습니다.
1. 에러 코드와 에러 메시지는 enum이나 yml, xml, json 파일로 따로 빼서 관리
2. if~else if 문은 가독성이 좋지 않기 때문에 사용이 권장되지 않으니 제거 요구됨
3. 스프링 시큐리티의 Filter단에서 발생하는 에러도 Servlet단에서 처리하여 에러를 중앙집중식으로 관리되도록 해야 함
1. 에러 코드와 에러 메시지는 enum이나 yml, xml, json 파일로 따로 빼서 관리
domain 패키지 밑에 enum 타입의 ErrorCode를 만들어 주어 이곳에서 프로젝트 내에서 사용할 에러코드와 에러 메시지를 관리하도록 변경하였습니다.
RuntimeException을 상속한 CustomException 클래스를 작성하여 enum ErrorCode 을 멤버변수로 추가한다.
CustomException을 상속한 MemberException 클래스를 생성하였다.
추후 다른 도메인에서 발생한 에러의 경우 별도의 Exception 클래스를 생성하여 사용하고 로그인과 관련된 Exception은 MemberException에서 다루도록 하기 위함.
2. if~else if 문은 가독성이 좋지 않기 때문에 사용이 권장되지 않으니 제거
기존 로그인 메시지 분기처리를 위한 if~else if문을 제거하고 enum ErrorCode를 호출하여 처리하는 방식으로 변경하였다.
상단의 주석처리된 코드의 경우 에러 메시지를 map의 value값으로 코드 내에서 하드코딩으로 "ERROR_LOGIN" 문자열을 삽입하여 처리하고 있다.
3. 스프링 시큐리티의 Filter단에서 발생하는 에러도 Servlet단에서 처리하여 에러를 중앙집중식으로 관리되도록 해야 함
처음에는 AuthenticationEntryPoint 인터페이스를 상속한 CustomAuthenticationEntryPoint 클래스를 생성하여 SecurityConfig에서 formLogin() 실패 시 CustomAuthenticationEntryPoint 클래스에서 처리되게 설정을 하려고 계획을 했었다.
(스프링부트 3.X 버전 이후)
스프링 시큐리티 5.2 버전 이후부터는 설정부분의 코드를 Lambda DSL 방식으로 설정하도록 변경되었습니다.
설정부분의 코드를 보면 formLogin()을 사용하여 로그인을 설정할 때 successHandler와 failureHandler 메소드를 설정할 수 있는데 해당 부분의 인수로 new CustomeAuthenticationEntryPoint() 를 적용하거나
반대로 exceptionHandling() 설정 시 authenticationEntryPoint 메소드의 인수로 new APILoginSuccessHandler() 를 적용하여도 에러가 발생한다.
해당 에러는 아래와 같다.
The method authenticationEntryPoint(AuthenticationEntryPoint) in the type ExceptionHandlingConfigurer<HttpSecurity> is not applicable for the arguments (APILoginFailHandler)Java(67108979)
ExceptionHandlingConfigurer<HttpSecurity> org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer.authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint)
Sets the AuthenticationEntryPoint to be used.
If no authenticationEntryPoint(AuthenticationEntryPoint) is specified, then defaultAuthenticationEntryPointFor(AuthenticationEntryPoint, RequestMatcher) will be used.
The first AuthenticationEntryPoint will be used as the default if no matches were found.
If that is not provided defaults to Http403ForbiddenEntryPoint.
● Parameters:
○ authenticationEntryPoint the AuthenticationEntryPoint to use
● Returns:
○ the ExceptionHandlingConfigurer for further customizations
한마디로 authenticationEntryPoint 메서드의 인수로 LoginFailHandler() 가 적합하지 않고,
AuthenticationEntryPoint(AuthenticationEntryPoint)가 지정되지 않은 경우 default AuthenticationEntryPointFor(AuthenticationEntryPoint, RequestMatcher)가 사용됩니다. 일치하는 항목이 없으면 첫 번째 AuthenticationEntryPoint가 기본값으로 사용됩니다.
이를 제공하지 않으면 기본값은 Http403 Forbiden EntryPoint입니다. 라고 추가로 말해주고 있다.
여기서 추가로 알아볼 사항은 다음과 같다.
AuthenticationFailureHandler와 AuthenticationEntryPoint의 차이점
AuthenticationFailureHandler와 AuthenticationEntryPoint는 모두 Spring Security 필터이다. 각각의 역할에 대해 간략히 설명하자면
1. AuthenticationFailureHandler:
○ Spring Security에서 인증 실패 시 호출되는 필터이다.
○ 주로 로그인 시 인증에 실패한 경우에 사용됩니다. 예를 들어, 잘못된 비밀번호를 입력한 경우 입니다.
○ 이 핸들러를 커스텀하게 구현하여, 실패한 인증 요청에 대한 처리를 정의할 수 있습니다.
○ 예를 들어, 비밀번호가 틀렸을 때 어떤 동작을 수행할지 결정할 수 있습니다.
2. AuthenticationEntryPoint:
○ 인증되지 않은 사용자에게 어디에서 인증을 수행해야 하는지 알려주는 역할을 합니다.
○ 주로 로그인 페이지로 리다이렉트하거나 인증을 위한 다른 경로를 제공합니다.
○ 인증되지 않은 사용자가 보호된 리소스에 접근하려고 할 때 호출 됩니다.
○ 예를 들어, 로그인되지 않은 상태에서 보호된 페이지에 접근하면 AuthenticationEntryPoint 가 실행됩니다.
요약하자면, AuthenticationFailureHandler 는 인증 예외를 처리하고,
AuthenticationEntryPoint 는 인증되지 않은 사용자에게 어디에서 인증을 수행해야 하는지 알려줍니다.
※ 추후 테스트 코드를 작성하여 AuthenticationEntryPoint 에서의 예외처리 흐름을 더 파악해 보도록 하자.
'Web > 스프링부트(SpringBoot Framework)' 카테고리의 다른 글
(1) @AllArgsConstructor과 @NoArgsConstructor 차이점 (0) | 2024.07.15 |
---|---|
(2) 스프링부트, JPA로 구현한 로그인을 시도한 사용자의 접속 시간 저장 (0) | 2024.07.11 |
(1) 스프링부트, JPA로 구현한 로그인을 시도한 사용자의 IP 저장 (0) | 2024.07.11 |
React와 Spring Boot를 함께 사용하는 환경에서 서버 사이드 렌더링(SSR) 구현하기...(작성중) (0) | 2024.07.10 |
@Autowired 의존성 주입을 자바 코드와 비교하기 (0) | 2024.05.15 |