diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java index 8ab87a8c4d..db02f19c18 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAdvisorProxyFactory.java @@ -171,6 +171,7 @@ public final class AuthorizationAdvisorProxyFactory for (Advisor advisor : this.advisors) { factory.addAdvisors(advisor); } + factory.setOpaque(true); factory.setProxyTargetClass(!Modifier.isFinal(target.getClass().getModifiers())); return factory.getProxy(); } @@ -357,6 +358,7 @@ public final class AuthorizationAdvisorProxyFactory ProxyFactory factory = new ProxyFactory(); factory.setTargetClass(targetClass); factory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass)); + factory.setOpaque(true); factory.setProxyTargetClass(!Modifier.isFinal(targetClass.getModifiers())); for (Advisor advisor : proxyFactory) { factory.addAdvisors(advisor); diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java index 15389c2ec2..9a7b88e8ae 100644 --- a/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java +++ b/core/src/test/java/org/springframework/security/authorization/AuthorizationAdvisorProxyFactoryTests.java @@ -34,6 +34,8 @@ import java.util.TreeSet; import java.util.function.Supplier; import java.util.stream.Stream; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; @@ -336,6 +338,18 @@ public class AuthorizationAdvisorProxyFactoryTests { assertThat(factory.proxy(35)).isEqualTo(35); } + @Test + public void serializeWhenAuthorizationProxyObjectThenOnlyIncludesProxiedProperties() + throws JsonProcessingException { + SecurityContextHolder.getContext().setAuthentication(this.admin); + AuthorizationAdvisorProxyFactory factory = AuthorizationAdvisorProxyFactory.withDefaults(); + User user = proxy(factory, this.alan); + ObjectMapper mapper = new ObjectMapper(); + String serialized = mapper.writeValueAsString(user); + Map properties = mapper.readValue(serialized, Map.class); + assertThat(properties).hasSize(3).containsKeys("id", "firstName", "lastName"); + } + private Authentication authenticated(String user, String... authorities) { return TestAuthentication.authenticated(TestAuthentication.withUsername(user).authorities(authorities).build()); } diff --git a/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc b/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc index 8eeddf5efc..99bd41adc1 100644 --- a/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc +++ b/docs/modules/ROOT/pages/servlet/authorization/method-security.adoc @@ -2227,37 +2227,6 @@ class UserController { ---- ====== -If you are using Jackson, though, this may result in a serialization error like the following: - -[source,bash] -==== -com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle -==== - -This is due to how Jackson works with CGLIB proxies. -To address this, add the following annotation to the top of the `User` class: - -[tabs] -====== -Java:: -+ -[source,java,role="primary"] ----- -@JsonSerialize(as = User.class) -public class User { - -} ----- - -Kotlin:: -+ -[source,kotlin,role="secondary"] ----- -@JsonSerialize(`as` = User::class) -class User ----- -====== - Finally, you will need to publish a <> to catch the `AccessDeniedException` thrown for each field, which you can do like so: [tabs]