Авторизация на уровне ресурсов в сервисе RESTful - PullRequest
12 голосов
/ 09 июля 2011

Пусть /users/{id} будет URL ресурса в службе RESTful.

Базовая аутентификация включена, и только аутентифицированные пользователи могут получить доступ к URL.

Пример сценария:

User_1 & User_2 являются аутентифицированными пользователями с userId 1 и 2. Поскольку оба аутентифицированы, оба имеют доступ к

  • /users/1
  • /users/2

Но ожидается, что User_1 должен иметь доступ к /users/1, а не к /users/2 или другому идентификатору пользователя.

Вопрос: Как выполнить авторизацию на уровне ресурсов в сервисах RESTful?

Примечание: я реализую RESTful с использованием Jax-RS (с реализацией Apache CXF), полезно, если вы могли бы объяснить с помощью Jax-RS.

-Barath

Edit:

Как упоминал Донал, я не ищу авторизацию на основе ролей, а скорее авторизацию на уровне ресурсов.

Чтобы привести пример, скажем, / users / {id} / photos / {photoId} будет другим URL ресурса. Пользователю_1 должен быть предоставлен доступ к фотографиям, принадлежащим только ему. Если photoId 2 принадлежит user_2, то мы должны предоставить http_404 код ошибки для user_1 при запросе запроса / users / 1 / photos / 2. [Так как User_1 также является аутентифицированным пользователем, он может вызывать / users / 2 / photos / 2, поэтому мы должны идентифицировать идентификатор пользователя по параметрам аутентификации, а не по URL ресурса]

Единственное решение, которое я могу придумать, - включить уникальный идентификатор, который определяет авторизацию в каждом запросе, например,

Вместо SELECT * FROM PHOTO_TBL WHERE PHOTO_ID=2;

использовать SELECT * FROM PHOTO_TBL, USER_TBL WHERE PHOTO_ID=2 AND USER_ID=1 AND USER_ID=PHOTO_ID;

с помощью этих ресурсов доставляются данные, принадлежащие конкретному пользователю. [Должен быть механизм, предотвращающий изменение уникального идентификатора на стороне клиента, который используется для принятия решения об авторизации (в данном случае userId), поскольку все запросы являются запросами STATELESS]

Предупреждение: Каждый запрос должен быть достаточно интеллектуальным, чтобы понимать проблемы безопасности и включать дополнительное соединение. Это плохой дизайн для привязки логики безопасности к каждой бизнес-функции.

Мне еще предстоит изучить безопасность Spring и то, как ее можно использовать в этом случае.

Ответы [ 2 ]

3 голосов
/ 12 декабря 2013

Я бы порекомендовал не указывать идентификатор пользователя в URL-адресе (как если бы он был «ограничен» заголовком Basic Auth, тогда вы также можете просто «указать» его заголовком Basic Auth). Это снизит риск внедрения прямой ссылки на уязвимость объекта - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References)

В этом случае у вас может быть один из следующих URL:

/users/CURRENT
/me

Поскольку фотографии - это подресурс, вы можете просто создать фотографии с «порядковым номером» внутри пользователя. В базе данных sql это будет означать наличие «составного ключа» в столбцах пользователя и фотографии.

/users/CURRENT/photo/{user_photo_seq}
/me/photo/{user_photo_seq}

Ваш SQL будет выглядеть примерно так:

SELECT * FROM PHOTO_TBL WHERE USER_ID=<BasicAuthUsername> AND PHOTO_ID=<path param value>;

Хорошее объяснение "Basic Auth Headers":

http://en.wikipedia.org/wiki/Basic_access_authentication

1 голос
/ 11 февраля 2014

JAX-RS указывает подресурс , где вместо обработки запроса в методе обработка делегируется другому объекту - подресурсу.

Используя подресурсы, нужно заботиться о корневом ресурсе, а вложенные также будут защищены.

В примере вы видите UserResource и все его подресурсы, доступные только авторизованному пользователю.

@Path("/user/{userId}")
public class UserResource {

  private final String userId;

  public UserResource(@PathParam("userId") String userId, @Context SecurityContext securityContext) {
    this.userId = userId;

    boolean authorized = /* authorization code */;

    if (!authorized) { throw new WebApplicationException(Status.UNAUTHORIZED); }
  }

  @Path("photo")
  public PhotoResource getPhotoResource() {
    return new PhotoResource(userId);
  }

}

public class PhotoResource {

  private final String userId;

  public PhotoResource(String userId) {
    this.userId = userId;
  }

  @GET
  public Response listAll() { /* ... */ }

  @GET
  @Path("{photoId}")
  public Response present() { /* ... */ }

}
...