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

gih*_*han 2 java rest jersey

我已经使用 Jersey 实现了 REST 服务。为了提供更多的安全性,我在 REST 方法中添加了 jersey 安全注释(@PermitAll@DenyAll)。

下面是我的示例 REST 服务:

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

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

网页.xml:

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

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

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

private static String[] bypassPaths = { "/data/getall" };
Run Code Online (Sandbox Code Playgroud)

所以我的要求是这样的。

如果我们将某个 REST 端点声明@PermitAll为该路径,则不应在过滤器中将其声明为旁路路径,以便任何人都可以在没有有效令牌的情况下访问它。

但问题是当请求进入服务器时过滤器总是过滤,如果它不在旁路数组中,即使我声明为@PermitAll.

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

cas*_*lin 7

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

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

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Secured { }
Run Code Online (Sandbox Code Playgroud)

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

ContainerRequestContext帮助你提取HTTP请求信息(更多详情,看看该ContainerRequestContextAPI):

@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
    }
}
Run Code Online (Sandbox Code Playgroud)

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
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,安全过滤器将只被执行,mySecuredMethod(Long)因为它用@Secured.

您可以根据需要为 REST 端点设置任意数量的过滤器。为确保过滤器的执行顺序,请使用@Priority.

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

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

您可以将此方法与Jersey 安全机制结合起来。

此外,您可以注入ResourceInfo您的ContainerRequestFilter

    @Context
    private ResourceInfo resourceInfo;
Run Code Online (Sandbox Code Playgroud)

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

    Class<?> resourceClass = resourceInfo.getResourceClass();
    Method resourceMethod = resourceInfo.getResourceMethod();
Run Code Online (Sandbox Code Playgroud)

并从中提取注释:

    Annotation[] annotations = resourceClass.getDeclaredAnnotations();
    PermitAll annotation = resourceMethod.getAnnotation(PermitAll.class);
Run Code Online (Sandbox Code Playgroud)