6.5. 認可¶
目次
6.5.1. Overview¶
- Web(リクエストURL)
- 特定のURLにアクセスするために必要な権限を設定できる
- 画面項目(JSP)
- 画面中の特定の要素を表示するために必要な権限を設定できる
- メソッド
- 特定のメソッドを実行するために必要な権限を設定できる
6.5.1.1. アクセス認可(リクエストURL)¶
- ユーザのリクエストに対し、Spring Securityのフィルタチェーンが割り込み処理を行う。
- 認可制御の対象となるURLとリクエストのマッチングを行い、アクセス認可マネージャにアクセス認可の判断を問い合わせる。
- アクセス認可マネージャが、ユーザの権限とアクセス認可情報をチェックし、 必要なロールが割り当てられていない場合は、アクセス拒否例外をスローする。
- 必要なロールが割り当てられている場合は、処理を継続する。
6.5.1.2. アクセス認可(JSP)¶
- JSPから生成されたサーブレットが、アクセス認可マネージャに問い合わせる。
- アクセス認可マネージャが、ユーザの権限とアクセス認可情報をチェックし、 必要なロールが割り当てられていない場合は、タグの内部を評価しない。
- 必要なロールが割り当てられている場合は、タグの内部を評価する。
6.5.1.3. アクセス認可(Method)¶
- Springコンテナがアクセス認可情報をもとに、対象のオブジェクトに対してインターセプタを生成、割り込みさせる。
- インターセプタは設定されたロールをもとにアクセス認可マネージャに問い合わせる。
- アクセス認可マネージャが、ユーザが持つ権限とアクセス認可情報をチェックし、 必要なロールが割り当てられていない場合はアクセス拒否例外をスローする。
- 必要なロールが割り当てられている場合は、処理を継続する(設定により、処理を実行した後に権限をチェックすることもできる)。
6.5.2. How to use¶
6.5.2.1. アクセス認可(リクエストURL)¶
6.5.2.1.1. <sec:intercept-url>
要素の設定¶
<sec:http>
要素の子要素である<sec:intercept-url>
要素に制御対象とするURL、認可するロールを記述することで、spring-security.xml
<sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/> <!-- omitted --> </sec:http>
属性名説明pattern
アクセス認可を行う対象のURLパターンを記述する。ワイルドカード「*」、「**」が使用できる。「*」では、同一階層のみが対象であるのに対し、「**」では、指定階層以下の全URLが、認可設定の対象となる。access
Spring EL式でのアクセス制御式や、アクセス可能なロールを指定する。method
HTTPメソッド(GETやPOST等)を指定する。指定したメソッドのみに関して、URLパターンとマッチングを行う。指定しない場合は、任意のHTTPメソッドに適用される。主にRESTを利用したWebサービスの利用時に活用できる。requires-channel
「http」、もしくは「https」を指定する。指定したプロトコルでのアクセスを強制する。指定しない場合、どちらでもアクセスできる。上記以外の属性については、<intercept-url>を参照されたい。
spring-security.xml
<sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/reserve/*" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" /> <!-- (1) --> <sec:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')" /> <!-- (2) --> <sec:intercept-url pattern="/**" access="denyAll" /> <!-- (3) --> <!-- omitted --> </sec:http>
項番説明(1)「/reserve/*」にアクセスするためには、「ROLE_USER」もしくは「ROLE_ADMIN」ロールが必要である。hasAnyRole
については、後述する。(2)「/admin/*」にアクセスするためには、「ROLE_ADMIN」ロールが必要である。hasRole
については、後述する。(3)denyAll
を全てのパターンに設定し、権限設定が記述されていないURLに対してはどのユーザもアクセス出来ない設定としている。denyAll
については、後述する。Note
URLパターンの記述順序について
クライアントからのリクエストに対して、intercept-urlで記述されているパターンに、上から順にマッチさせ、 マッチしたパターンに対してアクセス認可を行う。そのため、パターンの記述は、必ず、より限定されたパターンから記述すること。
<sec:http>
属性にuse-expressions="true"
の設定をしたことで、Spring EL式が有効になる。access
属性に記述したSpring EL式は真偽値で評価され、式が真の場合に、アクセスが認可される。spring-security.xml
<sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/> <!-- (1) --> <!-- omitted --> </sec:http>
項番 説明 (1)hasRole('ロール名')
を指定することで、ログインユーザが指定したロールを保持していれば真を返す。使用可能なExpression一覧例属性名 説明 hasRole('ロール名')
ユーザが指定したロールを保持していれば、真を返す。hasAnyRole('ロール1','ロール2')
ユーザが指定したいずれかのロールを保持していれば、真を返す。permitAll
常に真を返す。認証されていない場合も、アクセスできることに注意する。denyAll
常に偽を返す。isAnonymous()
匿名ユーザであれば、真を返す。isAuthenticated()
認証されたユーザならば、真を返す。isFullyAuthenticated()
匿名ユーザ、もしくはRememberMe機能での認証であれば、偽を返す。hasIpAddress('IPアドレス')
リクエストURL、およびJSPタグへのアクセス認可のみで、有効となる。指定のIPアドレスからのリクエストであれば、真を返す。その他、使用可能なSpring EL式は、 Common built-in expressionsを参照されたい。演算子を使用した判定も行うことができる。以下の例では、ロールと、リクエストされたIPアドレス両方に合致した場合、アクセス可能となる。spring-security.xml
<sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN') and hasIpAddress('192.168.10.1')"/> <!-- omitted --> </sec:http>
使用可能な演算子一覧演算子 説明 [式1] and [式2]
式1、式2が、どちらも真の場合に、真を返す。[式1] or [式2]
いずれかの式が、真の場合に、真を返す。![式]
式が真の場合は偽を、偽の場合は真を返す。
6.5.2.1.2. アクセス認可制御を行わないURLの設定¶
- spring-security.xml
<sec:http pattern="/css/*" security="none"/> <!-- 属性の指定順番で(1)~(2) --> <sec:http pattern="/login" security="none"/> <sec:http auto-config="true" use-expressions="true"> <!-- omitted --> </sec:http>
項番 説明 (1)pattern
属性に設定を行う対象のURLパターンを記述する。pattern
属性を記述しない場合、すべてのパターンにマッチする。 (2)security
属性にnone
を指定することで、pattern
属性に記述されたパスは、Spring Securityフィルタチェインを回避することができる。
6.5.2.1.3. URLパターンでの例外処理¶
org.springframework.security.access.AccessDeniedException
がスローされる。org.springframework.security.web.access.ExceptionTranslationFilter
に設定されたorg.springframework.security.web.access.AccessDeniedHandlerImpl
が、エラーコード403を返却する。spring-security.xml
<sec:http auto-config="true" use-expressions="true"> <!-- omitted --> <sec:access-denied-handler error-page="/accessDeneidPage" /> <!-- (1) --> </sec:http>
項番説明(1)<sec:access-denied-handler>
要素のerror-page
属性に、遷移先のパスを指定する。
6.5.2.2. アクセス認可(JSP)¶
<sec:authorize>
を利用する。<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<sec:authorize>
タグの属性一覧属性名説明access
アクセス制御式を記述する。真であれば、タグ内が評価される。url
設定したURLに対して権限が与えられている場合に、タグ内が評価される。リンクの表示の制御等に利用する。method
HTTPメソッド(GETやPOST等)を指定する。 url属性と合わせて利用し、指定したメソッドのみに関して、指定したURLパターンとマッチングを行う。指定しない場合、GETが適用される。ifAllGranted
設定したロールが全て与えられている場合に、タグ内が評価される。ロール階層機能は効かない。ifAnyGranted
設定したロールについて、いずれかが与えられている場合に、タグ内が評価される。ロール階層機能は効かない。ifNotGranted
設定されたロールが与えられていない場合、タグの中身が評価される。ロール階層機能は効かない。var
タグの評価結果を格納するpageスコープの変数を宣言する。同等の権限チェックをページ内で行う場合に利用する。
<sec:authorize>
タグの使用例を示す。spring-security.xml
<div> <sec:authorize access="hasRole('ROLE_USER')"> <!-- (1) --> <p>This screen is for ROLE_USER</p> </sec:authorize> <sec:authorize url="/admin/menu"> <!-- (2) --> <p> <a href="/admin/menu">Go to admin screen</a> </p> </sec:authorize> </div>
項番説明(1)「ROLE_USER」を持つ場合のみ、タグ内が表示される。(2)「/admin/menu」に対してアクセスが認可されている場合、タグ内が表示される。Warning
<sec:authorize>
タグによる認可処理は、画面表示の制御でしかないため、特定の権限でリンクを表示されなくても、URLが推測されれば、直接リンク先のURLにアクセスできてしまう。 そのため、必ず、前述の「アクセス認可(リクエストURL)」、もしくは、後述の「アクセス認可(Method)」を併用して、本質的な認可制御をに行うこと。
6.5.2.3. アクセス認可(Method)¶
org.springframework.security.access.prepost.PreAuthorize
アノテーションを設定すればよい。spring-security.xml
<sec:global-method-security pre-post-annotations="enabled"/> <!-- (1) -->
項番説明(1)<sec:global-method-security>
要素のpre-post-annotations
属性をenabled
に指定する。デフォルトはdisabled
である。Javaコード
@Service @Transactional public class UserServiceImpl implements UserService { // omitted @PreAuthorize("hasRole('ROLE_ADMIN')") // (1) @Override public User create(User user) { // omitted } @PreAuthorize("isAuthenticated()") @Override public User update(User user) { // omitted } }
項番説明(1)アクセス制御式を記述する。メソッドを実行する前に式が評価され、真であれば、メソッドが実行される。偽であれば、org.springframework.security.access.AccessDeniedException
がスローされる。設定可能な値は、<sec:intercept-url>要素の設定で述べたExpressionや、およびSpring Expression Language (SpEL)で記述された式である。Tip
上記の設定では
org.springframework.security.access.prepost.PreAuthorize
以外にも、以下のアノテーションを使用できる。org.springframework.security.access.prepost.PostAuthorize
org.springframework.security.access.prepost.PreFilter
org.springframework.security.access.prepost.PostFilter
これらの詳細はSpring Security マニュアルを参照されたい。
Note
Spring SecurityではJava標準であるJSR-250の
javax.annotation.security.RolesAllowed
アノテーションによる認可制御も可能であるが、@RolesAllowed
ではSpELによる記述ができない。@PreAuthorize
であればSpELを用いて、spring-security.xmlの設定と同じ記法で認可制御Note
リクエストパスに対する認可制御はControllerのメソッドにアノテーションをつけるのではなく、spring-security.xmlに設定を行うことを推奨する。
ServiceがWeb経由でしか実行されず、リクエストパスのすべてのパターンが認可制御されているのであればServiceの認可制御は行わなくても良い。 Serviceがどこから実行されるか分からず、認可制御が必要な場合にアノテーションを使用するとよい。
6.5.3. How to extend¶
6.5.3.1. ロール階層機能¶
Spring Security 設定ファイル
<sec:http auto-config="true" use-expressions="true">
<sec:intercept-url pattern="/user/*" access="hasAnyRole('ROLE_USER')" />
<!-- omitted -->
</sec:http>
6.5.3.1.1. 共通設定¶
org.springframework.security.access.hierarchicalroles.RoleHierarchy
クラスのBean定義を行う。spring-security.xml
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl"> <!-- (1) --> <property name="hierarchy"> <value> <!-- (2) --> ROLE_ADMIN > ROLE_STAFF ROLE_STAFF > ROLE_USER </value> </property> </bean>
項番説明(1)RoleHierarchy
のデフォルトorg.springframework.security.access.hierarchicalroles.RoleHierarchyImpl
クラスを指定する。(2)hierarchy
プロパティに階層関係を定義する。書式:[上位ロール] > [下位ロール]例では、STAFFはUSERに認可されたすべてのリソースに、アクセスできる。ADMINはUSER、STAFFに認可されたすべてのリソースに、アクセスできる。
6.5.3.1.2. アクセス認可(リクエストURL)、アクセス認可(JSP)での使用方法¶
spring-security.xml
<bean id="webExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"> <!-- (1) --> <property name="roleHierarchy" ref="roleHierarchy"/> <!-- (2) --> </bean> <sec:http auto-config="true" use-expression="true"> <!-- omitted --> <sec:expression-handler ref="webExpressionHandler" /> <!-- (3) --> </sec:http>
項番説明(1)クラスにorg.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
を指定する。(2)roleHierarchy
プロパティにRoleHierarchy
のBean IDをプロパティに設定する。(3)expression-handler
要素に、org.springframework.security.access.expression.SecurityExpressionHandler
を実装したハンドラクラスのBean IDを指定する。
6.5.3.1.3. アクセス認可(Method)での使用方法¶
spring-security.xml
<bean id="methodExpressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"> <!-- (1) --> <property name="roleHierarchy" ref="roleHierarchy"/> <!-- (2) --> </bean> <sec:global-method-security pre-post-annotations="enabled"> <sec:expression-handler ref="methodExpressionHandler" /> <!-- (3) --> </sec:global-method-security>
項番説明(1)クラスにorg.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler
を指定する。(2)roleHierarchy
プロパティにRoleHierarchy
のBean IDをプロパティに設定する。(3)expression-handler
要素に、org.springframework.security.access.expression.SecurityExpressionHandler
を実装したハンドラクラスのBean IDを指定する。