java - 泽西容器请求过滤器 : Getting 404 after throwing 'abortWith' with status forbidden (403)

标签 java rest httpresponse jersey-2.0 restful-authentication

Jersey 2.22 API 具有 token 身份验证 + 基于角色的授权(我保护 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(Priorities. AUTHENTICATION)),验证我的 token ,从解码的 token 中获取用户,然后将其注册为 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) {
... }

最佳答案

您应该设置此 Jersey init-param jersey.config.server.response.setStatusOverSendError true 。这是 Javadoc 中的说明

Whenever response status is 4xx or 5xx it is possible to choose between sendError or setStatus on container specific Response implementation. E.g. on servlet container Jersey can call HttpServletResponse.setStatus(...) or HttpServletResponse.sendError(...).

Calling sendError(...) method usually resets entity, response headers and provide error page for specified status code (e.g. servlet error-page configuration). However if you want to post-process response (e.g. by servlet filter) the only way to do it is calling setStatus(...) on container Response object.

If property value is true the method Response.setStatus(...) is used over default Response.sendError(...).

Type of the property value is boolean. The default value is false.

所以发生的情况是错误导致容器尝试将您发送到错误页面,并且当未配置时,您会收到 404。因此,当您将属性设置为 true ,它导致使用 setStatus而不是sendError

<小时/>

注意:如果您没有使用 web.xml,则 ResourceConfig ,您可以使用property(property, value)方法。对于 Application子类,您可以覆盖 Map<String, Object> getProperties()

public class MyApp extends ResourceConfig {
    public MyApp() {
        property(ServletProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
    }
}

public class MyApp extends Application {
    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("jersey.config.server.response.setStatusOverSendError", true);
        return props;
    }
}

关于java - 泽西容器请求过滤器 : Getting 404 after throwing 'abortWith' with status forbidden (403),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35906403/

相关文章:

javascript - 在 yammer 中的特定组上发帖时如何解决 REST Api 中的跨域错误

asp.net - HttpCookieCollection.Add 与 HttpCookieCollection.Set - Request.Cookies 集合是否被复制到 Response.Cookies 集合?

java - 如何操纵死锁 onAuthFailure 中的响应状态

java - 如何在 JavaFX 中使用字符串数组列表填充 TableView

java - 非等间隔时间序列数据的Round Robin数据存储

java - 从 Selenium Webdriver WebElement 字段中检索值并将其传递给 java 变量

Java HttpResponse 澄清

java - 如何用Android代码制作系统应用程序

java - 当路径中的第一个缺失时,多个 PathParams 不会失败

java - 通过rest和html作为客户端上传文件