권한 부여 처리 흐름

AuthorizationFilter
는 spring Security Filter Chain
에서 URL을 통해 사용자 액세스를 제한하는 권한 부여 Filter이다.
AuthorizationFilter
는 SecurityContextHolder
로 부터 Authentication
을 얻은 후 Authentication
과 HttpServletRequest
를 AuthorizationManager
에게 전달한다.
AuthorizationManger
- 권한 부여를 총괄하는 인터페이스
RequestMatcherDelegatingAuthorizationManager
가 구현체 중 하나
RequestMatcherDelegatingAuthorizationManager
RequestMatcher
평가식을 기반으로 해당 평가식에 매치되는 AuthorizationManger
에게 권한 부여 처리를 위임하는 역할
RequestMatcherDelegatingAuthoriztionManager
내부에서 매치되는 AuthorizationManager
구현 클래스가 있다면 해당 구현 클래스가 사용자의 권한을 체크한다.
- 적절한 권한이라면 계속해서 프로세스를 진행하고 , 적절한 권한이 아니라면
AccessDeniedException
이 throw 되고 ExceptionTranslationFilter
가 AccessDeniedException
을 처리하게 된다.
권한 부여 컴포넌트
AuthorizationFilter
public class AuthorizationFilter extends OncePerRequestFilter {
private final AuthorizationManager<HttpServletRequest> authorizationManager;
...
...
public AuthorizationFilter
(AuthorizationManager<HttpServletRequest> authorizationManager) {
Assert.notNull(authorizationManager, "...");
this.authorizationManager = authorizationManager;
}
@Override
protected void doFilerInternal
(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
AuthorizationDecision decision = this.authorizationManager
.check(this::getAuthentication, request);
...
...
filterChain.doFilter(request,response);
}
...
}
AuthorizationFilter
객체가 생성될 때, AuthorizationManager
를 DI 받는다.
- DI 받은
AuthorizationManager
의 check()
메서드 호출을 통해 적절한 권한 부여 여부를 체크한다.
AuthorizationManager
의 구현 클래스에 따라 check()
메서드는 권한 체크 로직이 다르다.
AuthorizationManager
@FunctionalInterface
public interface AuthorizationManager<T> {
...
...
@Nullable
AuthorizationDecision check(Supplier<Authentication> authentication , T object);
}
AuthorizationManger
인터페이스는 check()
메서드 하나만 정의되어 있고 Supplier 와 제너릭 타입의 객체를 파라미터로 갖는다.
RequestMatcherDelegatingAuthorizationManager
public final RequestMatcherDelegatingAuthorizationManager
implements AuthorizationManager<HttpServletRequest> {
...
...
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication,
HttpServletRequest request) {
if(this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.foramt("...",request);
}
for(RequestMathcherEntry<AuthorizationManager<ResultAuthorizationContext>>
mapping : this.mappings) {
RequestMatcher matcher = mapping.getRequestMatcher();
if (matchResult.isMatch()) {
AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
if (this.logger.isTraceEnabled()) {
this.logger
.trace(LogMessage.format("Checking authorization on %s using %s", request, manager));
}
return manager.check(authentication,
new RequestAuthorizationContext(request, matchResult.getVariables()));
this.logger.trace("...");
return null;
}
}
check()
메서드 내부에서 for 루프를 돌며 RequestMatcherEntry
정보를 얻은 후 ResultMatcher
객체를 얻는다.
matchResult.isMatch()
가 true 이면 AuthorizationManager
객체를 얻는 후, 사용자 권한을 체크한다.
ResultMatcher
는 SecurityConfiguration
에서 .antMatchers("/orders/**").hasRole("ADMIN")
와 같은 메서드 체인 정보를 기반으로 생성된다.