Spring Session - ユーザー名で検索

このガイドでは、Spring Session を使用してユーザー名でセッションを検索する方法について説明します。

前提事項

このガイドでは、組み込みの Redis 構成サポートを使用して、アプリケーションに Spring Session がすでに追加されていることを前提としています。また、このガイドでは、アプリケーションに Spring Security がすでに適用されていることを前提としています。ただし、このガイドは汎用性が高く、最小限の変更であらゆるテクノロジに適用できます。これについては、このガイドの後半で説明します。

プロジェクトに Spring Session を追加する方法を学ぶ必要がある場合は、サンプルとガイドのリストを参照してください。

サンプルについて

このサンプルでは、この機能を使用して、侵害された可能性のあるユーザーセッションを無効にします。次のシナリオを検討してください。

  • ユーザーはライブラリに移動し、アプリケーションに対して認証します。

  • ユーザーが家に帰ると、ログアウトするのを忘れていることに気づきます。

  • ユーザーは、場所、作成時刻、最終アクセス時刻などの手がかりを使用して、ライブラリからログインしてセッションを終了できます。

ユーザーが認証に使用する任意のデバイスからライブラリでのセッションを無効にできるとしたら、素晴らしいことではないでしょうか。このサンプルは、これがどのように可能であるかを示しています。

FindByIndexNameSessionRepository を使用する

ユーザー名でユーザーを検索するには、最初に FindByIndexNameSessionRepository を実装する SessionRepository を選択する必要があります。サンプルアプリケーションは、Redis サポートがすでに設定されていることを前提としているため、準備ができています。

ユーザー名のマッピング

開発者が Spring Session に、どのユーザーが Session に関連付けられているかを指示した場合、FindByIndexNameSessionRepository はユーザー名によってのみセッションを見つけることができます。これを行うには、FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME という名前のセッション属性にユーザー名が入力されていることを確認します。

一般的に、ユーザーが認証した直後に次のコードを使用してこれを行うことができます。

String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);

Spring Security を使用したユーザー名のマッピング

Spring Security を使用しているため、ユーザー名は自動的にインデックスに登録されます。つまり、ユーザー名にインデックスが付けられていることを確認するための手順を実行する必要はありません。

セッションへの追加データの追加

追加情報(IP アドレス、ブラウザー、場所、その他の詳細など)をセッションに関連付けると便利な場合があります。そうすることで、ユーザーは自分が見ているセッションを簡単に知ることができます。

これを行うには、使用するセッション属性と提供する情報を決定します。次に、セッション属性として追加される Java Bean を作成します。例: 次のように、サンプルアプリケーションにはセッションの場所とアクセス型が含まれています。

public class SessionDetails implements Serializable {

	private String location;

	private String accessType;

	public String getLocation() {
		return this.location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public String getAccessType() {
		return this.accessType;
	}

	public void setAccessType(String accessType) {
		this.accessType = accessType;
	}

	private static final long serialVersionUID = 8850489178248613501L;

}

次に、次の例に示すように、SessionDetailsFilter を使用して各 HTTP リクエストのセッションにその情報を挿入します。

@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
		throws IOException, ServletException {
	chain.doFilter(request, response);

	HttpSession session = request.getSession(false);
	if (session != null) {
		String remoteAddr = getRemoteAddress(request);
		String geoLocation = getGeoLocation(remoteAddr);

		SessionDetails details = new SessionDetails();
		details.setAccessType(request.getHeader("User-Agent"));
		details.setLocation(remoteAddr + " " + geoLocation);

		session.setAttribute("SESSION_DETAILS", details);
	}
}

必要な情報を取得してから、SessionDetails を Session の属性として設定します。ユーザー名で Session を取得すると、他のセッション属性と同じように、セッションを使用して SessionDetails にアクセスできます。

Spring Session がそのまま SessionDetails 機能を提供しないのはなぜか疑問に思われるかもしれません。2 つの理由があります。最初の理由は、アプリケーションがこれを自分で実装するのは非常に簡単なことです。2 番目の理由は、セッションで入力される情報(およびその情報が更新される頻度)がアプリケーションに大きく依存することです。

特定のユーザーのセッションを検索する

これで、特定のユーザーのすべてのセッションを見つけることができます。次の例は、その方法を示しています。

@Autowired
FindByIndexNameSessionRepository<? extends Session> sessions;

@RequestMapping("/")
public String index(Principal principal, Model model) {
	Collection<? extends Session> usersSessions = this.sessions.findByPrincipalName(principal.getName()).values();
	model.addAttribute("sessions", usersSessions);
	return "index";
}

この例では、現在ログインしているユーザーのすべてのセッションが検索されます。ただし、管理者がフォームを使用して検索するユーザーを指定できるように、これを変更できます。

findbyusername サンプルアプリケーション

このセクションでは、findbyusername サンプルアプリケーションの使用方法について説明します。

findbyusername サンプルアプリケーションの実行

サンプルを実行するには、ソースコードを取得し、次のコマンドを呼び出します。

$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun
サンプルを機能させるには、ローカルホストで Redis 2.8+ をインストールします (英語) を実行し、デフォルトのポート (6379) で実行する必要があります。または、Redis サーバーを指すように RedisConnectionFactory を更新することもできます。もう 1 つのオプションは、Docker (英語) を使用してローカルホストで Redis を実行することです。詳細な手順については、Docker Redis リポジトリ (英語) を参照してください。

これで、localhost:8080/ でアプリケーションにアクセスできるようになります。

セキュリティサンプルアプリケーションの調査

これで、アプリケーションを使用してみることができます。次のように入力してログインします。

  • ユーザー名 user

  • パスワード password

次に、ログインボタンをクリックします。以前に入力したユーザーでログインしていることを示すメッセージが表示されます。また、現在ログインしているユーザーのアクティブなセッションのリストも表示されます。

次の手順を実行することで、サンプルについてセクションで説明したフローをエミュレートできます。

  • 新しいシークレットウィンドウを開き、localhost:8080/ に移動します

  • 次のように入力してログインします。

    • ユーザー名 user

    • パスワード password

  • 元のセッションを終了します。

  • 元のウィンドウをリフレッシュして、ログアウトしていることを確認します。