2 분 소요

개요

DB와 연동하여 자원 및 권한을 설정하고 제어함으로 동적 권한 관리가 가능하도록 한다.

설정 클래스 소스에서 권한 관련 코드 모두 제거 ex) antMatcher(“/user”).hasRole(“USER”)

관리자 시스템 구축

  • 회원 관리 - 권한 부여
  • 권한 관리 - 권한 생성, 삭제
  • 자원 관리 - 자원 생성, 삭제, 수정, 권한 매핑

권한 계층 구현

  • URL - Url 요청 시 인가처리
  • Method - 메소드 호출 시 인가 처리
    • Method
    • Pointcut

URL 방식 - 주요 아키텍쳐 이해

스프링 시큐리티의 인가처리 http.antmatchers(“/user”).access(“hasRole(‘USER’)”) → 사용자(인증정보)가 /user 자원(요청정보)에 접근하기 위해서는 ROLE_USER 권한(권한정보)이 필요하다

1

인증정보(Authentication)은 SecurityContext에서 얻는다. 요청정보는 FilterInvocation클래스를 생성해서 request 정보를 얻는다. 권한정보는 설정클래스에서 설정한 내용(ex: hasRole(‘USER’))을 파싱해서 얻어낸다. → 내부적으로 스프링 시큐리티가 초기화 될 때 설정했던 내용들(ex: http.antmatchers(“/user”).access(“hasRole(‘USER’)”)) 에서 자원정보와 권한정보를 꺼내어 Map객체에 key(자원정보), value(권한정보)를 저장

⇒ 사용자가 자원요청을 할 경우 보안필터(SecurityInterceptor)가 요청을 받은 뒤 인증, 요청, 권한 정보들을 얻어서 접근 결정 관리자(AccessDecisionManager)에게 전달

권한정보 파싱및 저장 로직

파싱된 결과들(List<Map>)이 저장되는 곳은 ExpressionBasedFilterInvocationSecurityMetadataSource 의 requestToExpressionAttributesMap이다.

부모객체(DefaultFilterInvocationSecurityMetadataSource)에 먼저 map객체를 전달해서 설정정보들을 가지고 있게 함 이로써 DefaultFilterInvocationSecurityMetadataSource 의 requestMap에 설정정보들을 담음

권한 추출 방법

1

getAttributes(Object object)를 override해서 실질적인 구현을 한다. Method방식의 권한 정보 추출은 이미 구현되있는 클래스를 활용하여 Annotation방식으로 인가처리 설정을 해주도록 한다.

  • @RolesAllowed, @Secured, @PreAuthorize, @PostAuthorize

1

URL 방식 - 관리자 시스템 구성

1 1

FilterInvocationSecurityMetadataSource

1 사용자가 접근하고자 하는 Url 자원에 대한 권한 정보 추출 AccessDecisionManager 에게 전달하여 인가처리 수행 DB로부터 자원 및 권한 정보를 매핑하여 맵으로 관리 사용자의 매 요청마다 요청정보에 매핑된 권한 정보 확인

1

  1. 사용자는 /admin 으로 접근
  2. 보안필터(FilterSecurityInterceptor)에서 권한정보 조회
  3. FilterInvocationSecurityMetadataSource에서 요청정보와 매칭되는 권한정보 추출
  • RequestMap 에서 요청정보(/admin) 이 key값인 data(권한 목록)를 찾는다. (DB조회)
  1. 권한 목록이 존재하지 않는다면 인가처리를 하지 않는다.
  2. 권한 목록이 존재한다면 AccessDecisionManager에 정보들(인증객체, 요청정보, 권한정보들)을 넘긴다.

1

http.addFilterAt(filterSecurityInterceptor(), FilterSecurityInterceptor.class)
@Bean
public FilterSecurityInterceptor filterSecurityInterceptor() {
    FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
    filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
    filterSecurityInterceptor.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource());
    filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
    return filterSecurityInterceptor;
}
@Bean
public FilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource() {
        return new UrlFilterInvocationSecurityMetadataSource();
}



1

UrlResourcesMapFactoryBean DB로 부터 얻은 권한/자원 정보를 ResourceMap을 빈으로 생성해서 UrlFilterInvocationSecurityMetadataSource에 전달

인가처리 실시간 반영하기

1

PermitAllFilter

1

인증 및 권한심사를 할 필요가 없는 자원(ex: /, /home, /login) 들을 미리 설정해서 바로 리소스 접근이 가능하게 하는 필터

http.addFilterBefore(permitAllFilter(), FilterSecurityInterceptor.class)
@Bean
public PermitAllFilter permitAllFilter () {
    String[] permitAllPattern = [/,/index,/home,/login,/errorpage/**];

    PermitAllFilter permitAllFilter = new PermitAllFilter (permitAllPattern);

    permitAllFilter.setAccessDecisionManager(accessDecisionManager);
    permitAllFilter.setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
    permitAllFilter.setRejectPublicInvocations(false);

    return commonFilterSecurityInterceptor;
}

계층 권한 적용 RoleHierachy

1

기존 의 ROLE을 보면 ADMIN 과 USER가 있지만 ADMIN은 USER의 상위 계층이 아니고 그냥 이름이 다른 하나의 ROLE일 뿐이다. 하지만 그렇게만 적용해서는 ROLE마다 권한을 하나하나 각각 줘야하는 문제가 있다. 그렇기에 계층을 적용해서 윗 계층은 아래계층의 권한을 포함하도록 해야 한다.

RoleHirearchy 상위 계층 Role은 하위 계층 Role의 자원에 접근 가능함. Role_ADMIN > ROLE_MANAGER > ROLE_USER 일 경우 ROLE_ADMIN 만 있으면 하위 ROLE의 권한을 모두 포함한다.

RoleHierarchyVoter RoleHierarchy 를 생성자로 받으며 이 클래스에서 설정한 규칙이 적용되어 심사함.

아이피 접속 제한하기

1

심의 기준

특정한 IP만 접근 가능하도록 심의하는 Voter 추가 Voter 중에서 가장 먼저 심사하도록 하여 허용된 IP일 경우에만 최종 승인 및 거부 결정을 하도록 한다. 허용된 IP이면 ACCESS_GRANTED 가 아닌 ACCESS_ABSTAIN 을 리턴해서 추가 심의를 계속 진행하도록 한다. 허용된 IP가 아니면 ACCESS_DENIED를 리턴하지 않고 즉시 예외 발생하여 최종 자원 접근 거부