I created a Spring Boot 2.3 application. I securited my REST endpoint and my services.
I created some meta annotations because I have many role. For example:
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAnyRole('ROLE_CUSTOMER')")
public #interface IsCustomerUser {
}
and
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#PreAuthorize("hasAnyRole('ROLE_API')")
public #interface IsApiUser {
}
I've several of this meta annotations with many other roles. I thought I could add multiple meta annotations on my endpoints like this:
#IsCustomerUser
#IsApiUser
#GetMapping(path = "/tenants/current/avatar/{version}")
public ResponseEntity<?> getAvatar(#PathVariable("version") long version) {
//TODO some stuff
}
but it seems only one annotation is evalued. I see there is a feature request here. I'd like to know if you have some workaround in order to add multiple meta annotations.
It is very annoying be forced to create all permutations of my basic security annotation.
In fact I should create something like #IsAdminOrCustomerOrApiOrManagerOr.... and it's not really convenient.
Related
The idea is to create annotations hierarchy (similar to #Service, #Component etc) using #AliasFor annotation. This should give me the possibility to define aspect, that would execute on parent annotation, and every alias of it. But somehow it doesn't work for me.
#ComponentScan is fine, #EnableAspectJAutoProxy is set.
Example:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface ParentAnnotation {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#ParentAnnotation
public #interface ChildAnnotation {
#AliasFor(annotation = ParentAnnotation.class)
String value() default "";
}
#Aspect
#Component
public class EventRecorderAspect {
#Around("#annotation(com.example.ParentAnnotation)")
public void exampleMethod(ProceedingJoinPoint joinPoint) throws Throwable {
// This should be executed for both #ParentAnnotation and #ChildAnnotation
}
}
#RestController
public class ExampleController {
#ChildAnnotation // This should result in executing aspect for every implementation
String controllerMethod();
}
UPDATE:
I've updated code, as #M.Deinum suggested in a comment below. But it still doesnt work.
AspectJ pointcut matching syntax, a subset of which is used by Spring AOP, is ignorant of meta annotations, even though withing the Spring framework as such there is support for it in other places. I think the closest you can get to specifying meta annotations in your pointcut is to do it explicitly up to the nesting level you require. See this answer for examples showing the syntax variants for both
class-level, e.g. within(#(#com.example.ParentAnnotation *) *),
method-level, e.g. execution(#(#com.example.ParentAnnotation *) * *(..))
annotations.
Update: #Ariel Grabijas asked in a follow-up comment:
So is there a way to somehow inherit annotations from interface method to class method?
Not in Java and also not by means of Spring AOP. But there is a workaround using native AspectJ inter-type definitions (ITD).
I want to implement an Aspect so that Kafka read message from the latest offset.
I want to create and annotation like below:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
}
So if I use this annotation with any of the #KafkaListener method then this listener should read message from the latest one only.
I don't know how to write the AOP for this scenario.
How do you define an annotation in Spring that is semantically equivalent to #Bean, but has another name?
(Why? I'm building a DSL in which the functionality would fit, but it would greatly benefit from naming the annotation more closely to the role it plays in the library).
Well... It was as easy as:
#Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Bean
public #interface CustomAnnotation {
}
I have application with Angular 5 frontend and Spring 5 REST-backend. I need spring component, witch created one time for one token. If I been using non REST API I could use #Scope("session"). But now Session ID is different for each request.
I need that, because java.security.Principal in provides only username. But I need filtering my entities by customer ID.
I do not want to get customer from database while each request.
Create your own scope . Read spring doc to use a custom scope ,or go to Using custom scope . You will find plenty of examples,
Create a class TokenScope implementing Scope interface and use it as you use any other scope for a bean.
For a typical spring boot app
#Qualifier
#Scope("token")
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface TokenScoped {
}
and use it.
#Component
#TokenScoped
class SomeBean
I am trying to specify a pre-matching filter that is only associated to some of my API calls, by following what the RESTeasy documentation suggests. Here is what my code looks like:
Name binding:
#NameBinding
public #interface ValidateFoo {}
Resource:
#Path("/foo/bar")
#Produces(MediaType.APPLICATION_JSON)
public class FooBar {
#GET
#ValidateFoo
public Object doStuff() {
//do stuff
}
#POST
public Object doAnotherStuff() {
//do another stuff
}
}
Filter:
#ValidateFoo
#Provider
#PreMatching
public class FooValidation implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext reqContext) throws IOException {
//validate stuff
}
}
Problem is: the FooValidation filter runs before every method call (e.g.: before GETs and POSTs to /foo/bar), not only the ones annotated with #ValidateFoo (seems a bug to me). If I remove the #Provider annotation from the filter, it won't run before any call (as expected).
I am seeing this behavior consistently, either using WebLogic or Tomcat. My dependency management is done through Maven, and the RESTeasy version is 3.0-beta-3.
Anyone experiencing/experienced the same behavior? I have seen another user with a similar problem on JBoss forums, with no luck so far.
UPDATE:
Still experiencing the same issue with RESTeasy 3.0.1-Final.
I had similar problem. For me the solution was to add following annotation configuration (to #ValidateFoo):
#Target({ ElementType.TYPE, ElementType.METHOD })
#Retention(value = RetentionPolicy.RUNTIME)
#NameBinding