3

我想知道为什么 spring 不直接评估所有表达式,因为它们是从属性文件注入到@PreAuthorize(...)注释中的。我认为 spring 不会评估某些字符,例如 '('、')'、''' 等,或者它会在属性文件中的注入值之上添加特殊字符。为了澄清,让我们考虑以下示例。

@PreAuthorize("hasRole('ROLE_ADMIN')")

上面的表达式是正常的,并且工作正常。假设属性文件的值如下。

role1=ROLE_ADMIN
role2='ROLE_ADMIN'
role3=hasRole('ROLE_ADMIN')
  1. 让我们从属性文件中注入role1并将其传递给@PreAuthorize("hasRole(${role1})"),它工作正常。在评估hasRole(...)表达式的正常方式中,角色名称必须用单引号括起来,即'ROLE_ADMIN'. 但在这里它适用于 ROLE_ADMIN。奇怪!。

  2. 如果我们role2从属性文件中注入@PreAuthorize("hasRole(${role2})"),它会返回拒绝访问。这意味着它已被评估,但我们可以意识到传递给表达式的值不是“ 'ROLE_ADMIN'”。因此,如果角色名称在单引号下,则拒绝访问。另一个惊喜!

  3. 如果我们尝试role3从属性文件中注入@PreAuthorize("${role3}"),它也不会被评估。例外:

    • java.lang.IllegalArgumentException: Failed to evaluate expression 'role3'根本原因:
    • org.springframework.expression.spel.SpelEvaluationException: EL1001E:(pos 0): Type conversion problem, cannot convert from java.lang.String to java.lang.Boolean
    • java.lang.IllegalArgumentException: Invalid boolean value 'hasRole('ROLE_ADMIN')'

我的结论:

从上面的(1)和(2),我们可以意识到一件事。也就是说,似乎注入的值在传递给@PreAuthorize(...)注释时放在单引号 (' ') 下。如果此陈述不正确,则 (1) 和 (2) 将不起作用。这只是我的结论!

当我们来到(3)时,情况似乎类似于(1)和(2)。文件中的值为“ hasRole('ROLE_ADMIN')”。正确注入此值后,如果在传递给 时添加单引号@PreAuthorize(...),它将像@PreAuthorize("'hasRole('ROLE_ADMIN')'"). 所以“ 'hasRole('ROLE_ADMIN')'”是一个字符串而不是一个布尔值。它只是我的嫌疑人。

问题:

你认为我的结论正确吗?如果没有,你能指出我是否有遗漏的东西吗?或者,如果您有其他解决方案可以@PreAuthorize(...)通过从属性文件中注入值来实现,请提供给我。

先感谢您!

Note: 既不是配置问题,也不是注入问题。我检查了这些值是否正确注入。

4

1 回答 1

3

答案的关键是字符串字面量在 SpEL 中的表示方式。以下是有效的:

  • SpEL 中的字符串文字用单引号表示,例如'Hello'是 SpEL 字符串文字。
  • 资源包中的所有值都转换为字符串文字,这意味着:
    • 如果您从JavaHELLO中的包中获取 a ,您将收到一个字符串文字。"HELLO"
    • 如果您从SpELHELLO中的捆绑包中获取 a ,您将收到一个字符串文字。'HELLO'

现在让我们看看你上面的例子。

  1. 在您的第一种情况下,您role1=ROLE_ADMIN在资源包中,这意味着'ROLE_ADMIN'在评估时将创建一个字符串文字${role1}。这将产生@PreAuthorize("hasRole('ROLE_ADMIN')")完全有效的注释(如果您定义了 ROLE_ADMIN 角色)。这就是它起作用的原因,这并不奇怪。

  2. 在第二种情况下,您role2='ROLE_ADMIN'在资源包中,这意味着在评估'''ROLE_ADMIN'''时将创建一个字符串文字。${role2}请注意,'符号是通过放置两个'字符来转义的。您收到拒绝访问错误,仅仅是因为您没有'ROLE_ADMIN'角色,但是ROLE_ADMIN(这是不同的)。

  3. 你的第三个猜测几乎是正确的。#{role3}您唯一不正确的是注释在评估资源包中的值之后的样子。正如我所提到的,'在 SpEL 中通过放置两个'字符进行了转义。因此,注释看起来像@PreAuthorize("'hasRole('''ROLE_ADMIN''')'"). 你的假设是完全正确的,这是一个String,而不是一个Boolean表达式,这就是IllegalArgumentException抛出的原因。

于 2013-11-07T13:41:53.980 回答