Как использовать идентификатор пользователя в качестве параметра для пользовательской аннотации аутентификации?

У меня есть 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){
  
}
Другие вопросы по тегам