【问题标题】:How to bypass path in servlet filter with Jersey security annotations in Javajava - 如何使用Java中的Jersey安全注释绕过servlet过滤器中的路径
【发布时间】:2016-02-12 11:20:27
【问题描述】:

我已经使用 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,则该路径不应在过滤器中声明为旁路路径,这样任何人都可以在没有有效令牌的情况下访问它。

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

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

【问题讨论】:

  • 您是否考虑过使用 JAX-RS 作为名称绑定过滤器而不是 Servlet 过滤器?
  • 不,我不会看的。

标签: java rest jersey


【解决方案1】:

由于您正在执行身份验证和/或授权,因此我建议您使用名称绑定过滤器而不是 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 类中定义的值之一(将使用以下顺序):

如果您的过滤器未使用@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);

【讨论】:

  • 是的,谢谢@Cássio Mazzochi Molin,我会试试的。我从你的帖子中学到了很多东西。
  • @gihan 我更新了我的答案,添加了一些关于ResourceInfo 的信息。它可能对你有用:-)
  • 它工作正常。但我必须在 ResourceConfig 类中注册 SecurityFilter。注册(SecurityFilter .class);如果不是过滤器不执行。因为在我的 web.xml 中,我在 servlet 中声明了该类。这种方式正确还是有任何其他方式可以做到这一点?谢谢。
  • 如果你的过滤器没有执行,这个链接可以帮助别人。stackoverflow.com/questions/19785001/…
  • 虽然这是一个很好的答案,但我建议反其道而行之,默认关闭所有端点,而打开您需要的少数端点。这样您就不会因为忘记注释而突然打开端点。
猜你喜欢
  • 2013-05-28
  • 2011-12-30
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多