Spring可以评估SpEL表达式中的所有字符/表达式,因为它们是从属性文件中注入的吗?

时间:2013-11-07 12:47:11

标签: java spring spring-security annotations spring-el

我想知道为什么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')'
  4. 我的结论:

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

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

    问题:

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

    提前谢谢!

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

1 个答案:

答案 0 :(得分:3)

答案的关键是如何在SpEL中表示字符串文字。以下是有效的:

  • SpEL中的字符串文字用单引号表示,例如'Hello'是SpEL字符串文字。
  • 资源包中的所有值都将转换为字符串文字,这意味着:
    • 如果您从 Java 中的捆绑中获取HELLO,您将收到"HELLO"字符串文字。
    • 如果您从 SpEL 中的捆绑中获取HELLO,您将收到'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被抛出的原因。