Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
517 views
in Technique[技术] by (71.8m points)

java - Can Spring evaluate all characters/expressions in SpEL expressions as they are injected from a property file?

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. 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!.

  2. 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!.

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

    • 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')'

My conclusion:

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!.

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.

Question:

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.

Thank you in advance!

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

  • 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. 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.

  2. 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).

  3. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...