Support customized `TargetVisitor` implement for authorization proxying
la3rence opened this issue · comments
Expected Behavior
When using @AuthorizeReturnObject
annotation to mask object fields, AuthorizationAdvisorProxyFactory
now working with some built-in TargetVisitor
implements like ClassVisitor
, ContainerTypeVisitor
. I want the AuthorizationAdvisorProxyFactory can provide some methods to register some TargetVisitors that user implements for some returned object that not in Java native types.
Current Behavior
Creating a proxyFactory by withDefaults()
method.
AuthorizationProxyFactory proxyFactory = AuthorizationAdvisorProxyFactory.withDefaults();
Foo foo = new Foo();
foo.bar(); // passes
Foo securedFoo = proxyFactory.proxy(foo);
securedFoo.bar(); // access denied!
withDefaults()
using these default TargetVistor
implements:
private static final TargetVisitor DEFAULT_VISITOR = isReactivePresent
? TargetVisitor.of(new ClassVisitor(), new ReactiveTypeVisitor(), new ContainerTypeVisitor())
: TargetVisitor.of(new ClassVisitor(), new ContainerTypeVisitor());
Context
For example, some ORM provide an Interface to do pagination, the DAO interface directly returning type with class like Page<T>
rather than List<T>
. This Page<T>
looks like:
@Data
public class Page<T> {
private long size;
private long offset;
private long total;
private List<T> records;
}
So if I want to apply @AuthorizeReturnObject
on methods like Page<T> method()
, that would not work. I tried to create an implement of TargetVisitor
for this type but there seems no where to add it into DEFAULT_VISITOR
.
This is what you need?
@Bean
Customizer<AuthorizationAdvisorProxyFactory> customizer() {
return factory -> factory.setTargetVisitor(AuthorizationAdvisorProxyFactory.TargetVisitor.of(new CustomeTargetVisitor(), AuthorizationAdvisorProxyFactory.TargetVisitor.defaults()));
}
record CustomeTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor {
@Override
public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) {
if (target instanceof Page<?> page) {
return proxyPage(proxyFactory, page);
}
return null;
}
@SuppressWarnings("unchecked")
private <T> Page<T> proxyPage(AuthorizationProxyFactory proxyFactory, Page<T> page) {
page.setRecords((List<T>) proxyFactory.proxy(page.getRecords()));
return page;
}
}
This is what you need?
@Bean Customizer<AuthorizationAdvisorProxyFactory> customizer() { return factory -> factory.setTargetVisitor(AuthorizationAdvisorProxyFactory.TargetVisitor.of(new CustomeTargetVisitor(), AuthorizationAdvisorProxyFactory.TargetVisitor.defaults())); } record CustomeTargetVisitor implements AuthorizationAdvisorProxyFactory.TargetVisitor { @Override public Object visit(AuthorizationAdvisorProxyFactory proxyFactory, Object target) { if (target instanceof Page<?> page) { return proxyPage(proxyFactory, page); } return null; } @SuppressWarnings("unchecked") private <T> Page<T> proxyPage(AuthorizationProxyFactory proxyFactory, Page<T> page) { page.setRecords((List<T>) proxyFactory.proxy(page.getRecords())); return page; } }
Yes, exactly! I didn't notice the method AuthorizationAdvisorProxyFactory.TargetVisitor.defaults()
is already available.
Thanks!