我使用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;
Class<?> resourceClass = resourceInfo.getResourceClass();
Method resourceMethod = resourceInfo.getResourceMethod();
并从中提取注释:
Annotation[] annotations = resourceClass.getDeclaredAnnotations();
PermitAll annotation = resourceMethod.getAnnotation(PermitAll.class);