如何在Java中使用Jersey安全注释绕过servlet过滤器中的路径

我使用Jersey实现了REST服务.为了提高安全性,我在REST方法中添加了泽西安全注释(@PermitAll,@ DenyAll).

以下是我的示例REST服务:

@GET
@Path("/getall")
@Produces(MediaType.APPLICATION_JSON)
@PermitAll
public String getChartSupportedData(@QueryParam("items") int result) {
    // my code goes here
}

但问题是以前我使用javax.servlet.Filter过滤器来验证URI.

web.xml中:

<filter>
    <filter-name>ApplicationFilter</filter-name>
    <filter-class>web.filter.ApplicationFilter</filter-class>
</filter>
<filter-mapping>
       <filter-name>ApplicationFilter</filter-name>
       <url-pattern>/rest/api/*</url-pattern>
       <dispatcher>REQUEST</dispatcher>
       <dispatcher>ASYNC</dispatcher>           
</filter-mapping>

根据访问一些REST服务,HttpServletRequest应该包含一个有效的令牌(由应用程序生成).

某些REST端点不需要令牌来访问服务.在这种情况下,我必须在过滤器实现中绕过它:

private static String[] bypassPaths = { "/data/getall" };

所以我的要求是这样的.

如果我们将一些REST端点声明为@PermitAll,那么该路径不应该在filter中声明为旁路路径,这样任何人都可以在没有有效令牌的情况下访问它.

但问题是,当请求进入服务器时,过滤器总是过滤,如果不在旁路阵列中,则请求不会继续,即使我声明为@PermitAll.

我想知道是否可以在同一个Web应用程序中组合这两个安全选项.

解决方法:

由于您正在执行身份验证和/或授权,而不是servlet过滤器,我建议使用名称绑定过滤器,以便您可以轻松地将它们绑定到您需要的资源.

要将过滤器绑定到REST端点,JAX-RS提供了元注释@NameBinding,可以按如下方式使用:

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

@Secured注释将用于装饰过滤器类,它实现了ContainerRequestFilter,允许您处理请求.

ContainerRequestContext可帮助您从HTTP请求中提取信息(有关详细信息,请查看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
    }
}

如果用户未经过身份验证/授权,则ContainerRequestFilter#filter()方法是中止请求的好地方.为此,您可以使用ContainerRequestContext#abortWith()或抛出异常.

@Provider注释标记了在提供程序扫描阶段JAX-RS运行时应该可以发现的扩展接口的实现.

要将过滤器绑定到端点方法或类,请使用上面创建的@Secured注释对其进行注释.对于注释的方法和/或类,将执行过滤器.

@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
        ...
    }
}

在上面的示例中,安全过滤器将仅针对mySecuredMethod(Long)执行,因为它使用@Secured进行了注释.

您可以根据需要为REST端点提供尽可能多的过滤器.要确保过滤器的执行顺序,请使用@Priority对其进行注释.

强烈建议使用Priorities类中定义的值之一(将使用以下顺序):

> AUTHENTICATION
> AUTHORIZATION
> ENTITY_CODER
> HEADER_DECORATOR
> USER

如果您的过滤器未使用@Priority进行注释,则将使用USER优先级执行过滤器.

您可以将此方法与Jersey security mechanism结合使用.

此外,您可以在ContainerRequestFilter中注入ResourceInfo

    @Context
    private ResourceInfo resourceInfo;

它可用于获取与请求的URL匹配的MethodClass

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

并从中提取注释:

    Annotation[] annotations = resourceClass.getDeclaredAnnotations();
    PermitAll annotation = resourceMethod.getAnnotation(PermitAll.class);
上一篇:[转]据说200G网盘资料


下一篇:java – 如何对Tomcat上部署的Jersey Web应用程序进行单元测试?