I want to validate a user making a request. For that I have two filters: AuthenticationFilter and AuthorizationFilter. AuthenticationFilter extracts a token from the request and finds the user from the database. AuthorizationFilter checks if that user (retrieved by the previous filter) has the necessary permissions. I have two possible solutions and would like to know the pros and cons of each one and which should I use. I would also need to access the user in the actual business logic. My code is as follows:
AuthenticationFilter:
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
// option 1.1
@Inject
@AuthenticatedUser
private Event<User> authenticatedUserEvent;
// option 1.2
@Inject
@AuthenticatedUser
private User authenticatedUser;
public void filter(ContainerRequestContext requestContext) throws IOException {
String token = getToken(requestContext);
User user = getUser(token)
if (user == null) {
requestContext.abortWith(...);
} else {
// option 1.1
authenticatedUserEvent.fire(User);
// option 1.2
authenticatedUser.setData(user);
// option 2
requestContext.setProperty("authenticatedUser", user);
}
}
}
AuthorizationFilter:
@Secured
@Provider
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
// option 1
@Inject
@AuthenticatedUser
private User authenticatedUser;
public void filter(ContainerRequestContext requestContext) throws IOException {
// option 2
User authenticatedUser = (User) requestContext.getProperty("authenticatedUser")
boolean allowed = verifyRoles(user, resourceInfo.getResourceClass(), resourceInfo.getResourceMethod());
if (!allowed) {
requestContext.abortWith(...);
}
}
}
AuthenticatedUserProducer (only for option 1):
@RequestScoped
public class AuthenticatedUserProducer {
@Produces
@RequestScoped
@AuthenticatedUser
private User authenticatedUser;
public void handleAuthenticationEvent(@Observes @AuthenticatedUser User user) {
this.authenticatedUser = user
}
}
For option 1, is it necessary to annotate the filters with @RequestScoped
? By default filters are application scoped, so is the injection safe? I.e., the event fired by filter 1 in request chain 1 will not end up injected in filter 2 of chain 2, if more than one request is being processed at the same time? And the same when injecting the user in the resource class where the actual business logic runs?
For option 2, I no longer have access to ContainerRequestContext
, but I can access the object by injecting the HttpServletRequest
. But this option seems to me "less clean" because I have to cast the stored objects to User before using them, when with the injection approach I can use the objects directly.
I already checked these questions, what I'm looking for is to determine which option is the best:
- How to Pass Object from ContainerRequestFilter to Resource
- Pass data from ContainerRequestFilter to Resource
- Jax-RS Filter pass object to resource
- What scope do JAX-RS 2 filters have?
- Get resource class annotation values inside ContainerRequestFilter
I'm currently using WildFly 11, with its default implementation of JAX-RS (Resteasy) and CDI (Weld).