Пользовательский ответ о статусе HTTP с JAX-RS (Джерси) и @RolesAllowed - PullRequest
15 голосов
/ 29 июня 2011

С моей очень простой службой JAX-RS я использую Tomcat с областью JDBC для аутентификации, поэтому я работаю с аннотациями 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>

На данный момент Джерси возвращает следующее тело:

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?

Ответы [ 3 ]

18 голосов
/ 30 июня 2011

Самый простой способ справиться с подобными вещами - это создать исключение и зарегистрировать преобразователь исключений для преобразования в тип сообщения, которое вы хотите отправить в этом случае.Итак, предположим, что вы выбросили 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 ...)

9 голосов
/ 30 июня 2011

С созданием 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>
2 голосов
/ 01 июля 2011

REST основан на HTTP, поэтому вам не нужно менять поведение по умолчанию при сбое аутентификации. Наличие ошибки 403 при доступе к ресурсу достаточно для того, чтобы клиент четко понимал, что добавляется.

Чем больше ваши ресурсы соответствуют HTTP, тем больше другие могут это понять.

...