Authentication/authorization in JAX-RS using interceptors and injection

后端 未结 2 1745
忘了有多久
忘了有多久 2020-12-16 05:48

I am developing a new application in JavaEE 7 using WildFly 8. I am using JAX-RS to provide a RESTful service interface for remote applications.

Something like an

相关标签:
2条回答
  • 2020-12-16 05:52

    While lefloh's answer is definitely correct I'd like to elaborate on his 2nd approach which I find most convenient.

    You're to create Interceptor(Filter) which implements ContainerRequestFilter.

    import org.apache.commons.lang.StringUtils;
    import org.jboss.resteasy.spi.ResteasyProviderFactory;
    
    import javax.ws.rs.container.ContainerRequestContext;
    import javax.ws.rs.container.ContainerRequestFilter;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.ext.Provider;
    import java.io.IOException;
    
    @Provider
    public class UserProvider implements ContainerRequestFilter {
    
        @Override
        public void filter(ContainerRequestContext containerRequestContext) throws IOException {
            String userId = containerRequestContext.getHeaders().getFirst("User-Id");
            if (StringUtils.isEmpty(userId)) {
                Response response = Response
                        .status(Response.Status.BAD_REQUEST)
                        .type(MediaType.TEXT_PLAIN_TYPE)
                        .entity("User-Id header is missing.")
                        .build();
                containerRequestContext.abortWith(response);
                return;
            }
    
            //do your logic to obtain the User object by userId
    
            ResteasyProviderFactory.pushContext(User.class, user);
        }
    }
    

    You'd need to register it either by autodiscovering set up in web.xml

    <context-param>
        <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>
    </context-param>
    

    or in your app boot

    ResteasyProviderFactory.getInstance().registerProvider(UserProvider.class);
    

    Since all the logic behind fetching the user is in the UserProvider you can for example use it like this

    @Path("/orders")
    @GET
    public List<Order> getOrders(@Context User user) {
        return user.getOrders();
    }
    
    0 讨论(0)
  • 2020-12-16 06:04

    In my eyes this approach is valid as long as you don't try to build something like a session with this User Object.

    As answered here you could use @Context and @Provider but that's not exactly what you want. Directly injecting a Class per @Context is possible with the Resteasy Dispatcher. But here you must register the Object which should be injected. I don't think that makes sense for request-scoped parameters. What you could do is inject a provider like this:

    // Constructor of your JAX-RS Application
    public RestApplication(@Context Dispatcher dispatcher) {
        dispatcher.getDefaultContextObjects().put(UserProvider.class, new UserProvider());
    }
    
    // a resource
    public Response getById(@Context UserProvider userProvider) {
        User user = userProvider.get();
    }
    

    Other ways to solve your problem:

    1. Register a WebFilter, authenticate the user, wrap the ServletRequest and override getUserPrincipal. You can then access the UserPrincipal from a injected HttpServletRequest.
    2. Implement a JAX-RS Interceptor which implements ContainerRequestFilter. Use ContainerRequestContext.html#setSecurityContext with a UserPrincipal and inject the SecurityContext as ResourceMethod-Parameter.
    3. Implement a CDI-Interceptor which updates your Method-Parameters.
    4. Implement a class which produces your user and inject it via CDI.

    I pushed examples to github.

    0 讨论(0)
提交回复
热议问题