使用Spring(Java)的数据模型和REST控制器的多租户权限模型

使用Spring(Java)的数据模型和REST控制器的多租户权限模型,java,spring,rest,spring-data-jpa,Java,Spring,Rest,Spring Data Jpa,我正在寻找RESTful web服务的多租户权限模型和后端数据模型的示例。我使用Spring在Java中构建了OAUTH AS和RESTful web服务。大部分后端已经完成,但现在我正在构建安全性。我需要的是用户对不同对象拥有不同权限的能力。为了论证起见,假设有一些公司包含帐户。经过身份验证的用户可以拥有以下任何权限: 超级用户-所有内容的完全权限 公司管理权-对一个或多个公司的各种财产和该公司内的账户的权利 帐户权限-对公司中一个或多个帐户的权限 例如,Alice可以是超级管理员。Bob

我正在寻找RESTful web服务的多租户权限模型和后端数据模型的示例。我使用Spring在Java中构建了OAUTH AS和RESTful web服务。大部分后端已经完成,但现在我正在构建安全性。我需要的是用户对不同对象拥有不同权限的能力。为了论证起见,假设有一些公司包含帐户。经过身份验证的用户可以拥有以下任何权限:

  • 超级用户-所有内容的完全权限
  • 公司管理权-对一个或多个公司的各种财产和该公司内的账户的权利
  • 帐户权限-对公司中一个或多个帐户的权限
例如,Alice可以是超级管理员。Bob可以只拥有ACME-USER1的帐户权限,但拥有INITECH和该公司所有帐户的公司管理权限。Bill只是拥有INITECH-USER2用户权限的最终用户

最初,这个概念将应用于REST控制器。我的web服务如下所示:

  • 发布/公司->创建公司->超级用户
  • 获取/company/{id}->获取公司->该公司的超级用户和公司管理员
  • POST/company/{id}/account->Create account in company->该公司的超级用户和公司管理员
  • 获取/company/{id}/account/{acctid}->获取帐户->超级用户、公司管理员和该用户
这一概念也将扩展到数据模型。公司应具有以下属性,并要求具有以下权限才能修改每个属性:

  • 名称->超级管理员
  • 联系\u name->company admin
  • 联系\u电子邮件->公司管理员
  • max_帐户-超级管理员
用户模型如下所示:

  • 名称->用户
  • 电子邮件->用户
  • 启用->公司管理
  • 配额->超级管理员
我已经创建了OAUTH授予的权限,例如:

  • 角色超级管理员
  • ROLE_COMPANYADMIN-ACME
  • ROLE_COMPANYADMIN-INITECH
  • 角色\u USERADMIN-ACME-USER1
  • 角色\u USERADMIN-ACME-USER2
由于角色不是静态的,我不相信我能够在Java中使用诸如@Secured或@PreAuthorize之类的注释。我编写了一个方法,该方法将主体、公司和用户作为参数,然后生成所需的角色,并检查用户是否拥有该角色。我不确定这是否是最佳实践,或者是否有一种“Spring-y”的方法来做到这一点。如前所述,我还希望将此应用于我的数据模型。我不希望必须将实体拆分为多个数据传输对象,并使用其自己的REST控制器来评估权限

我还了解了他们在哪里拥有包含特权的角色。我喜欢这个模型,因为我会创建粒度权限,比如创建公司或编辑配额。然后必须将这些应用于特定对象


任何实现类似于此的项目示例或关于最佳实践的一般想法都将不胜感激。

在Spring SpEL中,您可以收到上下文中任何bean的参考

在这种情况下,可以使用@PreAuthorize注释。例如:

@Component("accessChecker")
public class AccessChecker {
  public boolean hasAccessToCompany(Long companyId) {
    return checkAccessRightsHere(SecurityContextHolder.getContext().getAuthentication(), companyId);
  }
}  

@Controller
public class CompanyController {
   @RequestMapping("/company/{companyId}")
   @PreAuthorize("@accessChecker.hasAccessToCompany(#companyId)")
   public CompanyDto getCompany(@PathVariable("comapanyId") Long companyId) {

   }
}

在SpringSpel中,您可以接收上下文中任何bean的引用

在这种情况下,可以使用@PreAuthorize注释。例如:

@Component("accessChecker")
public class AccessChecker {
  public boolean hasAccessToCompany(Long companyId) {
    return checkAccessRightsHere(SecurityContextHolder.getContext().getAuthentication(), companyId);
  }
}  

@Controller
public class CompanyController {
   @RequestMapping("/company/{companyId}")
   @PreAuthorize("@accessChecker.hasAccessToCompany(#companyId)")
   public CompanyDto getCompany(@PathVariable("comapanyId") Long companyId) {

   }
}

这无疑对控制器有帮助,但对模型/DTO的属性/字段级安全性没有帮助。@aaronanderson可能值得一看前置/后置过滤器。他们也支持SpEL。如果你提供一些代码示例,我会帮你更多。我的项目在这里。自述文件描述了我试图实现的目标。我使用预授权管理对控制器中端点的访问,并在DTO上创建了自己的ModelMapper注释(请参阅)。这对控制器肯定有帮助,但对模型/DTO的属性/字段级安全性没有帮助。@aaronanderson可能值得一看预/后过滤器。他们也支持SpEL。如果你提供一些代码示例,我会帮你更多。我的项目在这里。自述文件描述了我试图实现的目标。我使用预授权管理对控制器中端点的访问,并在DTO上创建了自己的ModelMapper注释(请参阅)。