본문 바로가기
Spring/Spring Security

SpringSecurity 인가 아키텍쳐 - 요청 기반 인가 관리자

by 롱싱싱 2024. 11. 9.

요청 기반 인가 관리자 AuthorityAuthorizationManager

  • 스프링 시큐리티는 요청 기반 인증된 사용자 및 특정 권한을 가진 사용자의 자원 잡근 허용 여부를 결정하는 인가 관리자 클래스를 제공한다
  • AuthorityAuthorizationManager, AuthenticatedAutorizationManager, RequestMatcherDelegatingAuthorizationManager(대리자)

내부 구조

  1. client의 요청
  2. AuthenticationFilter는 SecurityContextHolder에 인증 객체를 담아서 요청 정보와 인증 정보를 관리자에게 전달
    1.  - request, Authentication(GrantedAuthority)
  3. RequestMatcherDelegatingAuthorizationManager
    • 요청패턴을 기준으로 적절한 인가 관리자 호출
    •  AuthenticatedAuthorizationManager
      • any request
    • AuthorityAuthorizationManager
      •  .requestMatchers("/user").hasAuthority("USER")
      • .requestMatchers("/admin").hasRole("ADMIN")
    •  WebExpressionAuthorizationManager
      • .requestMatchers("/db").access(new WebExpressionAuthorizationManager("hasRole('Admin')))
  4. -> 요청 자원에 대한 승인 혹인 거부 결과를 AuthorizationDecision에 반환
  5. AuthorizationDecision
    • - 인가되었나?
    • Y : Spring MVC
    • N : AccessDeniedException

 

AuthenticatedAuthorizationManager - 인증 상태 확인

FullyAuthenticatedAuthorizationStrategy - 익명 인증 및 기억하기 인증 아닌지 검사(ID, PASSWORD 입력해서 인증 받았을 떄)

RememberMeAuthorizationStrategy - 기억하기 인증인지 검사

AuthenticatedAuthorizationStrategy - 인증된 사용자인지 검사

AnonymousAuthorizationStrategy - 익명 사용자인지 검사

 

AuthorityAuthorizationManager - 특정 권한 확인, 허용, 거부

내부적으로 AuthoritesAuthorizationManager를 사용하여 권한 여부를 위임

매핑된 요청 패턴과 권한 정보를 사용하여 사용자 정보와 Authentication권한을 비교, 일치하는지 검사

ex) hasAuthority, hasRole, hasAnyRole, hasAnyAuthority

 


CustomAuthenticationManager 구현하기

 

사용자의 요청에 대한 권한 검사를 access()에 지정한 AuthorizationManager가 처리

public class CustomAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
    private static final String REQUIRED_ROLE = "ROLE_SECURE";
    @Override
    public void verify(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
        AuthorizationManager.super.verify(authentication, object);
    }

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
        Authentication auth = authentication.get();

        //auth 객체가 없음, 인증 안됨, anonymous일 때
        if(auth==null || !auth.isAuthenticated() || auth instanceof AnonymousAuthenticationToken){
            return new AuthorizationDecision(false);
        }
        boolean hasRequiredRole = auth.getAuthorities().stream().anyMatch(grantedAuthority -> REQUIRED_ROLE.equals(grantedAuthority.getAuthority()));
        
        return new AuthorizationDecision(hasRequiredRole);

    }

 

        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api").access(new CustomAuthorizationManager())
                        .anyRequest().authenticated())

                .formLogin(Customizer.withDefaults())
                .csrf(AbstractHttpConfigurer::disable)

                ;