Spring Security - Ajax 기반 인증
생각할 거리
Ajax가 비동기 호출이면서 주로 REST API호출인 점을 감안하면 CSR(vue) 와 유사하게 Content-type: application-json 형태일 것 같다.
그리고 이걸 통해서 현재 safe-web에 적용할 수 있는 방안을 찾을 수 있을 것 같다.
일단은 기존의 Form 인증은 스프링 시큐리티가 기본적으로 제공해주는 Security Filter(AuthenticationFilter)인 UsernamePasswordAuthenticationFilter를 사용했었는데 form, get 방식의 request 특성을 고려하여 request.getParameter를 이용한 데이터 추출 방식이었다.
그런데 위 방식은 application-json 타입에서는 사용이 불가능하고, RequestBody를 직접 파싱해줘야 하기 때문에 별도의 AuthenticationFilter를 구현하는 방식을 채택하지 않을까 싶다.
흐름 및 개요
스프링 시큐리티 기반에서는 인증이 필터로 시작해서 필터로 끝난다.
인증 필터 구현
AjaxAuthenticationFilter
AbstractAuthenticationProcessingFilter상속- 필터 작동 조건
AntPathRequestMatcher(”/api/login”)로 요청 정보와 매칭하고 요청 방식이 Ajax이면 필터 작동- Form 방식의 필터와 Ajax 방식과 함께 구성이 가능
AjaxAuthenticationToken을 생성하고AuthenticationManager에게 전달하여 인증 처리- Filter 추가
http.addFilterBefore(AjaxAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)- Form 기반의 필터 작동 이전에 먼저 작동하게끔 필터의 순서를 조정하여 추가할 수 있다.
AjaxLoginProcessingFilter(인증 처리 위임 필터)
ajax 인증 요청을 담당할 AuthenticationFilter의 구현체 AjaxLoginProcessingFilter의 코드.
요청 url과 Content-Type을 확인하여 request body에 담겨서 전달된 json 형태의 메시지를 객체로 파싱한다.
그 외에는 다른 AuthenticationFilter 처럼
- 클라이언트가 전달한 ID/PASSWORD 기반으로 Authentication(Token) 생성
- AuthenticationManager에게 Authentication을 넘기며 인증 처리 위임
AjaxAuthenticationProvider(인증 처리)
AuthenticationManager(ProviderManager)로 부터 전달받은 Authentication을 이용하여 실제 검증 및 인증 처리를 진행한다.
물론 사전에 AuthenticationManager는 supports 메서드를 이용하여 해당 AuthenticationProvider가 Authentication을 지원하는지 여부를 확인한다.
DispatcherServlet이 RequestHandlerMapper, RequestHandlerAdapter와 협력하는 구조와 유사
-
UserDetailsService로부터UserDetails를 반환받는다.UserDetailsService가 비즈니스 유즈케이스 이하 계층으로부터 유저의 인증 및 인가와 관련된 정보인UserDetails를 만들어 반환하는 일종의어댑터역할을 한다고 생각하면 될 듯 하다.
-
클라이언트가 username, password와 함께 전달한 디테일 정보를
authentication으로부터 반환받아 검증한다.- 이 정보에는 기본적으로
remoteAddr,SessionID가 저장되어 있다. - 필요 시 디테일 정보를 추가가 가능하다.
- 이 디테일 정보는
Authentication의details필드에 저장이 된다.
- 이 정보에는 기본적으로
인증 핸들러
인증 성공 시, 인증 실패 시 이후 작업을 처리하는 핸들러가 필요하다.
AjaxAuthenticationSuccessHandler
AuthenticationProvider를 거쳐 인증이 성공하게 되면 AuthenticationFilter는 AuthenticationSuccessHandler를 호출하게 된다.
기존의 view-rendering 방식이 아니라 ajax를 이용한 Http body에 데이터를 담아 Request를 받았기 때문에 마찬가지로 Http Response도 application-json 컨텐츠 타입으로 Response Body 에 응답 데이터를 담아 전달한다.
AjaxAuthenticationFailureHandler
인증 실패 핸들러 역시 마찬가지다.
인증 및 인가 예외 처리
로그인 단계에서 인증 및 인가 예외가 발생하는 경우는 두 가지가 있다.
- 인증 단계를 거치지 않고(익명의 사용자) 서버의 리소스에 접근하려 하는 경우
- 인가 예외 발생
- 인증을 받고 진행하도록 인증 페이지(로그인 페이지)로 이동
- 인증은 완료가 되었지만 접근하려는 리소스에 대한 권한이 없는 경우
- 인가 예외 발생
- 접근 불가 메시지 및 페이지
위의 처리는 인가와 관련된 처리로써 스프링 시큐리티는 이를 FilterSecurityInterceptor, ExceptionTranslationFilter를 이용하여 인가 확인 및 인가 예외 발생을 담당한다.
그리고 이 때 인가 예외 발생 시 처리할 클래스들을 우리가 구현하면 된다.
FilterSecurityInterceptor
FilterSecurityInterceptor라는 클래스는 인가 확인을 하고 만일 인가되지 않은 경우 ExceptionTranslationFilter를 호출하여 인가 예외 처리에 대한 위임을 한다.
ExceptionTranslationFilter
인가 예외에 대한 위임을 받아서 위 두 가지 상황에 따른 인가 예외 처리를 진행한다.
- 인증 단계를 거치지 않고(익명의 사용자) 서버의 리소스에 접근하려는 경우
AuthenticationEntryPoint를 호출하여 인가 예외 처리 진행- 우리가 구현
- 인증은 완료가 되었지만 접근하려는 리소스에 대한 권한이 없는 경우
AccessDeniedHandler를 호출하여 인가 예외 처리 진행- 우리가 구현
따라서 우리는 인가 예외를 처리할 두 가지(AuthenticationEntryPoint, AccessDeniedHandler) 클래스를 구현하여 등록하면 된다.
AjaxLoginAuthenticationEntryPoint
AjaxAccessDeniedHandler
CustomDSL로 config 실행하기(스킵)
- AbstractHttpConfigurer
- 스프링 시큐리티 초기화 설정 클래스
- 필터, 핸들러, 메서드, 속성 등을 한 곳에 정의하여 처리할 수 있는 편리함 제공
public void init(H http) throws Exception- 초기화public void configure(H http)- 설정
- HttpSecurity의
apply(C Configurer)메서드 활용