基于角色的REST API?


27

我正在构建一个REST API,具有不同角色的多个用户将可以访问它所包含的资源。

为了简化范围,让我们采用“学生/教师/班级”域:

GET /students 是要访问的资源。

用户可能具有学生和/或老师之类的角色

学生将只能访问其班级的学生。老师将有机会接触所教课程的学生。一些用途可能是学生,也可能教其他课程。他们必须有权访问班级的学生和所教课程的学生。

理想情况下,我希望将其实现为两个功能-每个角色一个,如果用户具有多个角色,则“工会”。

我的问题是:我应该使用哪种模式来实现这一目标?

在外部

  • 我应该按角色划分API吗?GET /teacher/studentsGET /student/students这似乎并不合适的给我。
  • 保留所有这些,我是一种资源(首选)

内部地

应该如何在内部实施?

  • 每种方法都应该以BIG开关/如果每个角色开头吗?
  • 我应该为每个角色实现一个存储库吗?
  • 有没有一种设计模式可以帮助我实现这一目标?

附带说明一下:我正在使用ASP.NET Web APIEntity Framework 6,但这对于概念性实现来说并没有关系。


3
“这是一个很大的问题,我想知道您是否为此提供了解决方案,因为我正在尝试做类似的事情。我认为应该是这样的:首先,我们将实现一个API,该API返回所有需要的数据,那么每个客户端将不直接连接到api,而是直接连接到代理,该代理将负责根据该用户的角色过滤数据”
Cleiton

Answers:


11

您应该围绕资源而不是角色来构建API,例如:

/rest/students

任何角色允许他们看到学生的人都应该可以访问。

在内部,您正在实现基于角色的安全性。处理方式取决于应用程序的详细信息,但是假设您有一个角色表,每个人都有一个或多个角色,这些角色决定了每个人可以访问什么。您已经说明了访问学生的规则:

  • 学生可以在所参加的课程中访问学生
  • 老师可以在他们所教的课程中与学生接触

因此,当有人打电话时:

/rest/students

您调用一种方法来访问学生,并传递人的角色。这是一些伪代码:

roles = person.roles; //array
students = getStudents( roles );
return students;

通过这种方法,您可以通过单独的调用来获得每个角色的学生,例如:

factory = getFactory();
classes= [];
students = [];
for( role in roles ){
    service = factory.getService( role );
    // implementation details of how you get classes for student/teacher are hidden in the service
    classes = classes.merge( service.getClasses( person ) );
    // classes[] has class.students[]
    // loop on classes and add each student to students, or send back classes with nested students? depends on use case
  }
}

对于您可以做什么,这是一个很粗糙的想法,不一定能满足您的特定需求,但是它应该使您对所涉及的部分有所了解。如果您想返回列出的每个学生的课程,这是一个很好的方法。如果您只想要学生,则可以从每个班级中提取他们,然后将其合并为学生集合。

不可以,每个角色都不应有单独的存储库。角色所要做的就是确定如何获取数据,以及如何处理数据(例如,老师可以输入学生成绩)。数据本身是相同的。

至于模式,这种方法是使用Factory Pattern提取基于角色的获取数据的服务。按角色拥有单独的服务可能适当,也可能不合适。我喜欢这种方法,因为它可以使程序每个阶段的代码量减至最少,并使它比开关或if块更具可读性。


1
谢谢回复。我最终做了类似您建议的事情。通过使用LINQ2SQL(C#),我可以将查询传递给每个“角色”,并为用户获得的每个角色应用一个位置。结果将是对用户有权访问的每个角色都带有“ OR”条件的sql语句。如果没有为用户分配任何角色,则只需返回调用者Enumarable.Empty()即可。
卡斯珀·詹森

0

找到一支笔和一支纸,然后开始对系统进行建模。

您会发现您可能需要一个名为PERSON的域实体。由于学生和教师都是“是人”的人,因此您可以创建一个名为PERSON的抽象实体,其具有诸如名,姓等的通用属性。教师-> is-a-> Person。现在,您可以尝试查找不适用于学生的教师的特征;例如,一名老师教一个或多个主题的CLASS。

强制执行安全性被认为是应用程序的非功能性方面。这是一个跨领域的问题,应在“业务逻辑”之外进行处理。正如@Robert Munn指出的那样,所有角色都应放在一个地方。使用角色来限制对某些功能的访问是相当粗略的,该概念称为基于角色的访问控制(RBAC)。

为了验证是否应允许教师查看学生的成绩,应在您的领域模型中表达出来。假设一位老师开设了一个主题编程课程。您可能会在模型中表达学生参加不同主题的课程。这是应用程序/业务逻辑开始的地方。这是可以使用测试驱动的开发进行验证的逻辑。

应该分配资源以使您的应用程序可测试和模块化。

无论如何,真正显示我的意思的最好方法是使用代码显示它:)这是一个GitHub页面:https : //github.com/thomasandersen77/role-based-rest-api

祝好运 :)


3
您的链接已经消失了
Cleiton 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.