Skip to content

Commit

Permalink
Support @AuthenticationPrincipal on interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
kse-music committed Dec 2, 2024
1 parent ea53a49 commit 68dc359
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
Expand All @@ -29,6 +31,7 @@
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.MethodClassKey;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
Expand Down Expand Up @@ -103,11 +106,75 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
this.types = types;
}

private List<MergedAnnotation<A>> findParameterOnInterface(Method method, Class<?> superOrIfc, Parameter current) {
List<MergedAnnotation<A>> directAnnotations = Collections.emptyList();
for (Method candidate : superOrIfc.getMethods()) {
if (isOverrideFor(method, candidate)) {
for (Parameter parameter : candidate.getParameters()) {
if (parameter.getName().equals(current.getName())) {
directAnnotations = findDirectAnnotations(parameter);
if (!directAnnotations.isEmpty()) {
return directAnnotations;
}
}
}
}
}
return directAnnotations;
}

private List<MergedAnnotation<A>> findParameterAnnotations(Parameter current) {
List<MergedAnnotation<A>> directAnnotations = findDirectAnnotations(current);
if (directAnnotations.isEmpty()) {
Executable executable = current.getDeclaringExecutable();
if (executable instanceof Method method) {
Class<?> clazz = method.getDeclaringClass();
while (clazz != null) {
for (Class<?> ifc : clazz.getInterfaces()) {
directAnnotations = findParameterOnInterface(method, ifc, current);
if (!directAnnotations.isEmpty()) {
return directAnnotations;
}
}
clazz = clazz.getSuperclass();
if (clazz == Object.class) {
clazz = null;
}
if (clazz != null) {
directAnnotations = findParameterOnInterface(method, clazz, current);
if (!directAnnotations.isEmpty()) {
return directAnnotations;
}
}
}
}
}
return directAnnotations;
}

private boolean isOverrideFor(Method method, Method candidate) {
if (!candidate.getName().equals(method.getName())
|| candidate.getParameterCount() != method.getParameterCount()) {
return false;
}
Class<?>[] paramTypes = method.getParameterTypes();
if (Arrays.equals(candidate.getParameterTypes(), paramTypes)) {
return true;
}
for (int i = 0; i < paramTypes.length; i++) {
if (paramTypes[i] != ResolvableType.forMethodParameter(candidate, i, method.getDeclaringClass())
.resolve()) {
return false;
}
}
return true;
}

@Override
MergedAnnotation<A> merge(AnnotatedElement element, Class<?> targetClass) {
if (element instanceof Parameter parameter) {
return this.uniqueParameterAnnotationCache.computeIfAbsent(parameter, (p) -> {
List<MergedAnnotation<A>> annotations = findDirectAnnotations(p);
List<MergedAnnotation<A>> annotations = findParameterAnnotations(p);
return requireUnique(p, annotations);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ public void resolveArgumentCustomMetaAnnotationTpl() throws Exception {
.isEqualTo(this.expectedPrincipal);
}

@Test
public void resolveArgumentAnnotationFromInterface() {
CustomUserPrincipal principal = new CustomUserPrincipal();
setAuthenticationPrincipal(principal);
assertThat(this.resolver.supportsParameter(getMethodParameter("getUserByInterface", CustomUserPrincipal.class)))
.isTrue();
}

private MethodParameter showUserNoAnnotation() {
return getMethodParameter("showUserNoAnnotation", String.class);
}
Expand Down Expand Up @@ -312,7 +320,18 @@ private void setAuthenticationPrincipal(Object principal) {

}

public static class TestController {
interface UserApi {

String getUserByInterface(@AuthenticationPrincipal CustomUserPrincipal user);

}

public static class TestController implements UserApi {

@Override
public String getUserByInterface(CustomUserPrincipal user) {
return "";
}

public void showUserNoAnnotation(String user) {
}
Expand Down

0 comments on commit 68dc359

Please sign in to comment.