Spring Boot 控制用户更改对象的权限

fnvucqvd  于 2023-10-16  发布在  Spring
关注(0)|答案(2)|浏览(148)

假设有一个用户,他有一个特定的订单。用户决定“释放”它并拉取REST API句柄:

@PreAuthorize("hasRole('USER') || hasRole('ADMIN')")
@PatchMapping(path = "/setFree", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<OrderDTO> setFree(@RequestParam(name = "id") int id) {
    final var order = this.orderService.findById(id).orElseThrow(() -> new OrderNotFoundException(id));
    if (order.getStatus() == OrderStatus.FREE.getId())
        return ResponseEntity.badRequest().build();

    final var free = this.orderService.setFree(order);
    return ResponseEntity.ok(this.modelMapper.map(free, OrderDTO.class));
}

具有USER或ADMIN角色的授权用户可以访问此句柄。问题!在这种情况下,什么可以阻止具有USER角色的用户为其他用户发布订单?如何验证这一点?因此,用户可以更改对象的状态,只有那些“允许”他或与他有关的?将当前用户置于安全上下文中,检查他的"SpringSecurityHolder"#getId() == order#getUserId();?但这太原始了。如何正确地执行这种验证?

x6492ojm

x6492ojm1#

我相信当你说这太原始时,你的意思是解决方案在设计上没有很好的抽象和优雅。
如果这就是问题所在,为了使它更优雅,您可以遵循以下方法
1.在项目中定义AutoriationService。
1.您可以定义特定方法来验证此特定方法(getOrder)的身份验证。方法名称可以是- authenticationForToGetOrderAPI。
1.您可以定义此方法的自定义实现。自定义实现可以是“SpringSecurityHolder”#getId()== order#getUserId()"。
1.您可以使用SprintSecurity注解@PreAuthorize将此方法附加到getOrder API调用之上。@PreAuthorize注解在输入方法之前检查给定的表达式。
有关@PreAuthorize的更多详细信息,请查看此处-发现此链接对Spring Security Features很有帮助-https://www.baeldung.com/spring-security-method-security

0s7z1bwu

0s7z1bwu2#

@PreAuthorize允许你使用SpEL来引用执行授权检查的bean方法。所以你可以定义一个bean来进行这样的检查:

@Service
public class AuthzService {

    public boolean isAllowFreeOrder(int orderId){
       
      //access the order and current user information for the authorisation check
      //return true if it is allow. otherwise , return false
    }  
}

在此方法中,您可以从存储库中获取订单并检查其所需的状态。要获取当前用户信息,以下是一些代码片段,您可能会发现它们很有用:

Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
User currentUser =  (User) currentUser.getPrincipal();

List<GrantedAuthority> userRoles =  = currentUser.getAuthorities()
boolean hasUserRole =  userRoles.stream().map(GrantedAuthority::getAuthority).anyMatch(a->a.equals("ROLE_USER"));
boolean hasAdminRole =  userRoles.stream().map(GrantedAuthority::getAuthority).anyMatch(a->a.equals("ROLE_ADMIN"));

我假设您使用默认的Spring Security User对象来表示当前经过身份验证的用户。
最后配置@PreAuthorize使用此方法进行检查:

@PreAuthorize("@authzService.isAllowFreeOrder(#id)")
@PatchMapping(path = "/setFree")
public ResponseEntity<OrderDTO> setFree(int id) {
   
}

相关问题