【问题标题】:Custom HTTP status response with JAX-RS (Jersey) and @RolesAllowed使用 JAX-RS (Jersey) 和 @RolesAllowed 自定义 HTTP 状态响应
【发布时间】:2011-09-25 02:10:17
【问题描述】:

通过我非常简单的 JAX-RS 服务,我使用带有 JDBC 领域的 Tomcat 进行身份验证,因此我正在使用 JSR 250 注释。

问题是我想在 HTTP 状态响应中返回一个自定义消息体。状态码 (403) 应该保持不变。例如,我的服务如下所示:

@RolesAllowed({ "ADMIN" })
@Path("/users")
public class UsersService {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public String getUsers() {
        // get users ...
        return ...;
    }
}

如果具有不同于“ADMIN”角色的用户访问服务,我想将响应消息更改为类似的内容(取决于媒体类型 [xml/json]):

<error id="100">
    <message>Not allowed.</message>
</error>

此时 Jersey 返回以下正文:

HTTP Status 403 - Forbidden

type Status report
message Forbidden
description Access to the specified resource (Forbidden) has been forbidden.
Apache Tomcat/7.0.12

如何更改默认邮件正文?有没有办法处理(可能抛出的)异常来构建我自己的 HTTP 状态响应?

【问题讨论】:

标签: java jersey jax-rs jsr250


【解决方案1】:

处理此类事情的最简单方法是抛出异常并注册异常映射器以在这种情况下转换为您要发送的消息类型。所以,假设你抛出一个AccessDeniedException,你就会有一个像这样的处理程序(为了清楚起见,在地方有完整的类名):

@javax.ws.rs.ext.Provider
public class AccessDeniedHandler
        implements javax.ws.rs.ext.ExceptionMapper<AccessDeniedException> {
    public javax.ws.rs.core.Response toResponse(AccessDeniedException exn) {
        // Construct+return the response here...
        return Response.status(403).type("text/plain")
                .entity("get lost, loser!").build();
    }
}

您注册异常映射器的方式因您使用的框架而异,但对于泽西岛,您只需使用@Provider 就可以了。我会让你自己弄清楚你想如何生成你想要的那种错误文档,但我确实建议将失败处理为某种 HTTP 错误代码(这更符合 RESTful...)

【讨论】:

  • 事情是泽西返回它的自定义 403 响应。我无法将AccessDeniedException 用于授权,因为@RolesAllowed 的东西处理了这个问题。 HTTP错误代码应该是我只想更改正文消息的一些。
  • 我认为你可以在泽西岛用 ExceptionMapper 做到这一点;我知道你可以使用 Apache CXF(尽管由于我开始欣赏的原因,它的配置不同)所以我认为至少 try 是合理的,因为它们都是 JAX-RS 引擎,这是只是使用 JAX-RS API,但我没有直接使用 Jersey 的经验,所以可能会有一些意想不到的事情发生。
【解决方案2】:

通过创建ExceptionMapper(映射WebApplicationException 的异常),可以“捕获”应用程序抛出的某些异常:

@Provider
public class MyExceptionMapper implements ExceptionMapper<WebApplicationException> {

    @Override
    public Response toResponse(WebApplicationException weException) {

        // get initial response
        Response response = weException.getResponse();

        // create custom error
        MyError error = ...;

        // return the custom error
        return Response.status(response.getStatus()).entity(error).build();
    }
}

您还需要将包添加到您的应用程序 web.xml 以注册提供程序:

<init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>
        com.myapp.userservice; // semi-colon seperated
        com.myapp.mappedexception
    </param-value>
</init-param>

【讨论】:

  • 我遇到了同样的问题,就我而言,这是完美的答案。谢谢斯特凡!
【解决方案3】:

REST 基于 HTTP 构建,因此您不必更改身份验证失败的默认行为。访问资源时出现 403 错误足以让客户端清楚地了解附加的内容。

您的资源越符合 HTTP,其他人就越能理解它。

【讨论】:

  • 问题是可能有多种情况发生单个http错误。一个可以是由 AS 管理的会话超时(导致 403)。另一个可能是对休息资源的未经授权的尝试 (403)。如果您必须以不同的方式以编程方式对这些错误做出反应,那么这是自定义它们的好方法。
  • @Lars 我认为在这种情况下您可以使用自定义 http 代码 4##。第一个数字决定类别。 4 表示“请求包含错误的语法或无法完成”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 2015-01-03
  • 1970-01-01
相关资源
最近更新 更多