스프링 시큐리티

Ch02. 스프링 시큐리티 주요 아키텍처 이해 - 인증 저장소 필터(SecurityContextPersistenceFilter)

webmaster 2022. 1. 16. 16:07
728x90

SecurityContext 객체의 생성, 저장, 조회

  • 익명 사용자(인증하지 않고 자원 접근)
    • 새로운 SecurityContext 객체를 생성하여 SecurityContextHolder에 저장
    • AnonymousAuthenticationFilter에서AnonymousAuthenticationToken 객체를 SecurityContext에 저장
  • 인증
    • 새로운 SecurityContext 객체를 생성하여 SecurityContextHolder에 저장
    • UsernamePasswordAuthenticationFilter에서인증 성공 후 SecurityContext에UsernamePasswordAuthenticationToken 객체를 SecurityContext에 저장
    • 인증이 최종 완료되면 Session에SecurityContext를 저장
  • 인증 후
    • Session에서SecurityContext 꺼내어 SecurityContextHolder에 저장
    • SecurityContext 안에 Authentication 객체가 존재하면 계속 인증을 유지한다
  • 최종 응답 시 공통
    • SecurityContextHolder.clearContext()
    • 매 요청마다, SecurityContextHolder안에 SecurityContext를 저장하기 때문에 매번 삭제해주는 작업을 해야된다.

동작 과정

  • SecurityContextPersistenceFilter
    • 매요청마다 사용자 요청을 받는다.
  • 인증 전일 경우 새로운 콘텍스트를 생성한다
    • 인증 받기전의 SecurityContext와 인증 후의 SecurityContext
    • AuthFilter에서 인증이 성공하게 된다면 SecurityContextHoler에 인증된 객체를 저장한다.
    • 클라이언트에 응답할 때, SecurityContextPersistenceFilter가 세션에 SecurityContext를 저장한 뒤, SecurityContext 자원을 삭제해 준다.
  • 인증받은 이후일 경우 세션에 SecurityContext객체가 있는지 확인한다.
    • 인증을 받았을 경우 세션에 SecurityContext 값이 있기 때문에 SecurityContextPersistenceFilter가 SecurityContextHolder에 SecurityContext를 저장하고 다음 필터로 이동한다.
  • SecurityContextPersistenceFilter의 DoFilter
    • private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
         // ensure that filter is only applied once per request
         if (request.getAttribute(FILTER_APPLIED) != null) {
            chain.doFilter(request, response);
            return;
         }
         request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
         if (this.forceEagerSessionCreation) {
            HttpSession session = request.getSession();
            if (this.logger.isDebugEnabled() && session.isNew()) {
               this.logger.debug(LogMessage.format("Created session %s eagerly", session.getId()));
            }
         }
         HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
         SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);
         try {
            SecurityContextHolder.setContext(contextBeforeChainExecution);
            if (contextBeforeChainExecution.getAuthentication() == null) {
               logger.debug("Set SecurityContextHolder to empty SecurityContext");
            }
            else {
               if (this.logger.isDebugEnabled()) {
                  this.logger
                        .debug(LogMessage.format("Set SecurityContextHolder to %s", contextBeforeChainExecution));
               }
            }
            chain.doFilter(holder.getRequest(), holder.getResponse());
         }
         finally {
            SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
            // Crucial removal of SecurityContextHolder contents before anything else.
            SecurityContextHolder.clearContext();
            this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
            request.removeAttribute(FILTER_APPLIED);
            this.logger.debug("Cleared SecurityContextHolder to complete request");
         }
      }

 

728x90