부트캠프

Spring Security - 권한 부여 컴포넌트

hunm719 2023. 3. 22. 21:53
1.권한 부여 컴포넌트를 이용한 권한 부여 처리

-기본 part 2의 권한 부여 처리 흐름을 보다 자세히 이해하기 위해 Spring Security의 몇 가지 권한 부여 컴포넌트들의 내부 코드를 들여다볼 예정임

Spring Security의 컴포넌트로 보는 권한 부여(Authorization) 처리 흐름

 

 [1] AuthorizationFilter

  ● URL을 통해 사용자의 액세스를 제한하는 권한 부여 Filter

  ● Spring Security 5.5 버전부터 FilterSecurityInterceptor를 대체하고 있음

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class AuthorizationFilter extends OncePerRequestFilter {
 
    private final AuthorizationManager<HttpServletRequest> authorizationManager;
  
  ...
  ...
    
  // (1)
    public AuthorizationFilter(AuthorizationManager<HttpServletRequest> authorizationManager) {
        Assert.notNull(authorizationManager, "authorizationManager cannot be null");
        this.authorizationManager = authorizationManager;
    }
 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
 
        AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request); // (2)
        this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
        if (decision != null && !decision.isGranted()) {
            throw new AccessDeniedException("Access Denied");
        }
        filterChain.doFilter(request, response);
    }
 
  ...
  ...
 
}
cs

<위의 코드는 AuthorizationFilter 코드 일부>

  ● (1)과 같이 AuthorizationFilter 객체가 생성될 때, AuthorizationManager를 DI 받는 것을 확인할 수 있으며, DI 받은 AuthorizationManager를 통해 권한 부여 처리를 진행함

  ● (2)와 같이 DI 받은 AuthorizationManager의 check() 메서드를 호출해 적절한 권한 부여 여부를 체크함

      ○ check() 메서드는 AuthorizationManager 구현 클래스에 따라 권한 체크 로직이 다름

      ○ URL 기반으로 권한 부여 처리를 하는 AuthorizationFilter는 AuthorizationManager의 구현 클래스로 RequestMatcherDelegatingAuthorizationManager를 사용함

 

 

 [2] AuthorizationManager

  ● 권한 부여 처리를 총괄하는 매니저 역할을 하는 인터페이스

1
2
3
4
5
6
7
8
9
@FunctionalInterface
public interface AuthorizationManager<T> {
  ...
  ...
 
    @Nullable
    AuthorizationDecision check(Supplier<Authentication> authentication, T object);
 
}
cs

<위의 코드는 AuthorizationManager 코드 일부>

  ● check() 메서드 하나만 정의되어 있으며, Supplier와 제너릭 타입의 객체를 파라미터로 가짐

 

 

[3] RequestMatcherDelegatingAuthorizationManager

  ● AuthorizationManager의 구현 클래스 중 하나

  ● 직접 권한 부여 처리를 수행하지 않고 RequestMatcher 를 통해 매치되는 AuthorizationManager 구현 클래스에게 권한 부여 처리를 위임함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public final class RequestMatcherDelegatingAuthorizationManager implements AuthorizationManager<HttpServletRequest> {
 
  ...
  ...
 
    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace(LogMessage.format("Authorizing %s", request));
        }
 
    // (1)
        for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
 
            RequestMatcher matcher = mapping.getRequestMatcher(); // (2)
            MatchResult matchResult = matcher.matcher(request);
            if (matchResult.isMatch()) {   // (3)
                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("Abstaining since did not find matching RequestMatcher");
        return null;
    }
}
cs

<위의 코드는 RequestMatcherDelegatingAuthorizationManager 클래스의 코드 일부>

  ● (1)과 같이 check() 메서드의 내부에서 루프를 돌면서 RequestMatcherEntry 정보를 얻은 후에 (2)와 같이 RequestMatcher 객체를 얻음

  ● (3)과 같이 MatchResult.isMatch() 가 true이면 AuthorizationManager 객체를 얻은 뒤, 사용자의 권한을 체크함

      ○ 여기서의 RequestMatcher는 SecurityConfiguration에서 .antMatchers("/orders/**").hasRole("ADMIN") 와 같은 메서드 체인 정보를 기반으로 생성됨

 

 

 

 

 

-내용 출처 : code states