【问题标题】:Post authorizing Spring asynchronous controller response发布授权 Spring 异步控制器响应
【发布时间】:2017-12-26 19:07:13
【问题描述】:

我有一个带有 GET 方法的 REST 控制器。它返回一个资源。我想通过将Resource 上的owner 字段与授权用户的登录名进行比较来验证资源是否属于授权用户。对于正常的同步请求,我会做这样的事情:

@RestController
@RequestMapping("/api")
public class AController {

    private final AService aService;

    public AController(AService aService) {
        this.aService = aService;
    }

    @GetMapping("/resources/{id}")
    @PostAuthorize("returnObject.ownerLogin == authentication.name")
    public Resource getResource(@PathVariable Long id) {
        return aService.getResource(id);
    }
}

但是如果控制器方法是异步的(用DeferredResult 实现)呢?

@RestController
@RequestMapping("/api")
public class AController {

    private final AService aService;

    public AController(AService aService) {
        this.aService = aService;
    }

    @GetMapping("/resources/{id}")
    @PostAuthorize("returnObject.ownerLogin == authentication.name")
    public DeferredResult<Resource> getResource(@PathVariable Long id) {
        DeferredResult<Resource> deferredResult = new DeferredResult<>();

        aService
            .getResourceAsync(id)
            .thenAccept(resource -> {
                deferredResult.setResult(resource);
            });

        return deferredResult;
    }
}

AService 界面如下所示:

@Service
public class AService {

    @Async
    public CompletableFuture<Resource> getResourceAsync(Long id) {
        // implementation...
    }

    public Resource getResource(Long id) {
        // implementation...
    }
}

Resource 类是一个简单的 DTO:

public class Resource {

    private String ownerLogin;

    // other fields, getters, setters

}

在第二个示例中,Spring Security 显然会在 DeferredResult 实例上查找 ownerLogin 字段。我希望它将异步解析的Resource 视为@PostAuthorize SPEL 表达式中的returnObject

有可能吗?也许有人可以建议一种替代方法?欢迎提出任何建议。

【问题讨论】:

    标签: spring asynchronous spring-security spring-web deferred-result


    【解决方案1】:

    无法通过PostAuthorize 实现我的目标并最终执行以下操作:

    使Resource 成为User 资源的子资源。使用PreAuthorize 注释来验证用户的登录。

    @RestController
    @RequestMapping("/api")
    public class AController {
    
        private final AService aService;
    
        public AController(AService aService) {
            this.aService = aService;
        }
    
        @GetMapping("/users/{login:" + Constants.LOGIN_REGEX + "}/resources/{id}")
        @PreAuthorize("#login == authentication.name")
        public DeferredResult<Resource> getResource(@PathVariable String login, @PathVariable Long id) {
            DeferredResult<Resource> deferredResult = new DeferredResult<>();
    
            aService
                .getResourceAsync(login, id)
                .thenAccept(resource -> {
                    deferredResult.setResult(resource);
                });
    
            return deferredResult;
        }
    }
    

    AService 中添加了所有权检查。如果Resource 所有者和请求用户的登录名不匹配,则抛出解析为404 HTTP 状态的异常:

    @Service
    public class AService {
    
        private final ARepository aRepository;
    
        public AController(ARepository aRepository) {
            this.aRepository = aRepository;
        }
    
        @Async
        public CompletableFuture<Resource> getResourceAsync(String owner, Long id) {
            Resource resource = aRepository.getResource(id);
    
            if (!resource.owner.equals(owner)) {
                // resolves to 404 response code
                throw ResourceNotFounException();
            }
    
            return resource;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-12
      • 2023-03-27
      • 2018-02-07
      • 2014-12-22
      • 2019-09-27
      • 1970-01-01
      • 2014-08-04
      • 2013-08-29
      • 1970-01-01
      相关资源
      最近更新 更多