이전 포스트에서 Url
에 따른 인가 정책(hasRole)을 DB로 관리하는 방법을 알아보았습니다. 단 permitAll()
과 같이 모든 사용자들에게 허용된 페이지를 작업하기 위해서는 또 다른 작업이 필요합니다.
이전 포스트를 확인해보시면 FilterSecurityInterceptor
의 인스턴스를 새로 생성하여, 인가 정책에 필요한 객체를 셋팅해주는 부분이 있습니다. 즉, FilterSecurityInterceptor
안에서 내부적으로 MetaSource
나 AuthenticationManager
들을 읽어와 작업을 처리하게 해주는 겁니다. 그렇다는 것은FilterSecurityInterceptor
안에서 requst
를 invoke
해주는 부분이 있을겁니다. 우리는 이 부분을 수정하여, 정상필터 실행 전 처리 하게 해주는 PermitAll을 구현 시킬 수 있습니다.
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);
}
}
}
이전 포스트에서 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;
}