3

@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)から、1つのことがわかるかもしれません。つまり、注入された値は、@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のバンドルからをフェッチすると、文字列リテラルが返されます。"HELLO"
    • SpELHELLOのバンドルからをフェッチすると、文字列リテラルが返されます。'HELLO'

それでは、上記の例を見てみましょう。

  1. 最初のケースでrole1=ROLE_ADMINは、リソース バンドルに含まれています。これは'ROLE_ADMIN'、評価時に文字列リテラルが作成されることを意味し${role1}ます。これにより、@PreAuthorize("hasRole('ROLE_ADMIN')")完全に有効な注釈が得られます (ROLE_ADMIN ロールが定義されている場合)。それが機能している理由であり、驚くべきことではありません。

  2. 2 番目のケースでrole2='ROLE_ADMIN'は、リソース バンドルに含まれています。これは、が評価さ'''ROLE_ADMIN'''れるときに文字列リテラルが作成されることを意味します。記号は 2文字入れることでエスケープされること${role2}に注意してください。ロールを持っていないという理由だけで、Access Denied エラーが表示されますが(これは異なります)。'''ROLE_ADMIN'ROLE_ADMIN

  3. 3 番目の推測はほぼ正しいです。あなたが正しくない唯一のことは#{role3}、リソースバンドルの値を評価した後、注釈がどのように見えるかです。前述したように、'SpEL では 2'文字を入れることでエスケープされます。したがって、注釈は のようになります@PreAuthorize("'hasRole('''ROLE_ADMIN''')'")Stringこれは式ではなく であり、これががスローされるBoolean理由であるというあなたの仮定は完全に正しいです。IllegalArgumentException

于 2013-11-07T13:41:53.980 に答える