I want to implement开发者_开发百科 custom authorisation in my REST services using Jersey. This custom authorisation inspects annotations on methods as well as the actual parameters that a method receives.
My jax-rs annotated method looks like:
@GET
@Path("customers")
@Requires(Role.CustomerManager)
public Customer getCustomer(@ParseFromQueryString @CheckPermission final Customer customer) {
// ...
}
The @ParseFromQueryString
is an annotation that indicates Jersey (through an Injectable provider) to unmarshall a Customer
from a query string. The code for that looks like:
public class QueryStringCustomerInjectable implements Injectable<Customer> {
public Customer getValue() {
final Customer customer = new Customer();
// ... a UriInfo was injected using the @Context annotation
// ... extract parameters from QueryString and use setters
return customer;
}
}
The @CheckPermission
annotation indicates my custom authoriser that permissions are to be checked on a customer. Some users have access to information on some customers. Similarly, the @Requires
annotation takes a role that the invoker should have. These are not java's security roles (Strings), rather, they are enum values.
Using Jersey's ResourceDebuggingFilter
as a starting point, I have been able to get to the point of knowing which method will be invoked. However, I still haven't figured out how to determine which parameters will actually be used to invoke the method.
At the top of my head, I can think of two work arounds:
- A Method interceptor using Guice + Jersey.
- Code this logic in the
QueryStringCustomerInjectable
, but this seems a bit sloppy. It would be a class doing too much.
Yet, I would really like to do this using only Jersey / JAX-RS. I feel that I am so close!
Ideas? Pointers?
Thanks!
You should use Filters
or Interceptors
to handle all the information about method.
see Jersey Filter and Interceptors
For the Customer deserialization you could implement the javax.ws.rs.ext.ParamConverterProvider and register it into Jersey. Then you can inject it into your methods with @QueryParam("customer"). It's a bit more flexible since you can use it also with @BeanParam or @PathParam annotations.
Then you can use the ContainerRequestFilter. See as a reference how jersey does the Oauth1 for example OAuth1ServerFilter. The next thing you can do is to create maybe a feature which will register the newly created filter (see Oauth1ServerFeature for a reference - I couldn't find the source code right now).
Good luck!
Why not using your own Servlet filter e.g.
public class YourFilter implements Filter {
...
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// ..... httpReq.getUserPrincipal();
// then set what you need using ThreadLocal and use it inside your resource class
// do not forget to call
filterChain.doFilter(request, response); // at the end of this method
}
The last step is to register your servlet filter. This is done using web app's web.xml
It will intercept your HTTP requests before the actual code inside jersey resource is called.
精彩评论