[spring security] enum으로 @Secured 권한 관리하기
Spring Security Annotations
spring security는 @Secured나 @PreAuthorize 같은 어노테이션을 사용하여 메소드에 권한을 줄 수 있다. Secured 어노테이션은 @Secured("ROLE_USER") 와 같이 권한 이름을 파라미터로 사용하는데, 이 권한 이름들을 Enum에 정의하고, 사용해보자.
아래와 같은 권한용 Enum이 있다.
import org.springframework.security.core.GrantedAuthority;
public enum MyAuthority implements GrantedAuthority{
USER("ROLE_USER", "유저권한"),
ADMIN("ROLE_ADMIN", "어드민권한");
private String authority;
private String description;
private MyAuthority(String authority, String description){
this.authority = authority;
this.description = description;
}
@Override
public String getAuthority() {
return authority;
}
public String getDescription() {
return description;
}
}
그리고 나서 @Secured에서 아래와 같이 사용해보자.
@Secured(MyAuthority.USER.getAuthority())
@Secured안에는 String이 들어가고, getAuthority()는 String을 리턴하는데, "The value for annotation attribute Secured.value must be a constant expression" 라는 컴파일 에러가 났다. 어노테이션안에 Enum을 사용한 적은 많은 것 같은데, 왜 에러일까?
Enum 타입 사용이 가능했던 어노테이션들은 실제로 Enum을 받도록 만들어진 어노테이션이였다. @RequestMapping의 method를 예로들면, 타입이 String이 아닌 RequestMethod 라는 Enum을 받도록 되어있다. 만약 @Secured에서 Enum을 사용하려 했다면, String이 아닌 Enum을 받도록 설계되어 있어야 한다.
그렇다면 방법은 전혀 없는 것일까? 차선책으로는 static 레벨에 final로 권한을 선언하는 것이다. Enum 안에 ROLE_USER와 같은 권한들은 객체안에 생성되서 컴파일러가 가변적이라고 판단하는 것 같다. 그래서 코드를 아래와 같이 바꾸었다.
import org.springframework.security.core.GrantedAuthority;
public enum MyAuthority implements GrantedAuthority{
USER(ROLES.USER, "유저권한"),
ADMIN(ROLES.ADMIN, "어드민권한");
public static class ROLES{
public static final String USER = "ROLE_USER";
public static final String ADMIN = "ROLE_ADMIN";
}
private String authority;
private String description;
private MyAuthority(String authority, String description){
this.authority = authority;
this.description = description;
}
@Override
public String getAuthority() {
return authority;
}
public String getDescription() {
return description;
}
}
@Secured를 사용하는 부분은 아래와 같이 바꾸면 잘 된다.
@Secured(MyAuthority.ROLES.USER)
기존의 목표였던 권한을 Enum에서 관리하면서, Secured 어노테이션에서도 그 권한을 참조 할 수 있게 되었다. String을 파라미터로 받는 어노테이션에 변수를 전달하고 싶을 때는 final로 선언되어 있어야 한다.