[Spring Security] 스프링 시큐리티의 인가(Autorization)

olsohee·2023년 8월 7일
0

Spring Security

목록 보기
3/6

1. AuthorizationFilter

AuthorizationFilter는 SecutityFilterChain에 속해 있는 필터 중 하나로, HttpServletRequest에게 인가를 제공한다.

1.1. 등록 방법

AuthorizationFilter 필터 등록은 다음과 같이 SecurityFilterChain 등록시, authorizeHttpRequests() 메소드를 통해 등록하면 된다.

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

    http.authorizeHttpRequests(authHttp ->
                    authHttp.requestMatchers(POST, "/join", "/login").permitAll())
                    ...
                    
    return http.build();
}

1.2. 실행 흐름

  1. 먼저 AuthorizationFilter는 SecurityContextHolder에서 Authentication 객체를 얻어서 Authentication과 HttpServletRequest를 AuthorizationManager의 check() 메서드로 넘긴다.

  2. AuthorizationManager의 check() 메서드는 AuthorizationDecision을 반환한다.

  3. AuthorizationFilter는 반환받은 AuthorizationDecision을 검증하며 적절한 권한인지 확인하고, 검증에 실패하면 AccessDeniedException 예외를 발생시킨다.

    AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
    this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
    if (decision != null && !decision.isGranted()) {
    	throw new AccessDeniedException("Access Denied");
    }
    chain.doFilter(request, response);
  4. 만약 검증에 성공하면, 적절한 권한인 것이므로 다음 FilterChain을 이어간다.


2. AuthorizationManager

AuthorizationManager는 인터페이스로, 인가(Authorization)를 담당한다.

@FunctionalInterface
public interface AuthorizationManager<T> {

	default void verify(Supplier<Authentication> authentication, T object) {
		AuthorizationDecision decision = check(authentication, object);
		if (decision != null && !decision.isGranted()) {
			throw new AccessDeniedException("Access Denied");
		}
	}

	@Nullable
	AuthorizationDecision check(Supplier<Authentication> authentication, T object);

}

AuthorizationManager 인터페이스에는 두 가지 메서드(verify(), check())가 있다. verify 메서드는 내부적으로 check 메서드를 호출하고, check 메서드는 AuthorizationDecision을 반환한다.


3. AuthorizationDecision

public class AuthorizationDecision {

	private final boolean granted;

	public AuthorizationDecision(boolean granted) {
		this.granted = granted;
	}

	public boolean isGranted() {
		return this.granted;
	}

	@Override
	public String toString() {
		return getClass().getSimpleName() + " [granted=" + this.granted + "]";
	}

}

AuthorizationDecision은 생성자로 boolean granted를 넣어서 생성하고, isGranted() 메서드를 통해 인증 여부를 확인할 수 있다.

즉 AuthorizationManager의 check() 메서드를 통해 반환된 AuthorizationDecision을 verify() 메서드에서 검증하여 검증에 실패하면 AccessDeniedException 예외를 발생시킨다.


4. RequestMatcherDelegatingAuthorizationManager

Autorization에는 많은 종류가 있다. 따라서 이를 가운데에서 중재하고 알맞은 AuthorizationManager로 연결시켜주는 것이 RequestMatcherDelegatingAuthorizationManager이다. RequestMatcherDelegatingAuthorizationManager는 AuthorizationManager의 구현체이다.

RequestMatcherDelegatingAuthorizationManager는 request에 match되는 AuthorizationManager를 받고, 그 Manager의 check 메서드를 실행시켜 그 반환값(AuthorizationDecision)을 반환한다.

@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()));
		}
	}
    
	return DENY;
}

Reference

https://velog.io/@on5949/SpringSecurity-Authorization-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90
https://tech-monster.tistory.com/217?category=1075581
https://jaeyoungb.tistory.com/214

profile
공부한 것들을 기록합니다.

0개의 댓글