Как защитить ресурсы REST, чтобы к ним мог получить доступ только один пользователь роли? - PullRequest
5 голосов
/ 23 февраля 2012

Я успешно создал веб-сервис REST с Джерси и защитил его с помощью аннотаций безопасности Java. Это выглядит примерно так

GET    /users/     // gives me all users
GET    /users/{id} // gives the user identified by {id}
POST   /users/     // creates user
PUT    /users/{id} // updates user identified by {id}
DELETE /users/{id} // delete user

Я также настроил область с двумя ролями: пользователь и администратор

Я закрепил все методы, чтобы только администраторы могли получить к ним доступ.

Теперь я хочу бесплатно предоставить методы PUT /users/{id} и GET /users/{id}, чтобы пользователи могли получить доступ к своим собственным и только своим собственным ресурсам.

Пример:

// user anna is logged in and uses the following methods
    GET    /users/anna // returns 200 OK
    GET    /users/pete // returns 401 UNAUTHORIZED

Так как я не смог найти способ настроить это с помощью аннотаций, я думаю передать HTTP-запрос соответствующему методу, чтобы проверить, разрешен ли пользователю доступ к ресурсу.

Для метода GET /users/{id} это будет выглядеть примерно так:

@GET
@Path("/users/{id}")
@RolesAllowed({"admin","user"})
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(
    @PathParam("id") String id,
    @Context HttpServletRequest req
) {
    HttpSession session = request.getSession(false);

    if (session != null && session.getValue("userID").equals(id))
        return getObject(User.class, id);

    return Response.status(Status.UNAUTHORIZED).build();
}

Мне не нравится этот подход, потому что я думаю, что мне нужно было бы добавить userID руководство к сессии.

  • Знаете ли вы более элегантный способ решить эту проблему?

  • Если нет, то как добавить идентификатор пользователя в сеанс при использовании проверки подлинности формы?

EDIT

Спасибо, Уилл и Павел :) Вот мое окончательное решение:

@Context
private SecurityContext security;

// ...
@GET
@Path("/users/{id}")
@RolesAllowed({"admin","user"})
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(@PathParam("id") String id){
    if (security.isUserInRole("user"))
        if (security.getUserPrincipal().getName().equals(id))
            return getObject(User.class, id);
        else
            return Response.status(Status.UNAUTHORIZED).build();
    else
        return getObject(User.class, id);
}

Ответы [ 2 ]

2 голосов
/ 23 февраля 2012

В HttpServletRequest вы можете позвонить getRemoteUser() или getUserPrincipal(), чтобы получить личность вошедшего в систему пользователя. Затем вы продолжите, как и вы, специально разрешив или запретив им доступ к конкретному ресурсу.

Blessed Geek более конкретно ссылается на аспект REST, касающийся транзакций без сохранения состояния и использования HTTP-аутентификации. Хотя это важный момент в более широкой области применения архитектуры REST, он не так важен для вашего конкретного вопроса, поскольку вы не указываете тип механизма аутентификации, который вы используете для своего приложения Java EE, тем более что аутентификация является проблемой контейнера в Java EE не проблема приложения.

Если вы используете обычную аутентификацию, то вы используете HTTP-заголовки для управления аутентификацией и авторизацией. Если вы используете проверку подлинности на основе форм, тогда контейнер управляет этим для вас через сеанс сервлета, что делает службу состоящей из состояний (поскольку сеансы являются артефактом с состоянием).

Но это не имеет отношения к вашему конкретному вопросу.

0 голосов
/ 23 февраля 2012

Одним из наиболее важных аспектов развертывания REST является понимание роли заголовков http и файлов cookie.

Чтобы REST был практичным, вам необходимо развернуть структуру аутентификации.

Чтение

GWT и Google Docs API .

Вход в GWT-Platform + управление сеансом

Ознакомьтесь с Google Federated Login, OAuth и OpenID.

Некоторые из моих объяснений могут быть устаревшими, если они были опубликованы до OAuth 2.0.

...