简体   繁体   中英

Access servlet annotations from filter

I need a filter that gets called before every servlet and checks if that servlet has an annotation that states that it requires authentication, for example @ServletSecurity(@HttpConstraint(rolesAllowed={"user"})) in Servlet 3. If that is not the case then the filter will just return. If the servlet requires authentication, it will check if the request token has a user role, if it doesn't it will automatically set a NOT_AUTHENTICATED response, with not even passing through the servlet.

This job must be done by the filter because I need to validate the JWT token from the request and add the decodedJWT to the request so the servlet can use it's payload.

How do I check for servlet annotations from a filter? In that case, could I create a simpler annotation like @RequiresAuth in the servlet? Because I don't need roles in this project.

Is it possible to return a not authenticated response to the client from the filter without going through the servlet?

Is it possible to set the filter to be the first one programmatically?

This is how I solved it using Jersey but I need a solution just with servlets:

@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext context) {
        final Method method = resourceInfo.getResourceMethod();

        if (method.isAnnotationPresent(PermitAll.class)) return;
        if (method.isAnnotationPresent(DenyAll.class)) {
            context.abortWith(Response.status(Response.Status.FORBIDDEN).build());
            return;
        }

        final RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
        if (rolesAnnotation == null) return;
    }
}

How do I check for servlet annotations from a filter? In that case, could I create a simpler annotation like @RequiresAuth in the servlet? Because I don't need roles in this project.

It's possible, but not advised. Filters are meant to be selectively applied to servlets that need them. In your case, I would only map it to those servlets that require authentication.

In your Jersey example, the AuthenticationFilter applies to all endpoints. With servlet filters, you decide which servlets/url-patterns you want this filter to apply to. Introspecting for annotations no longer makes sense here.

Is it possible to return a not authenticated response to the client from the filter without going through the servlet?

Yes. you return from the filter by calling response.setStatus(401) instead of chain.doFilter.

if (isAuthenticated()) {
    // this proceeds to the next filter or servlet in the chain
    chain.doFilter(request, response);
}
else {
    // this returns the response to the client
    response.setStatus(401);
}

Is it possible to set the filter to be the first one programmatically?

Yes. It's not possible through annotations, but it is possible through web.xml. There it's just the order of elements for any given servlet or url-pattern.

<filter>
    <filter-name>filter1</filter-name>
    <filter-class>filter.Filter1</filter-class>
</filter>

<filter>
    <filter-name>filter2</filter-name>
    <filter-class>filter.Filter2</filter-class>
</filter>
    
<!-- filter2 will be applied 1st because it's listed 1st -->
<filter-mapping>
    <filter-name>filter2</filter-name>
    <servlet-name>some-servlet</servlet-name>
</filter-mapping>

<!-- filter1 will be applied after filter2 -->
<filter-mapping>
    <filter-name>filter1</filter-name>
    <servlet-name>some-servlet</servlet-name>
</filter-mapping>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM