我有一个 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);
}
但我的 userId 为 null。但是,如果我更换
@PreAuthorize("@applicationUserDetailsService.hasAccessToResourceOwnedBy(#userId)")
与
@PreAuthorize("@applicationUserDetailsService.hasAccessToResourceOwnedBy(#studentId)")
我获得了请求的用户ID。
基本上,我需要这个注释来避免权限的水平升级,也许有更好的解决方案?
认为这是因为 Spring Security 支持的元注释只是简单地允许用户使用自定义注释(即
@CurrentUserAccessLevel
)来引用 @PreAuthorize(xxxxx)
并且没有使用 self 属性的奇特行为-定义的注释(即 userId
的 @CurrentUserAccessLevel
属性)来执行一些动态安全配置,就像您想要做的那样。所以userId
的@CurrentUserAccessLevel
没有用,可以去掉。
#userId
表达式中的 @PreAuthorize
指的是用 @CurrentUserAccessLevel
注解的方法的参数名称。因此,如果将其更改为 #studentId
,则它会起作用,因为 getUserCourseDetails()
有一个方法参数名称 Long studentId
如果您不想将方法的参数名称更改为
userId
,您可以使用 @P
来指定其值,例如:
@CurrentUserAccessLevel
public UserCourseDetailsDto getUserCourseDetails( Long courseCode, @P("userId") Long studentId){
}