Remove Advised Methods from Authorization Proxy Objects
Closes gh-15561
This commit is contained in:
		
							parent
							
								
									ecf6cace82
								
							
						
					
					
						commit
						fd05c5ad76
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<String, Object> 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());
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <<custom_advice, custom interceptor>> to catch the `AccessDeniedException` thrown for each field, which you can do like so:
 | 
			
		||||
 | 
			
		||||
[tabs]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue