SpringのPreAuthorizeアノテーションを次のように使用しています。
@PreAuthorize("hasRole('role')");
ただし、別のクラスの静的文字列として「ロール」がすでに定義されています。この値を使おうとすると:
@PreAuthorize("hasRole(OtherClass.ROLE)");
エラーが発生します:
org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 14): Field or property 'OtherClass' cannot be found on object of type 'org.springframework.security.access.expression.method.MethodSecurityExpressionRoot'
PreAuthorizeアノテーションを使用してこのような静的変数にアクセスする方法はありますか?
Spring式言語を使用して型を評価する以下を試してください。
@PreAuthorize("hasRole(T(fully.qualified.OtherClass).ROLE)");
必ず完全修飾クラス名を指定してください。
パッケージ名なしで式を記述できるようにするには:
<sec:global-method-security>
<sec:expression-handler ref="methodSecurityExpressionHandler"/>
</sec:global-method-security>
<bean id="methodSecurityExpressionHandler" class="my.example.DefaultMethodSecurityExpressionHandler"/>
次に、DefaultMethodSecurityExpressionHandlerを拡張します。
public class DefaultMethodSecurityExpressionHandler extends org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler {
@Override
public StandardEvaluationContext createEvaluationContextInternal(final Authentication auth, final MethodInvocation mi) {
StandardEvaluationContext standardEvaluationContext = super.createEvaluationContextInternal(auth, mi);
((StandardTypeLocator) standardEvaluationContext.getTypeLocator()).registerImport("my.example");
return standardEvaluationContext;
}
}
次に、my.example.Roles.Javaを作成します。
public class Roles {
public static final String ROLE_UNAUTHENTICATED = "ROLE_UNAUTHENTICATED";
public static final String ROLE_AUTHENTICATED = "ROLE_AUTHENTICATED";
}
そして、注釈でパッケージ名なしでそれを参照してください:
@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATED)")
の代わりに:
@PreAuthorize("hasRole(T(my.example.Roles).ROLE_AUTHENTICATED)")
読みやすくします。また、役割も入力されるようになりました。書く:
@PreAuthorize("hasRole(T(Roles).ROLE_AUTHENTICATEDDDD)")
次のように書いた場合には発生しなかった起動エラーが発生します。
@PreAuthorize("hasRole('ROLE_AUTHENTICATEDDDD')")
Kevin Bowersoxから受け入れられた回答は機能しますが、T(fully.qualified.path)のものが気に入らなかったので、探し続けました。回答を使用してカスタムセキュリティメソッドを作成することから始めました。ジェームズワトキンスからここに:
Springセキュリティ式言語アノテーションで使用するカスタムメソッドを作成する方法
ただし、Stringの代わりに、enums.Permissionsクラスをパラメータータイプとして使用しました。
@Component
public class MySecurityService {
public boolean hasPermission(enums.Permissions permission) {
...do some work here...
return true;
}
}
ここで重要なのは、アノテーションからhasPermissionを呼び出すときに、パス全体を入力する必要はありませんが、一重引用符で囲む必要があるということです。
@PreAuthorize("@mySecurityService.hasPermission('SOME_ROLE_NAME')")
HasPermissionメソッドはEnumを予期しているため、その名前のEnum値を自動的に検索します。見つからない場合は、例外が発生します。
org.springframework.expression.spel.SpelEvaluationException: Type conversion problem, cannot convert from Java.lang.String to enums.Permissions
HasPermissionの名前をhasRoleに変更できます。この場合、唯一のトレードオフは、@ mySecurityServiceと追加のT(fully.qualified.path))をトレードすることです。一重引用符。
それがもっと良いかどうかはわかりませんが、あります。いずれにせよ、コンパイル時に値を検証することはないので、次のステップは注釈プロセッサを作成することです。
また、春は自動的に列挙型に変換できることを指摘したkrosenvoldの功績も認めなければなりません: https://stackoverflow.com/a/516899/618881
次のようなものを試してください。
_@PreAuthorize("hasRole(T(com.company.enumpackage.OtherClass).ROLE.name())");
_
OtherClass列挙型がpublicstaticとして宣言されている場合は、$記号を使用する必要があります。
_@PreAuthorize("hasRole(T(com.company.ParentTopLevelClass$OtherClass).ROLE.name())");
_
name()
が後でオーバーライドされる場合に、今後の問題を防ぐためにtoString()