Как использовать идентификатор пользователя в качестве параметра для пользовательской аннотации аутентификации?
У меня есть REST API:
@CurrentUserAccessLevel(userId = "#studentId")
@GetMapping(value = "/{course-code}/users/{student-id}")
public UserCourseDetailsDto getUserCourseDetails(@PathVariable(value = "course-code") final Long courseCode,
@PathVariable(value = "student-id") final Long studentId) {
return userCourseService.getUserCourseDetails(studentId, courseCode);
}
и пользовательская аннотация аутентификации:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@PreAuthorize("@applicationUserDetailsService.hasAccessToResourceOwnedBy(#userId)")
public @interface CurrentUserAccessLevel {
String userId();
}
в аннотации используется метод hasAccessToResourceOwnedBy(userId):
public boolean hasAccessToResourceOwnedBy(final Long userId) {
final User currentUser = userService.resolveCurrentUser();
return isAdmin(currentUser) || Objects.equals(currentUser.getId(), userId);
}
но я получаю нулевой идентификатор пользователя. Однако, если я заменю
@PreAuthorize("@applicationUserDetailsService.hasAccessToResourceOwnedBy(#userId)")
с
@PreAuthorize("@applicationUserDetailsService.hasAccessToResourceOwnedBy(#studentId)")
Я получаю запрошенный идентификатор пользователя.
По сути, мне нужна эта аннотация, чтобы избежать горизонтального повышения привилегий, может быть, есть какое-то лучшее решение?
1 ответ
Подумайте, что это потому, что метааннотации, поддерживаемые Spring Security, просто позволяют пользователям использовать самоопределенную аннотацию (т. е.) для ссылки на@PreAuthorize(xxxxx)
и нет никакого необычного поведения при использовании атрибута самоопределенной аннотации (т. е. атрибута ) для выполнения некоторой динамической конфигурации безопасности, похожей на то, что вы пытаетесь сделать. Таким образом, элемент бесполезен, и вы можете удалить его.
The #userId
в@PreAuthorize
Выражение относится к имени параметра метода, который помечен@CurrentUserAccessLevel
. Так что это работает, если вы измените его на#studentId
какgetUserCourseDetails()
имеет имя параметра методаLong studentId
Если вы не хотите менять имя параметра метода наuserId
, вы можете использовать@P
чтобы указать его значение, например:
@CurrentUserAccessLevel
public UserCourseDetailsDto getUserCourseDetails( Long courseCode, @P("userId") Long studentId){
}