Jersey ContainerRequestFilter:投掷'abortWith'后状态为禁止获得404(403)

时间:2016-03-10 02:17:54

标签: java rest httpresponse jersey-2.0 restful-authentication

Jersey 2.22 API,带有令牌身份验证+基于角色的授权(我保护API的方式基于此帖子中接受的答案:Best practice for REST token-based authentication with JAX-RS and Jersey。在尝试理解我的问题之前阅读它可能更好) :

这是我的 web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

<!-- LISTENERS -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>JerseySpringServlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>ca.toto.api.filters</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>ca.toto.api.restapi</param-value>
    </init-param>

    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>ca.toto.api.filters.AuthenticationFilter;ca.toto.api.filters.AuthorizationFilter;com.toto.api.restapi.TaskRestService</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>JerseySpringServlet</servlet-name>
    <url-pattern>/filters/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>JerseySpringServlet</servlet-name>
    <url-pattern>/restapi/*</url-pattern>
</servlet-mapping>

当我打电话给我的任务网络服务时,流程会进入第一个过滤器( AuthenticationFilter )而没有任何问题( @Priority(优先级。 AUTHENTICATION)),验证我的令牌,从解码后的令牌中获取用户,然后将其注册为 Principal ,然后传入第二个过滤器 AuthorizationFilter @Priority(Priorities.AUTHORIZATION))我从安全上下文中获取用户,获取他的角色,然后检查他是否有权拨打电话。如果是,请在正常情况下退出过滤器,使用 javax.ws.rs.container.ContainerRequestContext abortWith 方法发送状态为403的响应:

@Secured
@Provider
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {

    ...
try {
        boolean isAllowed = false;
        // Check if the user is allowed to execute the method
        // The method annotations override the class annotations
        if (methodRoles.isEmpty()) {
            logger.info("Checking permissions on CLASS level");
            isAllowed = checkPermissions(classRoles);
        } else {
            logger.info("Checking permissions on METHOD level");
            isAllowed = checkPermissions(methodRoles);
        }

        // Throw an Exception if the user has not permission to execute the method
        if(isAllowed == false) {
            logger.warn("USER IS NOT ALLOWED TO COMPLETE THE REQUEST. ABORT.");
             requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
        }

    } catch (Exception e) {
        requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
    }

当用户具有正确的角色时,将调用该服务并使用正确的信息获得正确的响应。 我的问题是,当我的变量 isAllowed 等于false时,我得到 404 而不是 403 ,我无法弄清楚原因。 ..

这是我的 TaskRestService 服务定义:

@Path("/tasks")
@Secured({RoleEnum.admin})
public class TaskRestService {
    ...
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Transactional(readOnly = true)
    public List<Task> getTasks(@QueryParam("code") String code) {
... }

1 个答案:

答案 0 :(得分:4)

您应该将此Jersey-param jersey.config.server.response.setStatusOverSendError设置为true。这是它在Javadoc中的陈述

  

每当响应状态为4xx或5xx时,可以在特定于容器的sendError实施中选择setStatusResponse。例如。在servlet容器上,Jersey可以调用HttpServletResponse.setStatus(...)HttpServletResponse.sendError(...)

     

调用sendError(...)方法通常会重置实体,响应标头并为指定的状态代码提供错误页面(例如,servlet错误页面配置)。但是,如果要进行后处理响应(例如,通过servlet过滤器),唯一的方法是在容器setStatus(...)对象上调用Response

     

如果属性值为true,则使用方法Response.setStatus(...)而不是默认Response.sendError(...)

     

属性值的类型为boolean。默认值为false

所以会发生错误导致容器尝试将您发送到错误页面,当没有配置时,您会得到404.所以当您将属性设置为true时,会导致使用setStatus而不是sendError