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

我想知道为什么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 :它既不是配置问题也不是注入问题。 我检查了值是否正确注入。

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

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

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

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

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

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