确保 AUTHENTICATED 用户被授权访问资源的最佳实践 - Spring mvc、Spring Security、Hibernate
Posted
技术标签:
【中文标题】确保 AUTHENTICATED 用户被授权访问资源的最佳实践 - Spring mvc、Spring Security、Hibernate【英文标题】:Best practice to make sure an AUTHENTICATED user is AUTHORISED to access a resource - Spring mvc, Spring Security, Hibernate 【发布时间】:2016-06-18 08:52:10 【问题描述】:我们有一个spring mvc rest api,利用spring security和hibernate到一个mysql db。
我们配置了一些角色。例如:
标准用户:ROLEA
超级用户:ROLEB
目前为了确保经过身份验证的用户被授权访问/更新某个资源,我们执行以下操作:
识别当前经过身份验证的用户:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String activeLogin = authentication.getName();
识别与他们尝试访问的实体关联的登录名:
String loginAssociatedToRequestedEntity = fooService.getEntityA(EntityAId).getEntityB().getEntityC().getLogin();
将与给定资源关联的用户与活动登录进行比较:
if (!loginAssociatedToRequestedEntity.equals(activeLogin))
throw new ForbiddenAccessException();
我对此有很多问题,其中一些包括:
非常浪费……每个实体都必须被水合/填充。如果要访问的实体离登录名所在的表更远,这可能比上面的示例更糟糕。 看起来像代码味道(得墨忒耳法则)。 一个请求可能会更新多个实体。可能需要重复与上述类似的检查。我考虑过以下可能的选择:
Spring ACLs
Apache shiro
所以我的问题是,是否有一种最佳做法来确保经过身份验证的用户被授权访问某个资源,即阻止他们访问另一个用户的资源同样的角色。
如果你能指出一个具体的例子(github),将不胜感激。
TIA。
【问题讨论】:
【参考方案1】:您可以使用 Spring Data JPA 将 Spring Security 主体信息添加到您的 SQL 查询中。示例:
https://github.com/spring-projects/spring-data-examples/blob/master/jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java
您还可以使用具有行安全性的数据库,如 PostgreSQL 9.5、Oracle VPD 或 SQL Server 2016
【讨论】:
感谢 Neil,我们目前没有使用 Spring Data,但如果我们将来采用,我会考虑这一点。【参考方案2】:虽然角色成员资格检查在某种程度上是一种反模式(最好对权限或活动进行编码),但它们通常用于服务级别访问控制(Web 请求和方法调用),但根本不是适合在多租户设置中保护实际域对象,例如防止用户访问具有相同角色的其他用户的资源。
您检查经过身份验证的登录是否与特定域对象相关联的方法可行,但它很麻烦,会将您的应用程序数据模型与安全数据模型耦合和/或污染,并且正如您所怀疑的那样,这不是最佳实践.
您已经确定了一些选项:
Apache Shiro 提供了支持域对象访问控制的一致且易于使用的 API,但您负责提供后端“领域”,这意味着您可能必须实现您的拥有自己的数据存储和/或 DAO。
Spring Security ACLs 是 Spring 用于保护域对象的访问控制范例。它将安全数据模型与您的应用程序数据模型分离。访问控制列表可以通过添加或查找 ACL 条目轻松地授予或检查对域对象的访问权限,但如果您想有效地找到用户有权访问的所有域对象(例如,呈现那些列表中的对象或撤销对它们的访问)。此外,您有责任维护 ACL,因为:
Spring Security 不提供任何特殊集成来自动创建、更新或删除 ACL,作为 DAO 或存储库操作的一部分。相反,您需要为您的各个域对象编写代码 [...]。值得考虑在您的服务层上使用 AOP 以自动将 ACL 信息与您的服务层操作集成。
——Spring Security 4.0 reference
最后,如果默认 API 与您的应用程序模型不兼容(例如,如果您的域对象没有公共 getId()
或不使用与 @ 兼容的 ID,则您必须自定义 ACL 实现987654326@)
如果您没有与 Spring 或 Shiro 结婚以提供域对象访问控制,那么还有另一种选择:
OACC,一个开源 Java 安全框架(披露:我是维护者和共同作者),它为 enforce 和管理您的授权需求。 OACC 是一个完整的访问控制框架,具有丰富的 API,无需任何 DIY 实现即可实现细粒度授权的编程和动态建模。它的安全模型具有完全实现的 RDBMS 支持的数据存储,API 在幕后为您管理。
OACC 的安全模型是基于权限的:它本质上管理资源 之间的权限。资源既代表受保护的域对象,也代表它们上的参与者(即主体)。它还提供高效的查询方法,通过权限查找资源,无需先加载所有资源,然后过滤掉未经授权的资源。这些方法是对称的,您既可以找到指定资源对其具有特定权限集的资源,也可以找到对指定资源具有特定权限集的资源
将下面授予权限的 OACC 片段与sample code from the Spring Security ACL reference 进行比较:
// get the resource representing the principal that we want to grant permissions to
User accessorUser = Users.findByName("Samantha");
Resource accessorResource = Resources.getInstance(accessorUser.getId());
// get the resource representing the object that we want to grant permissions to
Resource accessedResource = Resources.getInstance(Foos.findById(44).getId());
// Now grant some permissions
Permission permission = ResourcePermissions.getInstance("ADMINISTER");
oacc.grantResourcePermissions(accessorResource,
accessedResource,
permission);
要检查授权,您可以调用
oacc.assertResourcePermissions(accessorResource, accessedResource, permission);
或检查返回值
oacc.hasResourcePermissions(accessorResource, accessedResource, permission);
OACC 的另一个新特性是 create-permissions,它不仅可以控制主体可以创建什么样的资源,还可以准确定义他们在新资源上获得的权限创建它 - 定义一次,权限会自动分配给资源创建者,无需显式 API 调用。
总之,OACC 是专门针对您经过身份验证的细粒度授权的用例而开发的。
【讨论】:
只是想感谢您的回答。我还没有彻底了解 oacc 〜我确实有点卡在入门指南上...... 如果您需要任何帮助或澄清,请随时在此处或 OACC 的 mailing list 上发布问题以上是关于确保 AUTHENTICATED 用户被授权访问资源的最佳实践 - Spring mvc、Spring Security、Hibernate的主要内容,如果未能解决你的问题,请参考以下文章
java mockmvc test以确保用户被重定向到授权页面
2019-2020-1 20191232 《信息安全专业导论》第十二周学习总结