Spring Security Authorization Error

Gogh·2023년 9월 1일

Trouble Shooting

목록 보기
3/3
post-thumbnail

권한 부여 시 context.SecurityContext.getAuthentication() is null Issue

사이드 프로젝트 중 발생
현재 사이드 프로젝트의 인증 인가 구조

  • OAuth2 Login 만 허용하며, 클라이언트 단 에서 인증 완료 후 회원 데이터를 가져오기 위한 접근 Token 값을 서버에서 받아 OAuth2 플랫폼으로 회원의 정보를 받아오는 방식
  • 회원의 정보를 활용하여 백엔드 서버 자체 JWT Token을 클라이언트로 발급하여 헤더의 Token 값으로 인가에 활용한다
  • 즉, 인증은 백엔드 서버에서 구현하지 않으며, 클라이언트에서 헤더 값으로 들어온 JWT Token을 인증하여 서버에서는 권한 부여만 하는 방식이다

Cause

  • Authentication 데이터가 SecurityContext에 저장 되고 있는지 확인하기 위해 직접 구현한 AuthenticationFilter에서 Context 객체의 데이터를 조회하여 로깅하였다
  • 그 결과, SecurityContext 객체 내부에 Authentication 데이터가 NULL 값으로 확인 됨
  • JWT Token 검증과 Token 내부의 권한 설정에는 문제가 없었으며, Token 정상 인증됨에도 불구하고, Full authentication is required to access this resource 라는 에러 메세지를 받을 수 있었다

문제 발생 코드

// SecurityConfig.java
//..........
.apply(new CustomFilterConfig())
                .and()
                .httpBasic().disable()
                .headers()
                .addHeaderWriter(new XFrameOptionsHeaderWriter(
                        XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN))
                .and()
                .formLogin().disable()
                .logout().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        return http.build();
    }


    public class CustomFilterConfig extends AbstractHttpConfigurer<CustomFilterConfig, HttpSecurity> {
        @Override
        public void configure(HttpSecurity builder) throws Exception {

            JwtVerificationFilter jwtVerificationFilter = new JwtVerificationFilter(jwtTokenizer, authorityUtils);
            builder.addFilterBefore(jwtVerificationFilter, SecurityContextHolderFilter.class);
        }
    }
    //.......
  • CustomFilterConfig 정상적으로 적용 해 주고 있음
  • 문제 발생 코드는 CustomFilterConfig 내부의 addFilterBefore(jwtVerificationFilter, SecurityContextHolderFilter.class); 부분 이다
  • SecurityContextHolderFilter 의 역할이 단순 Context 데이터를 확인하는 필터로 착각하였기에 .addFilterBefore() 를 활용하여 SecurityContextHolderFilter 가 적용되기 이전에 JwtVerificationFilter(권한 부여 Filter)를 적용 하였다.
  • SecurityContextHolderFilter의 코드를 확인 한 결과 doFilter() 에서 SecurityContextHolderStrategySecurityContert 객체를 설정 해 주고 있었다.
// SecurityContextHolderFilter.java
// ............
@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
    }

    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        if (request.getAttribute(FILTER_APPLIED) != null) {
            chain.doFilter(request, response);
            return;
        }
        request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
        Supplier<SecurityContext> deferredContext = this.securityContextRepository.loadDeferredContext(request);
        try {
            this.securityContextHolderStrategy.setDeferredContext(deferredContext);
            chain.doFilter(request, response);
        }
        finally {
            this.securityContextHolderStrategy.clearContext();
            request.removeAttribute(FILTER_APPLIED);
        }
    }
    // ............

  • 디버깅 결과, SecurityContextAuthentication 객체는 NULL 값이였다.
  • 위 필터가 적용되기 이전에, 즉, SecurityContext 객체를 SecurityContextHolderStrategy 설정을 해주기도 전에 권한 부여 Filter에서 권한을 설정 해주는 상황이다
  • 지금 생각해 보면 당연한 결과라 생각된다, SecurityContext 설정 후 FilterChain을 통해 다음 필터로 이동하여, 권한 부여 Filter에서 Authentication을 설정 해 주어야 한다
  • 어떤 객체든, 코드를 확인 하고 정확히 무슨 역할을 하는지 알고 사용하도록 하자

Solve

개선 코드

//SecurityConfig.java
//........
    public class CustomFilterConfig extends AbstractHttpConfigurer<CustomFilterConfig, HttpSecurity> {
        @Override
        public void configure(HttpSecurity builder) throws Exception {

            JwtVerificationFilter jwtVerificationFilter = new JwtVerificationFilter(jwtTokenizer, authorityUtils);
            builder.addFilterAfter(jwtVerificationFilter, SecurityContextHolderFilter.class);
        }
    }
    //.......
  • ScurityConfig의 CustomFilterConfig 내부에서 addFilterBefore() -> addFilterAfter()로 변경하였다
  • 디버깅 결과 SecurityContextHolderFilter 적용 후에 권한 부여 Filter가 동작 하는 것을 확인
  • JWT Token이 인증 되고, Authentication도 정상적으로 설정 되어 권한 부여가 동작 하게 되었다.
profile
컴퓨터가 할일은 컴퓨터가

0개의 댓글