在Spring中保护REST资源的更好方法是什么?

时间:2017-11-13 05:07:40

标签: java spring rest spring-security

我有一个RESTful服务,可以公开/user/{id}

等资源

现在,用户可以提供凭据,获取令牌并访问资源。但是,经过身份验证后,用户可以访问任何id的资源。

意思是,user1可以访问/user/1以及user/2之类的URI,依此类推。我最终在控制器方法中使用了Principal,并开始使用用户尝试访问的id检查Principal的{​​{1}}。

此外,用户具有与其相关联的多个资源。比如说,user1拥有res1和res2,user2拥有res3和res4。这些可以通过id访问。我需要一种可以阻止/user/1/res/2的方法,因为res3归user1所有,而不是user2。

但我相信这个问题非常普遍,而且我并不相信我的解决方案。

有没有更好的方法来解决这个问题?

由于

3 个答案:

答案 0 :(得分:3)

如果所有用户都可以访问,则不应该公开资源/user/{id},只能访问自己的ID。 如果我理解正确,只需公开/user就足够了,从Principal或session等找到用户的ID并返回结果。

如果你真的想这样做,你可以自定义实现@PreAuthorize。从博客获得此代码。

@PreAuthorize("isUsersRes(#id)")
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
public UsersfindById(@PathVariable long id) {
return Users.findOne(id);
}

公共类CustomMethodSecurityExpressionRoot   extends SecurityExpressionRoot实现了MethodSecurityExpressionOperations {

public CustomMethodSecurityExpressionRoot(Authentication authentication) {
    super(authentication);
}

并实施isUsersRes

public class CustomMethodSecurityExpressionRoot 
extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
public boolean isMember(Long OrganizationId) {
 //user logic
}

检查完整博客here

答案 1 :(得分:1)

这是各种解决方案的常见问题。此外,它不仅仅与REST有关。自应用程序存在以来,我们就已经拥有了员工可以看到他的工资单,留下记录等,但不能看到其他员工。 我最喜欢的一个解决方案是“深度安全”。这个想法来自我几十年来在银行系统中看到这项工作的方式。这需要首先在DB层中得到支持。 你需要一个像这个例子的表设计(或者你的app的实体层次结构):

Organisation
-Dept
--user

所有非主表都需要与其中一个实体有关系。例如:

Payslip -> user
Leave record -> user
Manager -> dept
HR Manager -> org

等...

您需要另一个表来映射基本访问级别(如果我们需要实现不同的子访问级别,这可能会变得复杂)

user1:dept2:org1
user2:dept2:org1

(我已经看到一些实现将此表的信息作为加密访问令牌的一部分发送,如果访问必须是无会话的,则在每个访问请求上使用。)

您尚未提及框架/语言,但大多数语言都有数据库层。例如,如果DB层是hibernate-java。有拦截器(https://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/Interceptor.html#onPrepareStatement(java.lang.String))可用于修改正在执行的查询。 对DB的每个查询都将使用这些关系键的附加where子句。 我们可以通过Spring AOP,REST拦截器以及许多其他技术在这个基本架构之上变得聪明,以实现这种安全性。 想法是DB层不返回登录用户主体无法访问的数据,而不管更高层代码使用什么查询。 如果有这个,那就是对

的REST GET调用
  

/工资单/ USER1 / JAN-2017

最终会得到404而不是403。 期望通过一个框架或一组表面的拦截器来解决这个问题既有风险又有前途。随着网址模式的发展,我们最终不断调整拦截器。

添加show table示例:

ACL table
user, uid, dept, org
--------------------
jhon, 1  , 1   , 1
mary, 2  , 2   , 1
will, 3  , 2   , 1

Payslip table
--------------
month, net, deductions,..., uid
-------------------------------------
Jan  , 200, 15.5      ,..., 3  
Feb  , 200, 15.5      ,..., 3

Project table
-------------
pname, pstart, pbudget, dept
------------------------------------
mark1, 12/21 , 20000  , 2
markx, 12/31 , 40000  , 2

答案 2 :(得分:0)

您想要的是用户角色和权限+跨用户控制。要查找用户角色和权限,请参阅this

另外,您可能还想将其用户ID交叉检查到资源ID。由于您不能让user1的资源ID 1被user2查看,因此您需要将userID作为资源ID ex: - / user / user_id_1的一部分添加。 否则,我们没有合理的方法来分隔哪些资源适用于哪些用户。