Разрешение ресурса в службе RESTful

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

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

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

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

  • /users/1
  • /users/2

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

Вопрос: Как выполнить авторизацию уровня ресурса в службах 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 безопасность и как ее можно использовать в этом случае.

Ответ 1

Я бы порекомендовал не иметь идентификатор пользователя в URL-адресе (как если бы он был "ограничен" заголовком Basic Auth, тогда вы можете просто указать его "основным" заголовком 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>;

Хорошее объяснение "Основные заголовки Auth":

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

Ответ 2

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() { /* ... */ }

}