Programming/Spring
[Spring Security] 권한 부여 처리 흐름
Smile :DK
2023. 7. 17. 21:29
더보기
Authorization(인가, 권한 부여)
- 인증(Authentication) 과정이 정상적으로 수행된 사용자에게 하나 이상의 권한(Authority)을 부여하여 특정 애플리케이션의 특정 자원(Resource)에 접근할 수 있게 허가 하는 과정
- Authorization은 반드시 인증 과정 이후 수행되어야 하며 권한은 일반적으로 역할(Role)의 형태로 부여 된다.
Spring Security 권한 부여 처리 흐름
Spring Security 컴포넌트로 보는 권한 부여 처리 흐름
- AuthorizationFilter는 SecurityContextHolder로부터 Authentication을 획득한다.
- SecurityContextHolder로부터 획득한 Suppier<Authentication>과 HttpServletRequest를 AuthorizationManager에게 전달한다.
- AuthorizationManager의 구현체인 RequestMatcherDelegatingAuthorizationManager 내부에서 매치되는 AuthorizationManager 구현 클래스가 있다면 AuthorizationManager 구현 클래스가 사용자의 권한을 체크
- 적절한 권한 ⇒ 다음 요청 프로세스를 이어감
- 적절하지 않은 권한 ⇒ AccessDeniedException이 throw 되고 ExceptionTranslationFilter가 AccessDeniedException을 처리
- AuthorizationManager(인터페이스) / RequestMatcherDelegatingAuthorizationManager(구현체)
- RequestMatcherDelegatingAuthorizationManager는 RequestMatcher 평가식을 기반으로 해당 평가식에 매치되는 AuthorizationMagager에게 권한 부여 처리를 위임하는 역할
- RequestMatcherDelegatingAuthorizationManager가 직접 권한 부여 처리 하는 것이 아닌 RequestMatcher를 통해 매치되는 AuthorizationManager 구현 클래스에게 위임만 함
AuthorizationFilter
URL을 통해 사용자의 접근(Access)을 제한하는 권한 부여 필터이며 SpringSecurity 5.5 이전 버전의 FilterSecurityInterCeptor를 대체한다.
- AuthorizationFilter 객체가 생성될 때, AuthorizationManager를 의존성 주입(DI) 받는다.
- DI 받은 AuthorizationManager를 통해 권한 부여 처리를 진행
- DI받은 AuthorizationManager의 check() 메서드를 호출하여 적절한 권한 부여 여부를 체크한다.
- AuthorizationManager의 check() 메서드는 구현 클래스에 따라 권한 체크 로직이 다르다
- URI 기반으로 권한 부여 처리를 하는 AuthorizationFilter는 AuthorizationManager의 구현 클래스로 RequestMatcherDelegatingAuthorizationManager를 사용한다.
RequestMatcherDelegatingAuthorizationManager
- check() 메서드 내부에서 루프를 돌면서 RequestMatcherEntry 정보를 얻은 후 RequestMatcher 객체를 얻음
- Matcher.isMatch()가 true이면 AuthorizationManager 객체를 얻은 뒤 사용자의 권한을 체크
✔️ 여기서 RequestMatcher는 SecurityConfig에서 .antMatcher(”/orders/**).hasRole(”ADMIN”)와 같은 메서드 체인 정보를 기반으로 생성된다.
접근 제어 표현식
Spring Security 에서 웹 및 메서드 보안을 위해 표현식(Spring EL,Spring Expression Language)을 사용할 수 있다.
표현식 | 설명 |
hasRole(Stirng role) | - 현재 보안 주체(principal)가 지정된 역할을 갖고 있는지 여부를 확인하고 가지고 있다면 true를 리턴한다.- hasRole(’admin’)처럼 파라미터로 넘긴 role이 ROLE_ 로 시작하지 않으면 기본적으로 추가한다.(DefaultWebSecurityExpressionHandler의 defaultRolePrefix를 수정하면 커스텀할 수 있다.) |
hasAnyRole(String… roles) | - 현재 보안 주체가 지정한 역할 중 1개라도 가지고 있으면 true를 리턴한다.(문자열 리스트를 콤마로 구분해서 전달한다.)- ex) hasAnyRole(’admin’, ‘user’) |
hasAuthority(String authority) | - 현재 보안 주체가 지정한 권한을 갖고 있는지 여부를 확인하고 가지고 있다면 true를 리턴한다.- ex) hasAuthority(’read’) |
hasAnyAuthority(String… authorities) | - 현재 보안 주체가 지정한 권한 중 하나라도 있으면 true를 리턴한다.- ex) hasAnyAuthority(’read’, ‘write’) |
principal | - 현재 사용자를 나타내는 principal 객체에 직접 접근할 수 있다. |
authentication | - SecurityContext로 조회할 수 있는 현재 Authentication 객체에 직접 접근할 수 있다. |
permitAll | - 항상 true로 평가한다. |
denyAll | - 항상 false로 평가한다. |
isAnonymous() | - 현재 보안 주체가 익명 사용자면 true를 리턴한다. |
isRememberMe() | - 현재 보안 주체가 remember-me 사용자면 true를 리턴한다. |
isAuthenticated() | - 사용자가 익명이 아닌 경우 true를 리턴한다. |
isFullyAuthenticated() | - 사용자가 익명 사용자나 remember-me 사용자가 아니면 true를 리턴한다. |
hasPermission(Object target, Object permission) | - 사용자가 target에 해당 permission 권한이 있으면 true를 리턴한다.ex) hasPermission(domainObject, ‘read’) |
hasPermission(Object targetId, String targetType, Object permission) | - 사용자가 target에 해당 permission 권한이 있으면 true를 리턴한다.ex) hasPermission(1, ‘com.example.domain.Message’, ‘read’) |
Ref.