How to bypass path in servlet filter with Jersey security annotations in Java

前端 未结 1 917
执笔经年
执笔经年 2021-01-07 09:56

I have implemented REST service using Jersey. To give more security, I have added jersey security annotation into REST method(@PermitAll, @DenyAll)

相关标签:
1条回答
  • 2021-01-07 10:06

    Since you are performing authentication and/or authorization, instead of servlet filters I would recommend using name binding filters, so you can easily bind them to the resources you need.

    To bind filters to your REST endpoints, JAX-RS provides the meta-annotation @NameBinding and can be used as following:

    @NameBinding
    @Retention(RUNTIME)
    @Target({TYPE, METHOD})
    public @interface Secured { }
    

    The @Secured annotation will be used to decorate a filter class, which implements ContainerRequestFilter, allowing you to handle the request.

    The ContainerRequestContext helps you to extract information from the HTTP request (for more details, have a look at the ContainerRequestContext API):

    @Secured
    @Provider
    @Priority(Priorities.AUTHENTICATION)
    public class SecurityFilter implements ContainerRequestFilter {
    
        @Override
        public void filter(ContainerRequestContext requestContext) throws IOException {
            // Use the ContainerRequestContext to extract information from the HTTP request
            // Information such as the URI, headers and HTTP entity are available
        }
    }
    

    The ContainerRequestFilter#filter() method is a good place to abort the request if the user is not authenticated/authorized. To do it, you can use ContainerRequestContext#abortWith() or throw an exception.

    The @Provider annotation marks an implementation of an extension interface that should be discoverable by JAX-RS runtime during a provider scanning phase.

    To bind the filter to your endpoints methods or classes, annotate them with the @Secured annotation created above. For the methods and/or classes which are annotated, the filter will be executed.

    @Path("/")
    public class MyEndpoint {
    
        @GET
        @Path("{id}")
        @Produces("application/json")
        public Response myUnsecuredMethod(@PathParam("id") Long id) {
            // This method is not annotated with @Secured
            // The security filter won't be executed before invoking this method
            ...
        }
    
        @DELETE
        @Secured
        @Path("{id}")
        @Produces("application/json")
        public Response mySecuredMethod(@PathParam("id") Long id) {
            // This method is annotated with @Secured
            // The security filter will be executed before invoking this method
            ...
        }
    }
    

    In the example above, the security filter will be executed only for mySecuredMethod(Long) because it's annotated with @Secured.

    You can have as many filters as you need for your REST endpoints. To ensure the execution order of the filters, annotate them with @Priority.

    It's highly recommended to use one of the values defined in the Priorities class (the following order will be used):

    • AUTHENTICATION
    • AUTHORIZATION
    • ENTITY_CODER
    • HEADER_DECORATOR
    • USER

    If your filter is not annotated with @Priority, the filter will be executed with the USER priority.

    You can combine this approach with Jersey security mechanism.

    Additionally, you can inject ResourceInfo in your ContainerRequestFilter:

        @Context
        private ResourceInfo resourceInfo;
    

    It can be used to get Method and Class which match with the requested URL:

        Class<?> resourceClass = resourceInfo.getResourceClass();
        Method resourceMethod = resourceInfo.getResourceMethod();
    

    And extract the annotations from them:

        Annotation[] annotations = resourceClass.getDeclaredAnnotations();
        PermitAll annotation = resourceMethod.getAnnotation(PermitAll.class);
    
    0 讨论(0)
提交回复
热议问题