Java 春季保护REST资源的更好方法?

Java 春季保护REST资源的更好方法?,java,spring,rest,spring-security,Java,Spring,Rest,Spring Security,我有一个RESTful服务,它公开像/user/{id} 现在,用户可以提供凭据、获取令牌并访问资源。但是,一旦通过身份验证,用户就可以访问任何id的资源 也就是说,user1可以访问uri,比如/user/1以及user/2等等。最后,我在控制器方法中使用了主体,并开始使用用户试图访问的id检查主体的id 此外,用户具有与其关联的多个资源。比如说,user1拥有res1和res2,user2拥有res3和res4。这些可通过/user/1/res/2访问。我需要一种方法来阻止/user/1/r

我有一个RESTful服务,它公开像
/user/{id}

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

也就是说,user1可以访问uri,比如
/user/1
以及
user/2
等等。最后,我在控制器方法中使用了
主体
,并开始使用用户试图访问的
id
检查
主体
id

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

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

有没有更好的办法来处理这个问题


谢谢

如果所有用户都只能访问自己的id,那么您根本不应该公开资源
/user/{id}
。 如果我理解正确,只需公开
/user
就足够了,从主体或会话等中查找用户ID并返回结果

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

@PreAuthorize("isUsersRes(#id)")
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
public UsersfindById(@PathVariable long id) {
return Users.findOne(id);
}
公共类CustomMethodSecurityExpressionRoot 扩展SecurityExpressionRoot实现MethodSecurityExpressionOperations{

public CustomMethodSecurityExpressionRoot(Authentication authentication) {
    super(authentication);
}
isUsersRes的设计与实现

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

检查完整的博客

如果所有用户都只能访问自己的id,那么您根本不应该公开资源
/user/{id}
。 如果我理解正确,只需公开
/user
就足够了,从主体或会话等中查找用户ID并返回结果

如果你真的想这么做,你可以自定义@PreAuthorize的实现

@PreAuthorize("isUsersRes(#id)")
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
public UsersfindById(@PathVariable long id) {
return Users.findOne(id);
}
公共类CustomMethodSecurityExpressionRoot 扩展SecurityExpressionRoot实现MethodSecurityExpressionOperations{

public CustomMethodSecurityExpressionRoot(Authentication authentication) {
    super(authentication);
}
isUsersRes的设计与实现

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

查看完整的博客

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

此外,您可能还希望将其用户ID与资源ID进行交叉检查。由于无法让user2查看user1的资源ID 1,因此您需要将userID添加为资源ID的一部分,例如:-/user/user\u ID\u 1。
否则,我们没有逻辑方法来区分哪些资源适用于哪些用户。

您需要的是用户角色和权限+跨用户控制。要了解用户角色和权限,请参阅

此外,您可能还希望将其用户ID与资源ID进行交叉检查。由于无法让user2查看user1的资源ID 1,因此您需要将userID添加为资源ID的一部分,例如:-/user/user\u ID\u 1。
否则,我们就没有一种逻辑方法来区分哪些资源适用于哪些用户。

这是一个常见的问题,有各种解决方案。这也不是一个与REST无关的问题。自从应用程序存在以来,我们就有过这种情况。员工可以查看他的工资单、休假记录等,但不能查看其他员工的。 我最喜欢的一个解决方案是“深度安全”。这个想法来源于我几十年来在银行系统中看到这项工作的方式。这需要首先在数据库层得到支持。 您将需要类似于此示例的表设计(或应用程序的实体层次结构):

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

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

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

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

您没有提到框架/语言,但大多数语言都有数据库层。例如,如果数据库层是hibernate java,则可以使用拦截器()修改正在执行的查询。 对于这些关系键,对DB的每个查询都将带有额外的where子句。 我们可以利用SpringAOP、REST拦截器和许多其他技术在这个基本架构的基础上巧妙地加强这种安全性。 这个想法是,无论上层代码使用什么查询,DB层都不会返回登录用户主体无法访问的数据。 如果这是在适当的地方,休息得到呼吁

/工资单/user1/2017年1月

将以404而不是403结束。 期望通过一个框架或一组肤浅的拦截器来解决这一问题既有风险,也不是未来的证明。我们最终会随着url模式的发展不断调整拦截器

添加以显示表格示例:

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

这是一个常见的问题,解决方案多种多样。这也不是一个与REST无关的问题。自从应用程序存在以来,我们就一直存在这个问题。员工可以查看他的工资单、休假记录等,但不能查看其他员工的。 我最喜欢的一个解决方案是“深度安全”。这个想法来源于我几十年来在银行系统中看到这项工作的方式。这需要首先在数据库层得到支持。 您将需要类似于此示例的表设计(或应用程序的实体层次结构):

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

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

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

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

您没有提到框架/la