1. ホーム
  2. java

[解決済み] Spring Securityによるユニットテスト

2022-04-24 03:47:40

質問

私の会社では、次のプロジェクトでSpring MVCを使うべきかどうかを判断するために、評価を行っています。今のところ、私は見たものが大好きで、今、Spring Securityモジュールを見て、それが使えるかどうか、使うべきかどうかを判断しているところです。

私たちのセキュリティ要件はかなり基本的なもので、ユーザーはサイトの特定の部分にアクセスするためにユーザー名とパスワードを提供する必要があるだけです(自分のアカウントに関する情報を得るなど)。

私が作成したプロトタイプでは、認証されたユーザーのために、(ユーザー名とパスワードだけを含む)"LoginCredentials" オブジェクトをセッションに保存しています。いくつかのコントローラは、このオブジェクトがセッションにあるかどうかをチェックして、例えば、ログインしたユーザー名の参照を取得することができます。私はこの自前のロジックをSpring Securityに置き換えたいと考えています。そうすれば、コントローラやビジネスコードから「どうやってログインユーザーを追跡するのか?

Spring Securityは(スレッドごとに)"context"オブジェクトを提供し、アプリ内のどこからでもユーザー名/プリンシパル情報にアクセスできるようです...。

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

...このオブジェクトはある意味、(グローバルな)シングルトンなので、とてもSpringらしくないように思えますが。

もしこれがSpring Securityで認証されたユーザーに関する情報にアクセスする標準的な方法なら、ユニットテストが認証されたユーザーを必要とするときに、私のユニットテストで利用できるように、SecurityContextにAuthenticationオブジェクトを注入する受け入れられた方法は何でしょうか。

各テストケースの初期化メソッドで配線する必要があるのでしょうか?

protected void setUp() throws Exception {
    ...
    SecurityContextHolder.getContext().setAuthentication(
        new UsernamePasswordAuthenticationToken(testUser.getLogin(), testUser.getPassword()));
    ...
}

これは冗長すぎるように思います。もっと簡単な方法はないのでしょうか?

SecurityContextHolder オブジェクト自体が春らしくないような気もしますが...。

解決方法は?

問題は、Spring SecurityがAuthenticationオブジェクトをコンテナ内のBeanとして利用できないため、簡単にインジェクションやオートワイアを行う方法がないことです。

Spring Securityを使い始める前は、Principalを格納するためにコンテナ内でセッションスコープのBeanを作成し、これを"AuthenticationService"(シングルトン)にインジェクトし、このBeanを現在のPrincipalに関する知識を必要とする他のサービスにインジェクトする、という方法を取っていました。

もしあなたが独自の認証サービスを実装しているなら、基本的に同じことができます。quot;principal"プロパティを持つセッションスコープのビーンを作成し、これをあなたの認証サービスに注入します。

SecurityContextHolder.を使うのは悪くないと思うんだけどね。 Springは静的なSingletonを推奨していますが、Servletコンテナではセッション、JUnitテストではスレッドなど、環境に応じて適切に動作するような実装になっています。 シングルトンの本当の限界は、異なる環境に対して柔軟性のない実装を提供してしまうことです。