프로젝트에서 커스텀이 가능한 권한부여 기능 요구사항이 들어왔다.
기존 spring security에 의존해서 ROLE 기반으로 관리를 하기에는 제약사항이 많았고 유연하지 못하다라는 생각이 들었다.
그래서 우리는 각 도메인별로 C/R/U/D 각각 접근을 할 수 있는 정책을 만들었고 이 정책들을 모은 집합 권한을 만들어서 유저한테 부여하는 방식으로(AWS를 참고했다) 구성하였다.
수많은 정책들을 전부 관리하고 각 컨트롤러마다 권한을 확인하는일을 하나씩 만드는건 힘들다고 생각해 AOP와 커스텀 어노테이션을 적용해서 구현하기로 하였다.
기본 구성
스프링의 어노테이션을 많이 참고해서 구성을 하였다.
특히 @RequestMapping을 보며 우리도 상위 어노테이션 하나 만들고 정책을 넣고 하위 어노테이션으로 관리하면 되겠다라고 생각해
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface BemsPermission {
PolicyType[] policyType() default {};
}
@BemsPermission(
policyType = {PolicyType.CONTROL_POINT_CREATE}
)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ControlPointCreate {
}
@ControlPointCreate
@PostMapping
public ResponseEntity<List<ControlPointCreateResponse>> createControlPoint(@RequestParam Long buildingId,
@RequestBody @Valid List<ControlPointRequest> controlPointRequests) {
return new ResponseEntity<>(
controlPointApplicationService.createControlPoints(buildingId, controlPointRequests), HttpStatus.CREATED);
}
이렇게 구성 한 후 컨트롤러가 호출될 때 aop가 먼저 어노테이션에 있는 PolicyType와 유저가 가지고 있는 PolicyType을 비교해서 권한 체크를 한다.
어노테이션의 상속?
기본적으로 어노테이션은 상속이라는 개념이 없다.
하지만 나는 Spring의 @RequestMapping의 @GetMapping을 보며 GetMapping을 하면 RequestMapping(method = RequestMethod.GET)을 한것과 똑같이 동작하니까 상위의 어노테이션을 부를 수 있구나 라고 생각 했다.
@After
public void checkPermission(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// BemsPermission 어노테이션을 메소드에서 가져오기
BemsPermission permission = method.getAnnotation(BemsPermission.class);
}
분명히 @ControlPointCreate는 @BemsPermission을 가지고 있는데 permission이 null이 나오고 있었다.
메타 어노테이션
메타 애노테이션이란 애노테이션 위에 붙은 애노테이션이라는 뜻이다. 보통 애노테이션은 클래스나 메소드 앞에 붙지만, 애노테이션 위에도 애노테이션을 또 붙일 수 있다. 이때 애노테이션 위에 붙어있는 애노테이션을 메타 애노테이션이라 한다.
상속관계가 없는 어노테이션에서 상위(?) 어노테이션 즉 메타 어노테이션을 가져오려면 AnnotationUtils 클래스 또는 AnnotatedElementUtils 클래스를 사용하면 된다
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
BemsPermission permission = AnnotationUtils.findAnnotation(method, BemsPermission.class);
if (permission != null) {
PolicyType[] policyTypes = permission.policyType();
for (PolicyType policyType : policyTypes) {
log.info("Executed method with policy type: {}", policyType);
}
}
그래서 이렇게 메타 어노테이션을 찾아서 권한을 가져와서 권한 체크를 진행하고 있다.
참고
'트러블슈팅' 카테고리의 다른 글
Spring Batch processor 이야기 (0) | 2024.10.15 |
---|---|
연관관계 매핑 (0) | 2024.10.15 |
관제값 조회 디자인 패턴 적용 (1) | 2024.10.13 |
그래프 조회 속도 개선 (1) | 2024.10.13 |
배치 리팩터링 (3) | 2024.10.10 |