Tagbangers Blog

​@EnableGlobalMethodSecurity を Controller クラスで使うメモ

Spring Security で @EnableGlobalMethodSecurity を用いれば、メソッドレベルでアクセスコントールが可能になるが、Service クラスレイヤーではなく、Controller レイヤーで使用する場合はちょっと注意が必要。

Spring MVC の基本設定パターンでは、たいてい ServletMapping ごとにサブのアプリケーションコンテキストが生成され、ルートコンテキストのみに、@EnableGlobalMethodSecurity を適用してもそのままでは Controller クラスに @Secure などを指定しても動作しない。

これに関連することで Spring の FAQ に下記のように記載がある。
http://docs.spring.io/spring-security/site/docs/3....

2.16. I have added Spring Security's <global-method-security> element to my application context but if I add security annotations to my Spring MVC controller beans (Struts actions etc.) then they don't seem to have an effect.

In a Spring web application, the application context which holds the Spring MVC beans for the dispatcher servlet is often separate from the main application context. It is often defined in a file called myapp-servlet.xml, where "myapp" is the name assigned to the Spring DispatcherServlet in web.xml. An application can have multiple DispatcherServlet`s, each with its own isolated application context. The beans in these "child" contexts are not visible to the rest of the application. The"parent" application context is loaded by the `ContextLoaderListener you define in your web.xml and is visible to all the child contexts. This parent context is usually where you define your security configuration, including the <global-method-security> element). As a result any security constraints applied to methods in these web beans will not be enforced, since the beans cannot be seen from the DispatcherServlet context. You need to either move the <global-method-security> declaration to the web context or moved the beans you want secured into the main application context.

Generally we would recommend applying method security at the service layer rather than on individual web controllers.

そもそも公式には method security は Controller クラスレイヤーではなく、Service クラスレイヤーに適用するのがおすすめっぽいですが、やっぱり Controller クラスに設定できた方がしっくりくるときもある。

ということで、@EnableGlobalMethodSecurity を Controller クラスレイヤーで動作させたい場合は ServletMapping ごとのサブコンテキストに対しても設定すること。