스프링 시큐리티는 SpEL 표현식을 사용한다. 표현식 평가는 root object를 사용하여 평가된다. 스프링 시큐리티는 특정 클래스를 루트 객체로 사용하여 기본 제공 표현식을 제공하고 현재와 같은 엑세스 규칙을 제공한다.
SecurityExpressionRoot
가 바로 표현식 루트 객체이다.
Expression | Description |
---|---|
hasRole(String role) | 현재 principal이 지정된 role을 가지고 있으면 true를 반환한다. |
hasAnyRole(String… roles) | 현재 principal이 제공된 역할 중 하나라도 가지고 있으면 true를 반환한다. |
hasAuthority(String authority) | 현재 principal이 지정된 authority를 가지고 있으면 true를 반환한다. |
hasAnyAuthority(String… authorities) | 현재 principal이 제공된 authority들을 가지고 있으면 true를 반환한다. |
principal | 현재 사용자를 나타내는 principal 객체에 접근할 수 있다. |
authentication | SecurityContext에서 가져온 Authentication 객체에 직접 엑세스할 수 있다. |
permitAll | 항상 true를 반환 |
denyAll | 항상 false를 반환 |
isAnonymous() | 현재 사용자가 익명 사용자면 true를 반환한다. |
isRememberMe() | 현재 사용자가 remember-me 사용자면 true를 반환한다. |
isAuthenticated() | 현재 사용자가 익명도이 아니면 true를 반환한다. |
isFullyAuthenticated() | 현재 사용자가 익명도, rememer-me도 아니면 true를 반환한다. |
hasPermission(Object target, Object permission) | 사용자가 주어진 권한에 대해 제공된 대상에 접근할 수 있으면 true를 반환한다. ex) hasPermission(domainObject, ‘read’) |
hasPermission(Object targetId, String targetType, Object permission) | 사용자가 주어진 권한에 대해 제공된 대상에 접근할 수 있으면 true를 반환한다. ex) hasPermission(1, ‘com.example.domain.Message’, ‘read’). |
public class WebSecurity {
public boolean check(Authentication authentication, HttpServletRequest request) {
...
}
}
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/**").access(new WebExpressionAuthorizationManager("@webSecurity.check(authentication,request)"))
...
)
public class WebSecurity {
public boolean checkUserId(Authentication authentication, int id) {
...
}
}
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
...
);
@PreAuthorize
@PreFilter
@PostAuthorize
@PostFilter
global-method-security
를 설정해야 한다.<global-method-security pre-post-annotations="enabled"/>
가장 많이 사용되는 어노테이션은 @PreAuthorize
으로 메서드가 호출될 수 있는지 없는지를 결정한다.
@PreAuthorize("hasRole('USER')")
public void create(Contact contact);
ROLE_USER
에게만 위 메서드를 허용한다.아래 예제는 현재 사용자가 contant
에 admin
권한을 가지고 있는지 검사한다.
@PreAuthorize("hasPermission(#contact, 'admin')")
public void deletePermission(Contact contact, Sid recipient, Permission permission);
hasPermission()
표현식은 Spring Security ACL 모듈에 연결된다.Spring Security는 여러 방법으로 메서드 argument를 확인할 수 있다.
DefaultSecurityParameterNameDiscover
를 이용@P
나 @Param
어노테이션을 통해 아래와 같이 사용할 수도 있다. import org.springframework.security.access.method.P;
@PreAuthorize("#c.name == authentication.name")
public void doSomething(@P("c") Contact contact);
import org.springframework.data.repository.query.Param;
@PreAuthorize("#n == authentication.name")
Contact findContactByName(@Param("n") String name);
authentication
이 등장하는데 이는 Security Context 내부의 Authentication
이다.UserDetails
에도 principal
표현식으로 접근할 수 있다.@PostFilter
어노테이션을 사용하면 반환된 컬렉션 또는 맵을 반복하여 표현식이 거짓인 요소를 모두 제거한다.
@PreAuthorize("hasRole('USER')")
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")
public List<Contact> getAll();
filterObject
는 현재 컬렉션의 객체를 참조한다.Map
이 반환 값인 경우 filterObject.key
또는 filterObject.value
를 사용할 수 있다.hasPermission()
표현식은 자세히 살펴볼 필요가 있다.인터페이스에는 두 메서드가 있다.
boolean hasPermission(Authentication authentication, Object targetDomainObject,
Object permission);
boolean hasPermission(Authentication authentication, Serializable targetId,
String targetType, Object permission);
Authentication
이 제공되지 않을 때를 제외하고 사용 가능한 표현식에 직접 매핑된다.hasPermission()
표현식을 사용하려면 애플리케이션 컨텍스트에서 PermissionEvaluator
를 명시적으로 구성해야 한다.