Разрешение ресурса в службе RESTful
Пусть /users/{id}
будет URL ресурса в службе RESTful.
Обычная проверка подлинности разрешена, и доступ только к аутентифицированным пользователям разрешен для доступа к URL.
Пример сценария:
User_1
и User_2
являются аутентифицированными пользователями с параметрами userId 1 и 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() { /* ... */ }
}