【问题标题】:rest - approaches to restrict a user to their own datarest - 将用户限制在自己的数据中的方法
【发布时间】:2020-01-25 14:31:43
【问题描述】:

我遇到了一个难题,我需要将请求的范围限制为仅针对特定用户的数据。有了一个 API,以前经过身份验证的用户可以检索数据列表,我首先需要验证请求的数据是否归请求者所有。

例如,ID 为 1 的用户只能检索所有者实际上是 ID 为 1 的数据的子集。使用先前经过身份验证的用户调用 /api/elements/{elementId} 应该只返回具有提供的元素elementId IF 提出请求的用户是其所有者或 IF 提出请求的用户具有ADMIN 角色(或任何其他授予的角色)。在任何其他情况下应返回null404 HTTP 状态。

研究了一段时间,我有了这个办法:

在每个 CRUD 操作中使用用户 ID: 这种方法强制检查当前元素是否由发出请求的用户所有。

优点:我可以保证只有该用户拥有的数据会被读取/写入

缺点:我需要在所有查询中添加用户 ID,并限制返回的数据,不包括角色为 ADMIN 的用户,他可以不受任何限制地查询所有内容。

我将 Spring Boot 与 Spring Security 和 JWT 一起用于身份验证/授权。一切正常,但是有这个限制让我想到了某种框架解决方案(如果可能的话),而不是上面评论的方法。

在这些条件下,您将如何解决这个问题来解决这个限制?

与此问题相关但没有针对我的案例的具体解决方案的链接:

提前谢谢你!

【问题讨论】:

  • 在此处查看建议:stackoverflow.com/a/37060389/1356423。您可以在方法级别应用安全性,这样查询就不会改变。每个与用户关联的实体都实现了一个返回用户的通用接口。用户与安全上下文中的用户进行比较。
  • 谢谢@alan-hay。我想我明白了,但我仍然对此有些怀疑。如果我是对的,我需要先获得结果,以便针对发出请求的用户发布检查所有者。如果满足条件,则返回结果,否则为空。但是,使用这种方法,如果结果不满足先前的条件,我仍然会完全调用数据库以最终转储结果。是否有其他解决方案可以避免先前调用数据库以满足条件或将条件添加到查询中?
  • 不去数据库你怎么能知道?对数据库的调用需要几毫秒。此外,这只是恶意使用时发生的情况。
  • 经过几次尝试后,我刚刚完成了对您的解决方法的测试,而我添加了一个小改动,以便更好地适应我的项目需求。感谢您的 POV,它帮助我了解如何继续

标签: rest api spring-boot spring-security jwt


【解决方案1】:

经过多次尝试并在@alan-hay 的帮助下,我决定采用一种解决方法,在访问特定资源之前,检查用户(已通过身份验证)是否有足够的权限访问该资源。

所以我创建了一个名为 AuthorizationService 的服务类,如下所示:

@Component
public class AuthorizationService {
    @Autowired
    private AuthenticationUser authenticationUser;

    public boolean hasAccess(Long elementId, AccessValidatorBo accessValidatorBo) {
        return accessValidatorBo.hasAccess(elementId, authenticationUser.getAuthenticatedUser());
    }
}

elementId 是试图访问的元素的 ID,accessValidatorBo 是业务对象的包装器,其中执行逻辑以确保当前用户是否可以访问前面提到的资源,authenticationUser是 Spring 安全认证用户。

因此,在控制器中,我添加了@PreAuthorize 注释,以便首先验证请求访问资源的用户是否被允许这样做。

@RestController
@RequestMapping(path = ScriptUrlDefinition.BASE)
public class ScriptController {
    @Autowired
    private ScriptBo scriptBo;
    @Autowired
    private AuthenticationUser authenticationUser;

    @GetMapping(path = ScriptUrlDefinition.GET)
    @PreAuthorize("(" + ServiceSecurityConstants.HAS_ROLE_ADMIN + " or " + ServiceSecurityConstants.HAS_ROLE_STANDARD + ") "
            + "and @authorizationService.hasAccess(#scriptId, @scriptBoImpl)")
    @ResponseBody
    public ViewScript get(@PathVariable(name = ScriptUrlDefinition.PATH_VARIABLE_ID) Long scriptId) {
        return scriptBo.getScript(scriptId);
    }
}

如果用户有访问权限,则服务返回响应;否则@PreAuthorize 注解会抛出org.springframework.security.access.AccessDeniedException 异常

【讨论】:

    猜你喜欢
    • 2021-04-16
    • 2013-09-05
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    相关资源
    最近更新 更多