공부기록/Spring Security

[추가] AuthorizeRequests vs AuthorizeHttpRequests

jhs0129 2022. 12. 28. 14:50
320x100
반응형

목차

서론

이번글에선 Spring Security를 공부하면서 버전업에 의한 변경점에 대해서 다뤄볼 예정이다

기존에는 authorizeRequests를 사용하여 EndPoint에 관한 설정을 했지만 5.6버전 이후(아마도? docs보면 5.6부터 추가된 듯 보이긴 하는데) authorizeHttpRequests를 사용하는 것을 권장하고 있다

단순히 사용만 하는 것에 있어서는 그렇게 큰 차이는 없는 것 같지만 내부에서 동작이 크게 바뀌었기 때문에 한번 정리를 해보기로 한다

AuthorizeRequests

기존에 5.6버전 이전에 사용되는 방식이다

위 사진과 같이 SecurityFilterChain에 FilterSecurityInterceptor라는 필터가 추가된다

1번부터 순차적으로 동작을 보게되면

  1. SecurityContextHolder로 부터 Authentication객체 받아오기
  2. HttpServletRequest, HttpServletResponse, FilterChain을 이용하여 FilterInvocation 생성
  3. SecurityMetadataSource에 FilterInvocation를 전달하여 ConfigAtributes 가져오기
  4. AccessDecisionManager에 Authentication, FilterInvocation, ConfigAttribute 전달
  5. 접근 불가일 경우 예외 던짐
    • ExceptionTranslationFilter에서 예외 처리
  6. 접근 가능한 경우 filterChain타고 다음 filter로 전달

너무나도 많은 과정을 거치게 되고 권한이 필요없는 경로에서도 authentication에 관한 정보를 조회를 해야하는 단점이 있다

이러한 많은 과정을 단순화해서 만들어 진것이 authorizeHttpRequests이다

public class AffirmativeBased extends AbstractAccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException {
        int deny = 0;
        //모든 경로에 대해서 권한을 확인한다
        for (AccessDecisionVoter voter : getDecisionVoters()) {
            int result = voter.vote(authentication, object, configAttributes);
            switch (result) {
            case AccessDecisionVoter.ACCESS_GRANTED:
                return;
            case AccessDecisionVoter.ACCESS_DENIED:
                deny++;
                break;
            default:
                break;
            }
        }
        if (deny > 0) {
            throw new AccessDeniedException(
                    this.messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
        }
        checkAllowIfAllAbstainDecisions();
    }
}

AuthorizeHttpRequests

5.6버전 이후 사용시 권장

기존과는 다르게 FilterSecurityInterceptor가 아닌 AuthorizationFilter라느 필터가 추가된다

사진만 봐도 과정이 매우 단순해 진 것을 볼 수 있다

1번부터 순차적으로 동작을 보게되면

  1. SecurityContextHolder로 부터 Authentication객체 받아오기
    • 이 부분에 대해서는 지연조회를 위해 Supplier에 한번 래핑되어 가져오게 된다
  2. Authorizationmanager에 Supplier-Authentication, HttpServletRequest 전달
  3. 접근 불가일 경우 예외 던짐
    • ExceptionTranslationFilter에서 예외 처리
  4. 접근 가능한 경우 filterChain타고 다음 filter로 전달

Spring Security Docs를 보게되면 Supplier에 한번 래핑을 함으로써 모든 요청에 대해서 권한이 필요한지를 보는 것이 아닌 권한이 요구되는 곳에서만 확인을 하게 된다고 한다

public final class RequestMatcherDelegatingAuthorizationManager implements AuthorizationManager<HttpServletRequest> {
    private final List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
        for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {
            RequestMatcher matcher = mapping.getRequestMatcher();
            MatchResult matchResult = matcher.matcher(request);
            //요청받은 경로가 권한여부를 확인해야하는지 체크
            if (matchResult.isMatch()) {
                AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
                return manager.check(authentication,
                        new RequestAuthorizationContext(request, matchResult.getVariables()));
            }
        }
        this.logger.trace("Abstaining since did not find matching RequestMatcher");
        return null;
    }
}

이러한 것을 모르더라도 추후 나온것이 더 좋다고 Spring을 믿고 사용해도 되지않을까라는 생각이다

지금당장 필요한 것은 아니지만 이런 것까지 굳이라는 생각보다는 동작을 파악하고 보면서 재밌는 시간이었던 것 같다

참고 사이트

Spring Security Docs

320x100
반응형