我应该如何根据 Spring 中的用户角色将端点设计为 return 不同的模型
How should I design endpoint to return different models depending on User role in Spring
所以假设我有 2 个模型 classes - User 和 Presentation,它们看起来像这样:
@Entity
public class Presentation {
@Id
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@Entity
public class User implements UserDetails {
@Id
private Long id;
private String username;
private String name;
private String surname;
private String password;
@Enumerated(EnumType.STRING)
private Role role;
}
如您所见,我在 Presentation class 中为用户创建了一个单向映射。我的端点看起来像这样:
@RestController
public class PresentationController {
@GetMapping("/{presentationId}")
public PresentationDTO getPresentation(@PathVariable Long presentationId) {
return presentationService.getPresentationById(presentationId);
}
@GetMapping
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}
}
现在回答我的问题 - 如何将 getAllPresentations() 更改为 return 角色为“user”的用户拥有的演示文稿,以及 return 角色为“admin”的用户的所有演示文稿?我知道我可以创建一个具有不同映射(如 /admin/presentations)的单独端点并添加 @PreAuthorize(hasRole("admin")),但这是棘手的部分。
对于 getAllPresentations() 端点,每个经过身份验证的人都应该获取他自己的演示文稿,我怎么知道我必须为哪个用户 return 他的演示文稿?也许我可以获得用户名作为参数,但这可能很危险,因为他可以提交他想要的任何用户名并获得该用户的演示文稿。我不太了解 Spring 安全性,我什至不知道要问 google 正确的问题以获得答案,所以我被困住了......
任何帮助将不胜感激,谢谢!
您不必将用户名传递给您的控制器方法。当前经过身份验证的用户可通过 Spring.The 中的多种不同机制获得,检索当前经过身份验证的主体的最简单方法是通过对 SecurityContextHolder
的静态调用,如下所示:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
因此您可以重构服务 class 中的方法 getAllPresentations()
以接受 username
作为参数,然后您可以通过传递的 username
和 [=21 加载用户=] 该用户的演示文稿。
做你想做的事情的一种方法是使用 @PostFilter
注释来过滤已验证用户拥有的 List<Presentation>
或者如果已验证用户具有这样的角色 ADMIN
:
@GetMapping
@PostFilter("filterObject.user.username == authentication.principal.username or hasRole('ADMIN')")
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}
所以假设我有 2 个模型 classes - User 和 Presentation,它们看起来像这样:
@Entity
public class Presentation {
@Id
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@Entity
public class User implements UserDetails {
@Id
private Long id;
private String username;
private String name;
private String surname;
private String password;
@Enumerated(EnumType.STRING)
private Role role;
}
如您所见,我在 Presentation class 中为用户创建了一个单向映射。我的端点看起来像这样:
@RestController
public class PresentationController {
@GetMapping("/{presentationId}")
public PresentationDTO getPresentation(@PathVariable Long presentationId) {
return presentationService.getPresentationById(presentationId);
}
@GetMapping
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}
}
现在回答我的问题 - 如何将 getAllPresentations() 更改为 return 角色为“user”的用户拥有的演示文稿,以及 return 角色为“admin”的用户的所有演示文稿?我知道我可以创建一个具有不同映射(如 /admin/presentations)的单独端点并添加 @PreAuthorize(hasRole("admin")),但这是棘手的部分。 对于 getAllPresentations() 端点,每个经过身份验证的人都应该获取他自己的演示文稿,我怎么知道我必须为哪个用户 return 他的演示文稿?也许我可以获得用户名作为参数,但这可能很危险,因为他可以提交他想要的任何用户名并获得该用户的演示文稿。我不太了解 Spring 安全性,我什至不知道要问 google 正确的问题以获得答案,所以我被困住了...... 任何帮助将不胜感激,谢谢!
您不必将用户名传递给您的控制器方法。当前经过身份验证的用户可通过 Spring.The 中的多种不同机制获得,检索当前经过身份验证的主体的最简单方法是通过对 SecurityContextHolder
的静态调用,如下所示:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
因此您可以重构服务 class 中的方法 getAllPresentations()
以接受 username
作为参数,然后您可以通过传递的 username
和 [=21 加载用户=] 该用户的演示文稿。
做你想做的事情的一种方法是使用 @PostFilter
注释来过滤已验证用户拥有的 List<Presentation>
或者如果已验证用户具有这样的角色 ADMIN
:
@GetMapping
@PostFilter("filterObject.user.username == authentication.principal.username or hasRole('ADMIN')")
public List<PresentationDTO> getAllPresentations() {
return presentationService.getAllPresentations();
}