Spring Security - 基于所有权的访问

0x1*_*C1B 6 java security spring spring-security spring-boot

假设我有一个最小的 RESTful 控制器,如下所示,顺便使用 Java 8 和 Spring Boot 2,......

@RestController
class MyController {

    @Autowired
    private PostService service;    

    @GetMapping
    public Post get() {

        return service.getLatest();
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经使用 Spring Security 模块成功保护了这条路线。现在我只想允许资源所有者访问此资源。对于资源所有者,我的意思是创建者或简单地说:

Post myPost = new Post();
...
myPost.getCreator().equals(currentUser); // Should be true when access is granted
Run Code Online (Sandbox Code Playgroud)

我发现了很多关于基于角色的访问,但几乎没有检查所有权......当然我可以在控制器中放置一个 if 语句并抛出异常,但我打算使用类似 Spring 的Expression-Based Access Control之类的东西。

还有其他想法吗?有人有关于资源所有权检查的好主意或示例吗?

Joe*_*ons 8

对于简单的获取操作,您只需返回链接到当前登录用户的帖子

@GetMapping
public Post getPost(Authentication authentication) {
    return service.getPostByUser(authentication.getName());
}
Run Code Online (Sandbox Code Playgroud)

要更新现有帖子,您可以在 PreAuthorize 中检查创建者是否为登录用户。authentication.getName() 在我的示例中返回了一封电子邮件

@PutMapping
@PreAuthorize("#post.getCreator() == authentication.getName()")
public void update(@RequestBody Post post, Authentication authentication) {
    service.updatePost(post);
}
Run Code Online (Sandbox Code Playgroud)

@Component方式的基本示例

@Autowired
private CreatorCheck creatorCheck;

@PutMapping
@PreAuthorize("@creatorChecker.check(#post,authentication)")
public void update(@RequestBody Post post, Authentication authentication) {
    service.updatePost(post);
}
Run Code Online (Sandbox Code Playgroud)

和组件.. 可以扩展以检索原始帖子并检查该创建者..

@Component
public class CreatorCheck {

    public boolean check(Post post, Authentication authentication) {
       return post.getCreator().equals(authentication.getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更全面的教程,请查看0x1C1B找到的本教程链接

  • 但这意味着客户端正在请求中设置帖子的创建者,对吧?我怎样才能防止它操纵创建者?假设使用它自己的 id 来授予访问权限...或者对于 DELETE 请求,没有给出 DTO/有效负载作为参数... (2认同)
  • 您可以编写另一个 @Component public CreatorChecker 类来处理检查。@PreAuthorize("@creatorChecker.check(#post,authentication)") 在此组件中,您从数据库检索帖子并检查创建者 service.getPostId().getCreator() ==authentication.getName() ,如下所示 (2认同)