当 SpEL 表达式从属性文件注入时,Spring 是否可以评估它们中的所有字符/表达式? [英] Can Spring evaluate all characters/expressions in SpEL expressions as they are injected from a property file?

查看:34
本文介绍了当 SpEL 表达式从属性文件注入时,Spring 是否可以评估它们中的所有字符/表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I wonder why spring doesn't directly evaluate all expressions as they are injected from a property file into @PreAuthorize(...) annotation. I think spring doesn't evaluate some characters like '(', ')', ''', etc or it adds special characters on top of those injected values from property file. To clarify, let us consider the following example.

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

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

The above expression is normal, and works fine. Suppose values of the property file are the following.

role1=ROLE_ADMIN
role2='ROLE_ADMIN'
role3=hasRole('ROLE_ADMIN')

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

  1. Let us inject role1 from property file and pass it to @PreAuthorize("hasRole(${role1})"), it works fine. In normal way of evaluating hasRole(...) expression, the role name must be under single quotes, i.e, 'ROLE_ADMIN'. But here it works with ROLE_ADMIN. Surprising!.

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

If we inject role2 from property file into @PreAuthorize("hasRole(${role2})"), it returns access denied. That means it is evaluated but we can realise that the value passed to the expression is something other than "'ROLE_ADMIN'". So, if the role name is under single quotes, access is denied. Another surprise!.

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

If we try to inject role3 from a property file into @PreAuthorize("${role3}"), it is not being evaluated as well. exceptions:

  • java.lang.IllegalArgumentException:无法评估表达式role3",根本原因是:
  • org.springframework.expression.spel.SpelEvaluationException: EL1001E:(pos 0): 类型转换问题,无法从 java.lang.String 转换为 java.lang.Boolean
  • java.lang.IllegalArgumentException: 无效的布尔值 'hasRole('ROLE_ADMIN')'
  • java.lang.IllegalArgumentException: Failed to evaluate expression 'role3' with root causes:
  • 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) 将不起作用.这只是我的结论!.

From (1) and (2) above, we may realise one thing. That is, it seems that injected values are placed under single quotes (' ') when being passed to the @PreAuthorize(...) annotation. If this statement is not true, (1) and (2) wouldn't be working. Its just my conclusion!.

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

When we come to (3), the case seems similar to (1) and (2). The value in the file is "hasRole('ROLE_ADMIN')". After injecting this value correctly, if single quotes are added while passing to the @PreAuthorize(...), it will be like @PreAuthorize("'hasRole('ROLE_ADMIN')'"). So "'hasRole('ROLE_ADMIN')'" is a string not a boolean value. Its just my suspect.

问题:

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

Do you think that my conclusion is correct? if not, can you point out me if there is something that I've missed? Or provide me if you have alternative solutions to achieve @PreAuthorize(...) by injecting values from property file.

先谢谢你!

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

Note: it is neither a problem of configuration nor injection. I checked that the values are correctly injected.

推荐答案

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

The key to the answer is the way of how the the String literals are represented in SpEL. The following are valid:

  • SpEL 中的字符串文字用单引号表示,例如 'Hello' 是一个 SpEL 字符串文字.
  • 资源包中的所有值都转换为字符串字面量,这意味着:
    • 如果您从 Java 中的包中获取 HELLO,您将收到一个 "HELLO" 字符串文字.
    • 如果您从 SpEL 中的包中获取 HELLO,您将收到一个 'HELLO' 字符串文字.
    • The String literals in SpEL are presented with single quotes, e.g 'Hello' is a SpEL String literal.
    • All the values from a resource bundle are converted to String literals, which means that:
      • If you fetch a HELLO from a bundle in Java, you will receive a "HELLO" String literal.
      • If you fetch a HELLO from a bundle in SpEL, you will receive a 'HELLO' String literal.

      现在让我们看看上面的例子.

      Now let's take a look on the example you have above.

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

      1. In your first case, you have role1=ROLE_ADMIN in the resource bundle, which means that a 'ROLE_ADMIN' String literal will be created when evaluating ${role1}. This will result in @PreAuthorize("hasRole('ROLE_ADMIN')") annotation which is perfectly valid (if you have a ROLE_ADMIN role defined). That's why it's working and it is not surprising.

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

      In the second case, you have role2='ROLE_ADMIN' in the resource bundle, which means that a '''ROLE_ADMIN''' String literal will be created when the ${role2} is evaluated. Note that the ' sign is escaped by putting two ' characters. You receive an Access Denied error, simply because you don't have a 'ROLE_ADMIN' role, but ROLE_ADMIN (which is different).

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

    • Your third guess is almost correct. The only thing you're not correct about is how the annotation would look like afted evaluating the #{role3} value in the resource bundle. As I mentioned, the ' is escaped in SpEL by putting two ' characters. Therefore, the annotation would look like @PreAuthorize("'hasRole('''ROLE_ADMIN''')'"). You're completely correct in your assumption that this is a String, not a Boolean expression and this is why the IllegalArgumentException is thrown.

      这篇关于当 SpEL 表达式从属性文件注入时,Spring 是否可以评估它们中的所有字符/表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆