이 글은 정수원님의 Infrean 강의를 학습한 내용을 정리하여 작성합니다.
Ajax 인증 - AjaxLoginUrlAuthenticationEntryPoint, AjaxAccessDeniedHandler
목표
- 인증을 받지 못한 사용자가 특정 자원에 접근했을 때, 해당 자원이 인증을 필요로 한다면 사용자가 인증을 받도록 처리하는 클래스를 생성한다.
- 인증받은 사용자가 특정 자원에 접근했을 때, 해당 자원에 대한 권한이 없는 경우 처리하는 클래스를 생성한다.
FilterSecurityInterceptor
- 인가 처리를 수행한다.
- 익명 사용자가 인증을 필요로 하는 자원에 접근했을 경우 다음 예외를 발생시킨다.
- 이러한 인가 예외는 ExceptionTranslationFilter가 받는다.
- 인가 예외를 받은 경우 두 가지 방식 중 하나로 동작한다.
- 익명사용자인 경우
- 익명사용자인 경우 sendStartAuthentication() 함수를 통해 authenticationEntryPoint() 함수를 호출한다.
- 익명사용자가 아닌 인증받은 사용자인 경우
- accessDeniedHandler() 함수를 호출한다.
- 해당 자원에 접근할 수 없다는 메시지를 전달한다.
- 익명사용자인 경우
AjaxLoginUrlAuthenticationEntryPoint
- ExceptionTranslationFilter에서 인증 예외 시 호출
- AuthenticationEntryPoint 인터페이스 구현
- 인증 오류 메시지와 401 상태 코드 반환
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
AjaxAccessDeniedHandler
- ExceptionTranslationFilter에서 인가 예외 시 호출
- AccessDeniedHandler 인터페이스 구현
- 인가 오류 메시지와 403 상태 코드 반환
- response.sendError(HttpServletResponse.SC_FORBIDDEN, "forbidden");
구현
AjaxLoginAuthenticationEntryPoint
AjaxLoginAuthenticationEntryPoint
- 익명사용자가 인증이 필요한 자원에 접근한 경우 동작한다.
public class AjaxLoginAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
// 인증 예외 (AuthenticationException)가 파라미터로 전달된다.
// 인증을 받지 않은 사용자이므로 401 에러 코드를 발생시킨다.
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "UnAuthorized");
}
}
AjaxAccessDeniedHandler
AjaxAccessDeniedHandler
- 인증 받은 사용자가 해당 자원에 대한 권한이 없어 접근할 수 없는 경우 동작한다.
public class AjaxAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
// 파라미터로 인가 예외 (AccessDeniedException)가 전달된다.
// 해당 자원에 권한이 없으므로 403 에러를 발생한다.
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access is denied");
}
}
AjaxSecurityConfig
AjaxSecurityConfig
- 설정 파일에 위에서 생성한 클래스를 등록한다.
@Configuration
@Order(0)
public class AjaxSecurityConfig {
...
@Bean
public AccessDeniedHandler ajaxAccessDeniedHandler() {
return new AjaxAccessDeniedHandler();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
);
http
.addFilterBefore(ajaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
http
.exceptionHandling()
.authenticationEntryPoint(new AjaxLoginAuthenticationEntryPoint())
.accessDeniedHandler(ajaxAccessDeniedHandler());
http.csrf().disable();
return http.build();
}
}
- AjaxLoginAuthenticationEntryPoint의 경우 새로운 객체를 생성해서 등록하였고,
AjaxAccessDeniedHandler의 경우 Bean으로 등록한 뒤 등록하였다.
실행 (익명사용자)
포스트맨
Controller 설정
MessageController
@Controller
public class MessageController {
...
@GetMapping("/api/messages")
@ResponseBody
public String apiMessage() {
return "messages ok";
}
}
자원 권한 설정
AjaxSecurityConfig
- "/api/message" 자원은 MANAGER 권한을 가진 사용자만 접근 가능하도록 설정하였다.
- 현재 사용자는 USER 권한을 가졌으므로 해당 자원에 접근이 불가능하다.
참고
동작
ExceptionTranslationFilter
- 현재 사용자는 인증을 받지 않은 익명사용자이므로 sendSstartAuthentication() 메소드를 호출한다.
- authenticationEntryPoint의 commence 메소드가 호출된다.
- 여기서 authenticationEntryPoint는 우리가 위에서 등록한 AjaxLoginAuthenticationEntryPoint인 것을 확인할 수 있다.
AjaxLoginAuthenticationEntryPoint
- AjaxLoginAuthenticationEntryPoint의 commence 메서드가 호출되고 401 상태코드가 반환된다.
결과
실행(권한이 없는 사용자)
포스트맨
인증
- ROLE_USER 계정으로 다음과 같이 인증을 받는다.
자원 접근
- ROLE_USER 계정으로 인증을 받은 상태에서 접근 권한이 없는 "/api/message" 자원을 요청한다.
ExceptionTranslationFilter
- 권한이 없는 사용자이므로 accessDeniedHandler의 handle() 함수가 동작한다.
- 이때 accessDeniedHandler는 등록한 AjaxAccessDeniedHandler인 것을 확인할 수 있다.
AjaxAccessDeniedHandler
- AjaxAccessDeniedHandler가 정상 동작하는 것을 확인할 수 있다.
결과
- 우리가 원하는 대로 결과가 반환된 것을 확인할 수 있다.
실행(권한이 있는 사용자)
포스트맨
인증
- ROLE_MANAGER 계정으로 다음과 같이 인증을 받는다.
- 현재 사용자는 ROLE_MANAGER 권한을 가졌으므로 "/api/messages" 자원에 접근이 가능하다.
자원 접근
MessagesController
- 컨트롤러가 정상적으로 호출된다.
결과
- 원하는 결과값이 정상적으로 반환된다.
'스프링 시큐리티 > 실전프로젝트 - 인증 프로세스 Ajax 인증 구현' 카테고리의 다른 글
Ajax 로그인 구현 & CSRF 설정 (0) | 2023.02.14 |
---|---|
AjaxCustomDSLs구현하기 (0) | 2023.02.14 |
인증 핸들러 - AjaxAuthenticationSuccessHandler, AjaxAuthenticationFailureHandler (0) | 2023.02.14 |
인증 처리자 - AjaxAuthenticationProvider (0) | 2023.02.14 |
인증 필터 - AjaxAuthenticationFilter (0) | 2023.02.13 |