|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright 2002-2021 the original author or authors.
|
|
|
+ * Copyright 2002-2023 the original author or authors.
|
|
|
*
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -17,14 +17,18 @@
|
|
|
package org.springframework.security.authorization.method;
|
|
|
|
|
|
import java.lang.reflect.Method;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.function.Supplier;
|
|
|
|
|
|
import org.aopalliance.intercept.MethodInvocation;
|
|
|
|
|
|
import org.springframework.aop.support.AopUtils;
|
|
|
-import org.springframework.lang.NonNull;
|
|
|
+import org.springframework.core.MethodClassKey;
|
|
|
import org.springframework.security.access.annotation.Secured;
|
|
|
-import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
|
|
+import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
|
|
|
import org.springframework.security.authorization.AuthorizationDecision;
|
|
|
import org.springframework.security.authorization.AuthorizationManager;
|
|
|
import org.springframework.security.core.Authentication;
|
|
@@ -39,7 +43,9 @@ import org.springframework.security.core.Authentication;
|
|
|
*/
|
|
|
public final class SecuredAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
|
|
|
|
- private final SecuredAuthorizationManagerRegistry registry = new SecuredAuthorizationManagerRegistry();
|
|
|
+ private final AuthoritiesAuthorizationManager delegate = new AuthoritiesAuthorizationManager();
|
|
|
+
|
|
|
+ private final Map<MethodClassKey, Set<String>> cachedAuthorities = new ConcurrentHashMap<>();
|
|
|
|
|
|
/**
|
|
|
* Determine if an {@link Authentication} has access to a method by evaluating the
|
|
@@ -51,26 +57,28 @@ public final class SecuredAuthorizationManager implements AuthorizationManager<M
|
|
|
*/
|
|
|
@Override
|
|
|
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
|
|
|
- AuthorizationManager<MethodInvocation> delegate = this.registry.getManager(mi);
|
|
|
- return delegate.check(authentication, mi);
|
|
|
+ Set<String> authorities = getAuthorities(mi);
|
|
|
+ return authorities.isEmpty() ? null : this.delegate.check(authentication, authorities);
|
|
|
}
|
|
|
|
|
|
- private static final class SecuredAuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
|
|
|
-
|
|
|
- @NonNull
|
|
|
- @Override
|
|
|
- AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
|
|
|
- Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
|
|
- Secured secured = findSecuredAnnotation(specificMethod);
|
|
|
- return (secured != null) ? AuthorityAuthorizationManager.hasAnyAuthority(secured.value()) : NULL_MANAGER;
|
|
|
- }
|
|
|
+ private Set<String> getAuthorities(MethodInvocation methodInvocation) {
|
|
|
+ Method method = methodInvocation.getMethod();
|
|
|
+ Object target = methodInvocation.getThis();
|
|
|
+ Class<?> targetClass = (target != null) ? target.getClass() : null;
|
|
|
+ MethodClassKey cacheKey = new MethodClassKey(method, targetClass);
|
|
|
+ return this.cachedAuthorities.computeIfAbsent(cacheKey, (k) -> resolveAuthorities(method, targetClass));
|
|
|
+ }
|
|
|
|
|
|
- private Secured findSecuredAnnotation(Method method) {
|
|
|
- Secured secured = AuthorizationAnnotationUtils.findUniqueAnnotation(method, Secured.class);
|
|
|
- return (secured != null) ? secured
|
|
|
- : AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), Secured.class);
|
|
|
- }
|
|
|
+ private Set<String> resolveAuthorities(Method method, Class<?> targetClass) {
|
|
|
+ Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
|
|
+ Secured secured = findSecuredAnnotation(specificMethod);
|
|
|
+ return (secured != null) ? Set.of(secured.value()) : Collections.emptySet();
|
|
|
+ }
|
|
|
|
|
|
+ private Secured findSecuredAnnotation(Method method) {
|
|
|
+ Secured secured = AuthorizationAnnotationUtils.findUniqueAnnotation(method, Secured.class);
|
|
|
+ return (secured != null) ? secured
|
|
|
+ : AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), Secured.class);
|
|
|
}
|
|
|
|
|
|
}
|