AuthorizationAspect.java

package sprout.security.authorization.aop;

import sprout.aop.JoinPoint;
import sprout.aop.annotation.Aspect;
import sprout.aop.annotation.Before;
import sprout.security.authorization.annotation.PreAuthorize;
import sprout.security.context.SecurityContextHolder;
import sprout.security.core.Authentication;
import sprout.security.core.GrantedAuthority;

import java.lang.reflect.Method;
import java.nio.file.AccessDeniedException;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;

@Aspect
public class AuthorizationAspect {

    @Before(annotation = PreAuthorize.class)
    public void preAuthorize(JoinPoint joinPoint) throws AccessDeniedException {
        Method method = joinPoint.getMethod();
        PreAuthorize annotation = method.getAnnotation(PreAuthorize.class);

        if (annotation == null) {
            return;
        }

        Collection<? extends GrantedAuthority> authorities = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                .map(Authentication::getAuthorities)
                .orElse(Collections.emptyList());

        String requiredAuthority = annotation.value();

        if (!requiredAuthority.isBlank()) { // value가 비어있지 않은 경우에만 검사
            boolean hasRequiredAuthority = authorities.stream()
                    .anyMatch(a -> a.getAuthority().equals(requiredAuthority));

            if (!hasRequiredAuthority) {
                throw new AccessDeniedException("Access Denied: User '" +
                        Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                                .map(Authentication::getPrincipal)
                                .map(Object::toString)
                                .orElse("anonymous") +
                        "' does not have required authority '" + requiredAuthority + "' for method " + method.getName());
            }
        } else {
            System.err.println("[WARN] @PreAuthorize annotation on method " + method.getName() + " has no value defined. Access will be granted by default.");
        }
    }
}