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 6dfd604
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,23 @@

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.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.MethodClassKey;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedMethod;
import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.RepeatableContainers;
Expand Down Expand Up @@ -103,11 +108,45 @@ final class UniqueSecurityAnnotationScanner<A extends Annotation> extends Abstra
this.types = types;
}

private A findMethodAnnotation(Class<A> annotationClass, Parameter p) {
Executable executable = p.getDeclaringExecutable();
if (executable instanceof Method method) {
AnnotatedMethod annotatedMethod = new AnnotatedMethod(method);
MethodParameter parameter = null;
MethodParameter[] methodParameters = annotatedMethod.getMethodParameters();
for (MethodParameter methodParameter : methodParameters) {
if (p == methodParameter.getParameter()) {
parameter = methodParameter;
break;
}
}
if (parameter == null) {
return null;
}
A annotation = parameter.getParameterAnnotation(annotationClass);
if (annotation != null) {
return annotation;
}
Annotation[] annotationsToSearch = parameter.getParameterAnnotations();
for (Annotation toSearch : annotationsToSearch) {
annotation = AnnotationUtils.findAnnotation(toSearch.annotationType(), annotationClass);
if (annotation != null) {
return annotation;
}
}
}
return null;
}

@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 = this.types.stream()
.map((c) -> findMethodAnnotation(c, p))
.filter(Objects::nonNull)
.map(MergedAnnotation::from)
.toList();
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 6dfd604

Please sign in to comment.