当前位置: 首页 > 知识库问答 >
问题:

如何在spring security中解释hasPermission?

蓟俊杰
2023-03-14

我是Spring Security的新手。我该如何解释?

 @PreAuthorize("hasPermission(null, 'opetussuunnitelma', 'LUONTI')")
     OpetussuunnitelmaDto addOpetussuunnitelma(OpetussuunnitelmaDto opetussuunnitelmaDto);

将调用权限评估器中的哪个方法?我认为在这种情况下将调用具有三个参数的方法。它正在检查当前用户是否对类型为“opetussuunnitelma”的目标拥有“LUONTI”权限。我说得对吗?我们不能不包含“null”并只传递两个参数吗?我读到第一个参数(身份验证对象)没有提供。

+public class PermissionEvaluator implements org.springframework.security.access.PermissionEvaluator {
+
+    @Override
+    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
+        LOG.error(" *** ei toteutettu *** ");
+        return true;
+    }
+
+    @Override
+    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
+        LOG.error(" *** ei toteutettu *** ");
+        return true;
+    }
+
+    private static final Logger LOG = LoggerFactory.getLogger(PermissionEvaluator.class);
+}

共有2个答案

姬存
2023-03-14

这个答案已经触及了OP真正想问的问题的核心。我将用hasPermission表达式稍微深入地探究幕后发生的事情,以补充这个答案。

让我们首先回顾一下这个答案。回答者发现OP实际上是在使用带有两个参数的注释:

@PreAuthorize("hasPermission(#opetussuunnitelmaDto, 'LUONTI')")

混乱的出现是因为OP在代码中看到了一个方法hasPertion,该方法包含三个参数,并且不知道第一个参数应该传递什么。回答者确认Spring框架本身提供了第一个参数,即验证对象,所以在注释中我们只需要传递两个参数

为了更详细地了解发生了什么,让我们分析一下hasPermission在Spring OOTB中是如何工作的。我不会详细讲述每一个细节,但会勾勒出正在发生的事情的主要流程。希望这不仅能像OP所要求的那样,揭示哪个重载方法与hasPermissionSpEL表达式相链接,还能揭示整个ACL框架如何在引擎盖下解释hasPermission表达式;这将使我们对hasPermission表达式的含义,以及如何解释和使用它有更大的信心。

所以让我们从头开始。

要理解hasPermission表达式,我们真的需要理解预授权/后授权。然而,由于OP没有询问这一点,因此假设它是已知的,我不会通过@PreAuthorize@PostAuthorize注释详细介绍方法保护。读者可在此查阅更多信息。这里只需说明一下,我们将假定hasPermission表达式嵌入这样的注释中,以保护方法或返回对象。hasPermission表达式将依次计算为true或false。如果计算结果为true,Spring框架将允许在预授权的情况下继续方法调用,或者在后授权的情况下允许返回对象。否则,它将阻止访问。这些注释就够了。我们真正想知道的是Spring如何解释hasPermission表达式本身,从而得出真/假值。

所以,hasPertion将评估为true或false。但是如何评估呢?正如OP所暗示的,Spring将权限评估委托给嵌套在metodSecurityExpressionHandlerBean中的PermissionEvalator对象。如果您已经设置了Spring ACL,那么您可能已经注册了AclPermissionEvalator作为Spring要使用的权限评估器。例如,如果您使用代码配置Spring ACL,您可能会有这样的内容:

@Bean
public MethodSecurityExpressionHandler 
  defaultMethodSecurityExpressionHandler() {
    DefaultMethodSecurityExpressionHandler expressionHandler
      = new DefaultMethodSecurityExpressionHandler();
    AclPermissionEvaluator permissionEvaluator 
      = new AclPermissionEvaluator(aclService());
    expressionHandler.setPermissionEvaluator(permissionEvaluator);
    return expressionHandler;
}

如果您没有这样做,默认的权限评估器应该是DenyAllPermissionEvalator,我相信您已经猜到它会在所有情况下拒绝权限:这肯定是一个安全的默认值。

因此,如上所述,将AclPermissionEvaluator类插入Spring Security框架后,Spring表达式语言(SpEL)中的所有hasPermission表达式都将委托给AclPermissionEvaluator进行评估。我还没有研究SpEL表达式最终如何导致调用AclPermissionEvaluator中的方法的确切细节,但我认为不需要这些知识来解释hasPermission表达式的含义。在我看来,在这个层次上,只需要知道哪个注释会导致哪个方法调用。这个答案已经涵盖了这一点。但让我在这里重述一下。首先,我们注意到,hasPermission方法在AclPermissionEvaluator中被重载,实际上在PermissionEvaluator的任何实现中也是如此。其中一个方法使用3个参数,另一个方法使用4个参数:

//3-Arg-Method
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);

//4-Arg-Method
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);

另一方面,hasPertion表达式也有两个用例。其中一个传入2个参数,另一个传入3个参数。这些在这个答案中已经指出了。但是让我们在这里把它们标记为表达式,而不是方法,以免混淆两者:

hasPermission('#targetDomainObject', 'permission')    //2-arg-expression
hasPermission('targetId', 'targetType', 'permission') //3-arg-expression

我们现在可以将两者联系起来:

  1. 如果使用了//2-arg表达式,则调用//3-Arg方法
  2. 如果使用了//3-arg表达式,则调用//4-Arg方法

这些方法从哪里得到额外的参数?同样,这里已经回答了这个问题,但概括一下,Spring Security框架基于安全上下文提供的额外参数是这两种情况下的第一个参数,即身份验证参数,其名称为身份验证。我还没有研究Spring框架是如何做到这一点的,但对我来说,只要知道Spring Security性可以在这个上下文中获得身份验证对象就足够了。

好的,但是其他的论点呢?让我们接下来看看这个。为了避免这个答案变得太大,我将只关注使用//2-arg-expression并调用//3-arg-Method的情况。

如前所述,让我们只关注这个方法:

boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);

如前所述,第一个参数,身份验证对象是通过Spring Security推断出来的。我还没有研究这是如何发生的,但是我相信为了这篇文章的目的,我们需要知道的就是理解身份验证对象包含:

  1. 用户即主体例如Alice
  2. 授予该用户的所有角色,即权限,例如管理员或编辑器

在Spring ACL中,我们使用通用术语SID来指代主体(如“Alice”)或权限(如“editor”)。因此,authentication对象不仅包含一个SID,还包含一个完整的SID列表。这个列表的顺序很重要,我们将在后面看到。

hasPermission方法的其余参数通过hasPermission表达式传递。它们都被键入为对象。再次强调,为了让这篇文章简短一点,我将只关注一个用例。事实上,让我们关注OP提到的原始用例的一个稍微修改的版本:

@PreAuthorize("hasPermission(#opetussuunnitelmaDto, 'READ')")
OpetussuunnitelmaDto addOpetussuunnitelma(OpetussuunnitelmaDto opetussuunnitelmaDto);
  1. 在子表达式#opetussunnitelmadto中使用#符号是在SpEL中指定方法addopetussunnitelmadtoopetussunnitelmadto参数作为hasPermission方法的targetDomainObject传入的一种方式

因此,我们现在知道所有参数是如何提供给此方法的:

boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);

但是Object类型的参数从来没有多大用处。Spring ACL需要将这些参数转换为信息,以便从数据库中访问相关的ACL信息并进行权限检查。它通过委托给checkPermission方法来实现,该方法提取信息如下:

  1. 从身份验证对象中获得一个有序的SID列表。例如,假设用户Alice已登录,并且她拥有admin和编辑器权限。然后此列表将包含Alice、admin和编辑器的SID。存储该列表的变量是List

Spring现在拥有了执行是/否检查所需的所有信息:当前登录的用户是否有权访问此对象?它通过在PermissionGrantingStrategyBean上委托给isgrated方法来实现。默认情况下,这是通过DefaultPermissionGrantingStrategy实现的。

当我们观察这个方法时,很明显顺序对于ACL中的ACE列表和SID列表确实很重要。顺序对于权限列表也有些重要,但不那么重要——它所决定的是,如果(public*)isGranted表达式的结果评估为false,哪个权限被解释为拒绝访问的“第一”权限;据我所知,这只是用于日志记录/调试目的,以便管理员可以尝试修复最有可能首先被破坏的权限。

对于ACE和SID,顺序确实很重要,因为第一个匹配ACE和SID的优先顺序,并且不会为该权限执行其他匹配。如果匹配结果为允许,则整个isgrated函数返回true。否则,如果该权限不匹配或存在拒绝,则代码将转到下一个权限并进行尝试。通过这种方式,我们可以看到权限列表是使用OR类型的逻辑进行检查的:只有其中一个权限需要被授予isgrated才能成功。

检查给定ACE是否匹配给定权限和SID的实际逻辑是什么?SID位很简单:只需从ACE中获取SID字段并比较:ace.getSid(). equals(sid)。如果SID匹配,则调用重载的isGranted函数,该函数仅比较掩码:

protected boolean isGranted(AccessControlEntry ace, Permission p) {
    return ace.getPermission().getMask() == p.getMask();
}

在我看来,这个方法真的应该被称为isMatching,因为它应该为允许(即授予)和拒绝类型的权限返回true。它只是一个匹配函数——允许/拒绝行为存储在ace中。isgrating()字段。此外,函数名isgrated被重载*,更让人困惑。

关于为什么不使用位逻辑,也有一些困惑,但别担心,如果您愿意,您可以很容易地重写该方法,如链接问题的答案中所述。

总而言之,OP最初提出的问题是:

如何在spring security中解释hasPermission?

这个答案深入到hasPertion的机制中,以了解如何解释它。总结如下:

  1. hasPermissionSpEL表达式链接到Spring ACL中的AclPermissionEvaluator中重载的hasPermission方法之一,Spring security会自动填充Authentication对象

*有两种版本的isgrated功能。public-one确实会检查列表中的某个权限是否被授予了某个SID。在检查匹配的ACE时,受保护的一个真的应该被称为isMatching

闻人飞翼
2023-03-14

将调用权限评估器中的哪个方法?

public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) 

会接到电话。

我读到没有提供第一个参数(身份验证对象)。

它没有在注释中显式提供,而是由Spring隐式提供

@PreAuthorize("hasPermission(#opetussuunnitelmaDto, 'LUONTI')")

理想情况下,我会在执行授权之前检查它们是否经过身份验证。

@PreAuthorize("isAuthenticated() and hasPermission(#opetussuunnitelmaDto, 'LUONTI')")

更新你的评论

基本上,您可以通过以下任一方式调用PermissionEvaluator:

hasPermission('#targetDomainObject', 'permission')    // method1
hasPermission('targetId', 'targetType', 'permission') // method2

身份验证将始终由Spring提供。在您的情况下,您正在通过以下方式调用hasPertion

(null,'opetussuunnitelma','LUONTI')"

哪一个匹配method2,但传入一个空id没有意义,您要针对哪个实体进行权限检查?根据你使用@PreAuthorize的方法,

OpetussuunnitelmaDto添加Opetussuunnitelma(OpetussuunnitelmaDto OpetussuunnitelmaDto);

调用method1可能更有意义,因为您似乎有一些类似于目标域对象的东西。

 类似资料:
  • 问题内容: 为简单起见,请设想这种情况,我们有一台2位计算机,它具有一对称为r1和r2的2位寄存器,并且仅适用于立即寻址。 假设位序列 00 表示 添加 到我们的CPU中。也 01 的装置将数据移动到R 1和 10组 的装置将数据移动到R2。 因此,这台计算机和一个汇编器都有一种汇编语言,其中的示例代码将像 简而言之,当我将此代码汇编成本地语言时,文件将类似于: 上面的12位是以下代码的本机代码:

  • 我有一个Spring项目,它使用sping-oaust2和sping-Security使用LDAP身份验证提供程序进行身份验证。 在控制器中,我可以使用< code > @ AuthenticationPrincipal 注释访问当前主体的< code>UserDetails。 然而,当我使用client_credential令牌到达endpoint时,是一个,它是OAuth客户端id。sprin

  • 最近我一直在努力优化一些代码(在计算时间和所需的最大内存方面)。为了知道优化内存成本是否有潜在收益,我使用JProfiler。通常 如果它很高,我应该尝试在全球范围内降低它 如果它是尖形的,我应该尽量减少中间对象的创建 现在,我处于第二种情况,气相色谱活动图显示峰值,但都小于2%(见下图)。我应该如何理解? 默认情况下,我的理解是GC活动曲线的和/积分是用于收集数据的cpu总百分比的估计。这意味着

  • 问题内容: 我正在尝试从解释器中使用python命令执行文件。 编辑:我正在尝试使用该文件中的变量和设置,而不是调用一个单独的进程。 问题答案: 几种方法。 从外壳 从IDLE内部,按 F5 。 如果您是交互式输入,请尝试以下操作:( 仅适用于Python 2 !) 对于Python3 ,请使用:

  • 问题内容: 我很难理解Rails SQL Injections上此网站上的此部分的工作方式。 在ORDER BY子句中利用SQL注入是很棘手的,但是CASE语句可用于测试其他字段,将sort列切换为true或false。尽管可能需要执行许多查询,但攻击者可以确定该字段的值。 有人可以解释吗?他们说“将排序列切换为true或false”这一点很难理解,因为我不知道如何使攻击者揭示另一个字段的值。 问

  • 我有一个打包在ear文件中的servlet,我无法让它解析@Value注释属性。 该应用程序由两部分组成:一个封装在war文件中的servlet,然后由封装在ear文件中的不同应用程序包含。该应用程序提供了由servlet中的接口定义的类(ResourceManager)的实现,以及包含@Value注释字段的属性值的属性文件。 战争文件包含: web.xml: spring-ws.xml: spr