Jax-RS - Custom attribute to get header value
authentication, java, jax-rs
Solution
"I think if I used a filter/web.xml it would apply to all calls"
Actually there are `@NameBinding` annotations we can use. For example
@NameBinding
@Rentention(RetentionPoilicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Authorize {}
Then just annotate the filter and the methods/classes you want filtered.
@Authorize
public Response getUser() {
// Do something
}
@Provider
@Authorize
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
MultivauledMap<String, String> headers - requestContext.getHeaders();
...
if (!authorized) {
throw new NotAuthorizedException();
}
}
}
Notice the use of `@Priority`. This is important. Say you want the authenticate also, so you create a filter for authentication. If you don't set the priority, either filter may occur first. It's unpredictable. If we provide the authentication filter with `@Priority(Priorities.AUTHENTICATION)`, then that filter will always occur before the `@Priority(Priorities.AUTHORIZATION)` filter.
You will also need to register this filter with the `Application` subclass (See some other Deployment Options (Jersey, but the Application subclass is portable with implementations))
@ApplicationPath("/api")
public class YourApplication extends Application {
private Set<Class<?>> classes = new HashSet<>();
private Set<Object> singletons = new HashSet<>();
public YourApplication() {
classes.add(AuthorizationRequestFilter.class);
}
@Override
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public Set<Object> singletons() {
return singletons;
}
}
- See more on Filters and Interceptors
- See the WebAppplicationException Hierarchy for more exceptions like NotAuthorizedException
- See the `Priorities` class and Priories guide
Problem
EDIT: I just realized, is it even possible to perform a custom action with a custom attribute in Java? Or is it just informational? I want to include an authentication token in my Jax-RS service header, but I don't want to add a parameter to every request to get the header and check it like so: ``` public Response getUser(@Context HttpHeaders headers) { if(authorize(headers.getRequestHeader("token").get(0)) { // Do something } } ``` I would much rather add an attribute to each request (or even the class if that is possible: ``` @Authorize public Response getUser() { // Do something } ``` This way I can also add the attribute to only the requests I want to. And if the request isn't authorized, I can override it and return a 401. A custom attribute is easy to write, but how can I get the header information in the attribute without passing it in every time? NOTE: I would rather not use a web.xml. I don't have one right now and I don't like using them. I want to keep my code clean without xml and I think if I used a filter/web.xml it would apply to all calls. If that is the only way, I will, but I much prefer the approach with custom attributes.