Java Spring Security Custom permitAll 구현

떡ol·2023년 5월 29일
0


이전 포스트에서 Url에 따른 인가 정책(hasRole)을 DB로 관리하는 방법을 알아보았습니다. 단 permitAll()과 같이 모든 사용자들에게 허용된 페이지를 작업하기 위해서는 또 다른 작업이 필요합니다.

Custom FilterSecurityInterceptor

이전 포스트를 확인해보시면 FilterSecurityInterceptor의 인스턴스를 새로 생성하여, 인가 정책에 필요한 객체를 셋팅해주는 부분이 있습니다. 즉, FilterSecurityInterceptor안에서 내부적으로 MetaSourceAuthenticationManager들을 읽어와 작업을 처리하게 해주는 겁니다. 그렇다는 것은FilterSecurityInterceptor안에서 requstinvoke해주는 부분이 있을겁니다. 우리는 이 부분을 수정하여, 정상필터 실행 전 처리 하게 해주는 PermitAll을 구현 시킬 수 있습니다.

PermitAllFilter

FilterSecurityInterceptor를 상속받는 클래스 파일을 하나 만들어 작업을 시작합니다.
FilterSecurityInterceptor의 기능에서 조금만 수정할 것이므로 전체 코드 내용을 복사해서 옵니다.

public class PermitAllFilter extends FilterSecurityInterceptor {
// 1.FilterSecurityInterceptor안에 내용을 그대로 복붙합니다. 
    private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
    private boolean observeOncePerRequest = true;
	// 초기화할때 셋팅을위해 작성합니다. 생성자도 마찬가지 입니다.
    private List<RequestMatcher> permitAllRequestMatchers = new ArrayList<>();

    public PermitAllFilter(String...permitAllResources) {
        for(String resource : permitAllResources){
            permitAllRequestMatchers.add(new AntPathRequestMatcher(resource));
        }
    }
	// 3. 그럼 beforeInvocation를 override해서 구현합니다. 
    @Override
    protected InterceptorStatusToken beforeInvocation(Object object) {

        boolean permitAll = false;
        // 4. 현재 요청정보를 받아옵니다.
        HttpServletRequest request = ((FilterInvocation) object).getRequest();
        // 5. request가 permitAll에 해당되어있으면 모두 허용으로...
        for(RequestMatcher requestMatcher : permitAllRequestMatchers){
            if(requestMatcher.matches(request)){
                permitAll = true;
                break;
            }
        }
        // 6. permitAll()이면 다른 인가정책을 확인 할 필요가 없으므로 종료를 의미하게 null로 처리합니다.
        if(permitAll){
            return null;
        }
		// permitAll 이 아니면 평상시대로 하면 되겠죠?
        return super.beforeInvocation(object);
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        if (fi.getRequest() != null && fi.getRequest().getAttribute("__spring_security_filterSecurityInterceptor_filterApplied") != null && this.observeOncePerRequest) {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } else {
            if (fi.getRequest() != null && this.observeOncePerRequest) {
                fi.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
            }
			// 2. super.로 되어있겠지만 저희는 직접 구현할 것이므로 지우고 해당클래스의 매서드를 하나 구현해줍니다.
            InterceptorStatusToken token = beforeInvocation(fi);

            try {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            } finally {
                super.finallyInvocation(token);
            }

            super.afterInvocation(token, (Object)null);
        }

    }

}

WebSecurityConfigurerAdapter 수정

이전 포스트에서 FilterSecurityInterceptor를 생성했던 부분을 이제는 만들어 놓으신 PermitAllFilter로 대체 하시면 됩니다.

	//이 부분은 하드 코딩이기는 하지만 이 역시 이전 포스트처럼 DB로 불러와서 처리하게 하셔도 됩니다.
	private String[] permitAllResources = {"/", "/login", "/user/login/**"};

    @Bean
    public PermitAllFilter customFilterSecurityInterceptor() throws Exception {
        PermitAllFilter permitAllFilter = new PermitAllFilter(permitAllResources);
        permitAllFilter.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource());
        permitAllFilter.setAccessDecisionManager(affirmativeBased());
        permitAllFilter.setAuthenticationManager(authenticationManagerBean());
        return permitAllFilter;
    }
profile
하이

0개의 댓글