흐름 및 개요
•
스프링에서 인증 및 인가처리는 Filter로 시작해서 Filter로 끝납니다. 그렇기에 사용자가 인증요청을 할 때 Filter에서 가장 먼저 받아서 각각의 클래스에 인증처리를 맡기게 됩니다. 그래서 그런 인증요청을 맡을 AjaxAuthenticationFilter 를 만들 것입니다.
인증 처리
•
필터가 인증객체(AjaxAuthenticationToken) 에 인증처리를 하기위해 보낸정보를 담아서 인증관리자 (AuthenticationManager)에게 인증객체를 전달해주고 객체를 전달받은 매니저는 실질적으로 인증처리를 담당하는 AjaxAuthenticationProvider에게 인증처리를 위임하게 됩니다.
•
실질적인 인증처리를 위임받은 AjaxAuthenticationProvider는 인증 로직 수행 UserDetailsSevice 을 합니다.
•
인증성공을 한다면 AjaxAuthenticationSuccessHandler 구현체를 만들어 인증 성공시 처리로직을 수행합니다.
•
인증실패를 한다면 AjaxAuthenticationFailureHandler 구현체를 만들어 인증 실패시 처리로직을 수행합니다.
인가 처리
•
인증된 사용자가 자원에 접근요청을 할 경우 인가처리가 시작됩니다.
•
FilterSecurityInterceptor에서 인가처리를 담당합니다.
•
인가 검사중 인증예외(AuthenticationException)나 인가예외(AccessDeniedException)이 발생할 경우 ExceptionTranslationFilter에게 전달합니다.
•
ExceptionTranslationFilter 에서 인증이 실패했을 경우에는 AjaxUrlAuthenticationEntryPoint 구현체에서 로직을 수행합니다.
•
ExceptionTranslationFilter 에서 자원 접근이 거부되었을 경우에는 AjaxAccessDeniedHandler 구현체에서 로직을 수행합니다.
인증 필터 - AjaxAuthenticationFilter
•
AbstractAuthenticationProcessingFileter 상속
◦
이 필터는 실제로 Form인증 처리를 하는 UsernamePasswordAuthenticationFilter도 해당 추상클래스를 상속받아 사용한다
•
필터 작동 조건
◦
AntPathRequestMatcher('/api/login") 로 요청정보와 매칭하고 요청 방식이 Ajax이면 필터 작동
◦
Ajax인지 아닌지 기준을 두어 Ajax일 경우 필터가 동작하도록 구성을 하자
•
AjaxAuthenticationToken 생성하여 AuthenticationManager에게 전달하여 인증처리
•
Filter 추가
http.addFilterBefore(AjaxAuthenticationFIlter(), UsernamePasswordAuthenticationFilter.class)
Java
복사
◦
Form 방식의 인증처리를 담당하는 UsernamePasswordAuthenticationFilter앞에 위치하도록 한다.
1. security / filter / AjaxLoginProcessingFilter
Code
2. security / token / AjaxAuthenticaitonToken
Code
3. secrity / config / Security Config 설정 등록
Code
인증 처리자 - AjaxAuthenticationProvider
•
AuthenticationProvider 인터페이스를 구현합니다.
•
인증 작동 조건
◦
supports(Class<?> authentication)
▪
ProviderManager로부터 넘어온 인증객체가 AjaxAuthenticationToken 타입이면 작동합니다.
•
인증 검증이 완료되면 AjaxAuthenticationToken을 생성하여 최종 인증 객체를 반환합니다.
1. security / provider / AjaxAuthenticationProvider
Code
2. security / config / AjaxSecurityConfig 설정 등록
Code
인증 핸들러 AjaxAuthenticationSuccessHandler AjaxAuthenticationFailureHandler
AjaxAuthenticationSuccessHandler
•
AuthenticationSuccessHandler인터페이스 구현
•
Response Header 설정
◦
response.setStatus(HttpStatus.OK.value())
◦
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
•
JSON형식으로 변환하여 인증 객체 리턴 함
◦
objectMapper.writeValue(response.getWriter(), ResponseBody.ok(userDto));
AjaxAuthenticationFailureHandler
•
AuthenticationFailureHandler 인터페이스 구현
•
Response Header 설정
◦
response.setStatus(HttpStatus.UNAUTHORIZED.value())
◦
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
•
JSON 형식으로 변환하여 오류 메시지 리턴 함
◦
objectMapper.writeValue(response.getWriter(), ResponseBody.error(userDto));
1. security / handler / AjaxAuthenticationSuccessHandler
Code
2. security / handler / AjaxAuthenticationFailureHandler
Code
3. security/ config/ AjaxSecurityConfig 설정 등록
Code
인증 및 인가 예외 처리
AjaxLoginUrlAuthenticationEntryPoint AjaxAccessDeniedHandler
AjaxLoginUrlAuthenticationEntryPoint
•
인증을 받지못한 사용자가 허락되지 않은 자원에 접근시도를 할 경우 처리하는 클래스
•
ExceptionTranslationFilter 에서 인증 예외 시 호출
•
AuthenticationEntryPoint 인터페이스 구현
•
인증 오류 메시지와 401 상태 코드 반환
◦
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
AjaxAccessDeniedHandler
•
인증을 받은 사용자가 허락되지 않은 자원에 접근시도시 호출되는 클래스
•
ExceptionTranslationFilter 에서 인가 예외 시 호출
•
AccessDeniedHandler 인터페이스 구현
•
인가 오류 메시지와 403 상태 코드 반환
◦
response.sendError(HttpServletResponse. SC_FORBIDDEN, "forbidden");
1. security / handler / AjaxLoginUrlAuthenticationEntryPoint
Code
2. security / handler / AjaxAccessDeniedhandler
Code
3. security/ config / AjaxSecurityConfig 설정 등록
Code
Ajax Custom DSLs 구현하기
•
Custom DSL (도메인 특화 언어) : 특정한 도메인을 정용하는데 특화된 컴퓨터 언어
◦
AbstractHttpConfigurer
▪
스프링 시큐리티 초기화 설정 클래스
▪
필터, 핸들러, 메서드, 속성 등을 한 곳에 정의하여 처리할 수 있는 편리함 제공
▪
public void init(H http) throws Exception - 초기화
▪
public void configure(H http) - 설정
•
HttpSecurity 의 apply(C configurer)메서드 사용
1. security / configs / AjaxLoginConfigurer
Code
2. security / configs / AjaxSecurityConfig 설정 등록및 수정
Code
Ajax 로그인 구현 & CSRF 설정
•
헤더 설정
◦
전송 방식이 Ajax 인지의 여부를 위한 헤더 설정
▪
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
◦
CSRF 헤더 설정
<meta id="_csrf" name="_csrf" th:content="${_csrf.headerName}"/>
<meta id="_csrf_header" name="_csrf_header" th:content="${_csrf.headerName}"/>
HTML
복사
var csrfHeader = $('meta[name=_csrf_header"]').attr('content')
var csrfToken = $('meta[name="_csrf"]').attr('content')
xhr.setRequestHeader(csrfHeader, csrfToken);
JavaScript
복사