Post 授权 Spring 异步控制器响应
Post authorizing Spring asynchronous controller response
我有一个带有 GET 方法的 REST 控制器。它 returns 一种资源。我想通过比较 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
class是一个简单的DTO:
public class Resource {
private String ownerLogin;
// other fields, getters, setters
}
在第二个示例中,Spring 安全性会在 DeferredResult
实例中寻找 ownerLogin
字段。我希望它将异步解析的 Resource
视为 @PostAuthorize
SPEL 表达式中的 returnObject
。
可能吗?也许有人可以建议另一种方法?欢迎提出任何建议。
无法通过 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;
}
}
我有一个带有 GET 方法的 REST 控制器。它 returns 一种资源。我想通过比较 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
class是一个简单的DTO:
public class Resource {
private String ownerLogin;
// other fields, getters, setters
}
在第二个示例中,Spring 安全性会在 DeferredResult
实例中寻找 ownerLogin
字段。我希望它将异步解析的 Resource
视为 @PostAuthorize
SPEL 表达式中的 returnObject
。
可能吗?也许有人可以建议另一种方法?欢迎提出任何建议。
无法通过 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;
}
}