thymeleaf extras spring security を使ってみた

ThymeleafにSpringSecurity用のライブラリがあるということで使ってみました。

https://github.com/thymeleaf/thymeleaf-extras-springsecurity

このモジュールを追加するとThymeleafを使ってHTMLをレンダリングする際にSpringSecurityの Authentication に簡単にアクセスすることができるみたいです。Authentication はコントローラーから Model に詰め込んで渡すこともできますがコントローラーの数が増えるほど重複したコードを書く必要が出てきてしまうので、コードを簡潔にする効果が期待できそうですね。

ライブラリの追加

ライブラリはMavenリポジトリから取得できます。執筆時点での最新のバージョンを取得したら以下のようになりました。

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-security")
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
    implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity5")
}

thymeleaf-extras-springsecurity5 というのがそれですが、SpringSecurityのバージョンごとに対応したものがあるのでそれに合わせます。

使い方

ライブラリの使い方は以下のサイトで解説されています。

HTML内で使うには以下の宣言をすれば良さそう。 sec プレフィックスで機能にアクセスできるようになります。

<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

属性へのアクセス

Authentication の属性にアクセスするには以下のようにすればいいみたいです。直感的に書けますね。

<div sec:authentication="name">
  Authenticationのname値に書き換わる
</div>

nameAuthentication の属性名となるので、ここを変えてあげれば他の属性にもアクセスすることができます。例えば独自の UserDetails クラスを持っていてメールアドレスのフィールドがあるのであれば以下のようにすればいいはずです。

<div sec:authentication="mailAddress">
  Authenticationのメールアドレスの値に書き換わる
</div>

ロールへのアクセス

ユーザが保持するロールの有無で画面の表示内容を切り替えるということは多くの場面であると思いますが、以下のようにすればできるようです。

<div sec:authorize="hasRole('ROLE_ADMIN')">
  ADMINロールを持っている場合のみ表示される
</div>

sec:authorize は実際にはSpringEL式を使っているようなので hasRole 以外のメソッドも同じようにして使用できるみたいです。公式のGitHubでは以下のように許可するロールを変数として追加して動的に表示内容を切り替えるやり方が解説されていました。

<div sec:authorize="${hasRole(#vars.expectedRole)}">
  This will only be displayed if authenticated user has a role computed by the controller.
</div>

#vars というのはThymeleafの公式ドキュメントを見る限りコンテキスト変数の事なのでコントローラーから渡された値へのアクセスになるみたいですね。

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html#式基本オブジェクト

URLに基づいた制御

URLへの認可を判断して表示内容を切り替える事ができるみたいです。リンクの表示・非表示で使うと便利そうですね。

<div sec:authorize-url="/admin">
  /admin へアクセスできる場合は表示される。
</div>

メソッドを指定すればGET以外でも使用できます。

<div sec:authorize-url="POST /admin">
  /admin へPOSTリクエストを行える場合は表示される。
</div>