• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

인증 실패하지 않고 로그인할 경우 savedRequest

20.05.22 02:08 작성 조회수 1.08k

3

안녕하세요! 

먼저 강의 너무 잘 듣고있습니다. 감사합니다.

이번 강의를 보는 중 의문점이 생겨 질문 남깁니다.
강의 마지막의 디버깅 과정에서 과정 부분입니다.

캐싱 과정 확인을 위해 인위적으로 /로 접근한 후 요청 정보를 캐시에 남기게 하고, login 페이지로 redirect 되게 하여 인증을 하여, 캐시에서 요청 정보를 가져와서 해당 경로로 이동하게 하였습니다.
(successHandler()를 통해서)

여기서 의문점이 생겼습니다. /로 접근하지 않고 바로 /login으로 접근해 요청 정보를 캐싱하지 않는 경우는 어떻게 될지가 궁금했습니다.

결과는 예상했던대로 savedRequest가 null이어서 에러가 났습니다.

그래서 제 결론은 이 요청 정보 캐싱 기능을 이용하는 경우, successHandler에서 바로 /login으로 접근하는 경우도 고려해서 구현해야 하는지, 아니면 successHandler 이 외에 자동 설정이나 다른 설정을 해야하는 것이 있는지 궁금합니다.

감사합니다!

답변 5

·

답변을 작성해보세요.

4

인증에 성공하게 되면 기본적으로 스프링 시큐리티가 SavedRequestAwareAuthenticationSuccessHandler 클래스를 사용합니다.

그래서 savedRequest 의 생성여부에 따른 대한 처리를 별도로 하실 필요가 없습니다.

다만 AuthenticationSuccessHandler 에서 특정한 로직을 처리해야 하거나 추가적인 기능을 사용해야 한다면 SavedRequestAwareAuthenticationSuccessHandler 클래스를 상속해서 기본기능은 부모클래스에게 맡기고 커스터마이징 할 부분을 별도로 처리하시면 될 것 같습니다.

예를 들어

public class CustomAuthenticationSuccessHandler 
extends SavedRequestAwareAuthenticationSuccessHandler {

@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {

// 추가로직 구현

로깅처리 ..
세션처리 ..
예외처리 ..
등등 ...

super.onAuthenticationSuccess(request, response, authentication);

}

그리고 SecurityConfig 클래스에서 

http.formLogin()

        .successHandler(new CustomAuthenticationHandler())

로 설정하시면 됩니다.

상황에 따라 여러 방안으로 구현하시면 됩니다

4

먼저 아래쪽에 로시츠키 님께서 질문하신 "RequestCache와 savedRequest에 대해서" 에 대한 답변을 먼저 참조해 주시기 바랍니다.

요청 캐시 즉 RequestCache 는 그렇게 어려운 개념이 아니죠.

클라이언트가 요청 시 요청과정에서 발생하는 여러 정보들을 세션에 담아 두고 필요시 꺼내어 쓰기 위한 기능입니다.

유념할 점은 이 요청 캐시를 스프링 시큐리티가 언제, 어떤 이유로 사용하느냐를 이해하는 것이 중요합니다.

스프링 시큐리티에서는 SavedRequest 에 캐시용 데이터들을 담아 두고 이 객체를 세션에 저장하게 되는데 이 시점은 정확하게 인증에 실패할 때가 아닌 인증의 과정을 아예 거치지 않은 상태에서 인증 사용자에게만 허용되는 자원에 접근했다가  FilterSecurityInterceptor 필터에 의해서 접근이 거부되어 예외가 발생하게 되고 그 예외를 ExceptionTranslationFilter 가 받아서 처리하는 과정중에 requestCache.saveRequest(request, response) 처리가 이루어 진다는 점입니다.

그리고 이후에 사용자가 인증에 성공하게 되면 인증필터가 ExceptionTranslationFilter 에서 처리한 RequestCache 와 SavedRequest  객체를 참조해서 클라이언트가 원래 접근하고자 했던 자원의 정보를 얻어서 SuccessHandler 에서 리다이렉트 할 뿐 이러한 원리를 어떤 시점과 위치에서 활용하느냐는 개발자의 몫입니다.

그래서  /login 으로 바로 접근해서 인증에 성공하게 되면 RequestCache 와 SavedRequest  의 처리가 전혀 이루어지지 않기 때문에 당연히 savedRequest  는 null 일 수 밖에 없습니다.

즉 인증에 성공한 상태에서 자원에 접근할 경우 FilterSecurityInterceptor 가 접근을 거부하지 않을 것이고 그러면 예외가 발생하지 않으므로 ExceptionTranslationFilter 를 호출할 일이 없기 때문에 savedRequest  객체는 생성되지 않습니다.

savedRequest 는 FilterSecurityInterceptor 와 ExceptionTranslationFilter 의 과정에서 생성되는 객체임을 기억하시면 됩니다.

그렇다면 SuccesHandler 에서 savedRequest  가 null 인치 체크하는 구문이 필요하고 상황에 따른 분기 로직이 구현되어야 할 것입니다.

참고로 AuthenticationSuccessHanlder 의 구현체 중 스프링 시큐리티에서 제공하는SavedRequestAwareAuthenticationSuccessHandler 클래스가 있는데 소스를 보시면 다음과 같은 부분이 있습니다.

public class SavedRequestAwareAuthenticationSuccessHandler extends
SimpleUrlAuthenticationSuccessHandler {
protected final Log logger = LogFactory.getLog(this.getClass());

private RequestCache requestCache = new HttpSessionRequestCache();

@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {

SavedRequest savedRequest = requestCache.getRequest(request, response);

if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);

return;
}

보시면 savedRequest == null 일 경우 부모 클래스인 SimpleUrlAuthenticationSuccessHandler 에서 처리하도록 위임합니다.

if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);

return;
}

그래서 SimpleUrlAuthenticationSuccessHandler 에서 이부분을 어떻게 처리를 하고 있는지 소스를 분석해서 SuccessHandler 구현하실 때 참고하시면 될 것 같습니다.

아마 신수웅 님께서 질문하신 의도대로 스프링 시큐리티가 처리하고 있는 것 같습니다.

2

상세한 답변 정말 감사드립니다!
궁금증을 해소할 수 있었습니다.

추가적으로 간단한 질문을 드리자면, 
언급해주신 SavedRequestAwareAuthenticationSuccessHandler를 시큐리티 설정에서 주입받아 설정을 하면 되는 것인지,
이 Handler를 호출해 자동으로 처리 되는 부분이 있는 것인지 궁금합니다.
(예를 들면, 인증 예외가 발생해서 
savedRequest가 생성되는 경우, 인증 성공 후 이 Handler를 자동 호출한다던지??)

감사합니다!!

1

상세한 답변 정말 감사드립니다!!

정말 많은 도움이 됩니다~!!

0

원석나님의 프로필

원석나

2021.12.29

"/login"으로 직접 url로 접근하여 인증처리하게 되면 왜 savedRequest가 null인지 이해를 못하겠습니다

 

최강개발자님의 프로필

최강개발자

2022.01.19

제가 이해한 위에 내용 토대로 언제 인증을 하지 못해 requestCache되는 시점이 중요합니다. 근데 login url은 애초에 인증을  인증을 받는 페이지가 아닙니다. 즉 "닌 인증의 과정을 아예 거치지 않은 상태에서 인증 사용자에게만 허용되는 자원" 를 접근할때 requestCache에 저장된다고 이해하였습니다. 

 

위에 내용은 login로  바로 접근하게되어서 그전에 페이지가 없어서  null로 들어온걸로 이해하였습니다.

 

이