Spring Securityでログインしたユーザーを追跡する
1概要
このクイックチュートリアルでは、Spring Securityを使用してアプリケーションで現在ログインしているユーザーを追跡する方法の例を示します。
2アクティブユーザーストア
public class ActiveUserStore {
public List<String> users;
public ActiveUserStore() {
users = new ArrayList<String>();
}
//standard getter and setter
}
Springのコンテキストでは、これを標準のBeanとして定義します。
@Bean
public ActiveUserStore activeUserStore(){
return new ActiveUserStore();
}
3
HTTPSessionBindingListener
これは基本的に
HttpSessionBindingEvent
型のイベントを監視します。これは、値が設定または削除されるたびに、つまりHTTPセッションに対してバインドまたはアンバインドされるたびに発生します。
@Component
public class LoggedUser implements HttpSessionBindingListener {
private String username;
private ActiveUserStore activeUserStore;
public LoggedUser(String username, ActiveUserStore activeUserStore) {
this.username = username;
this.activeUserStore = activeUserStore;
}
public LoggedUser() {}
@Override
public void valueBound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (!users.contains(user.getUsername())) {
users.add(user.getUsername());
}
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
List<String> users = activeUserStore.getUsers();
LoggedUser user = (LoggedUser) event.getValue();
if (users.contains(user.getUsername())) {
users.remove(user.getUsername());
}
}
//standard getter and setter
}
リスナーには、リスンしているイベントをトリガーする2種類のアクションのために、実装する必要がある2つのメソッド、
valueBound()
と
valueUnbound()
があります。リスナーを実装する型の値がセッションから設定または削除されるか、セッションが無効になるたびに、これら2つのメソッドが呼び出されます。
この例では、
valueBound()
メソッドがユーザーのログイン時に呼び出され、
valueUnbound()
メソッドがユーザーのログアウト時またはセッションの期限が切れるときに呼び出されます。
各メソッドでは、イベントに関連付けられた値を取得し、値がセッションにバインドされているかどうかに応じて、ログインユーザーのリストからユーザー名を追加または削除します。
4.
ログインとログアウトの追跡
4.1.
AuthenticationSuccessHandler
の実装
ログインアクションでは、
session
および
authentication
オブジェクトへのアクセスを提供する
onAuthenticationSuccess()
メソッドをオーバーライドすることによって、ログインしているユーザーのユーザー名をセッションの属性として設定します。
@Component("myAuthenticationSuccessHandler")
public class MySimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
ActiveUserStore activeUserStore;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
HttpSession session = request.getSession(false);
if (session != null) {
LoggedUser user = new LoggedUser(authentication.getName(), activeUserStore);
session.setAttribute("user", user);
}
}
}
4.2.
LogoutSuccessHandler
を実装する
ログアウトアクションでは、
LogoutSuccessHandler
インターフェースの
onLogoutSuccess()
メソッドをオーバーライドしてユーザー属性を削除します。
@Component("myLogoutSuccessHandler")
public class MyLogoutSuccessHandler implements LogoutSuccessHandler{
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
HttpSession session = request.getSession();
if (session != null){
session.removeAttribute("user");
}
}
}
5コントローラとビュー
上記のすべての動作を確認するために、ユーザーのリストを取得し、それをモデル属性として追加して
users.html
ビューを返すURL
“/users”
のコントローラーマッピングを作成します。
5.1. コントローラ
@Controller
public class UserController {
@Autowired
ActiveUserStore activeUserStore;
@RequestMapping(value = "/loggedUsers", method = RequestMethod.GET)
public String getLoggedUsers(Locale locale, Model model) {
model.addAttribute("users", activeUserStore.getUsers());
return "users";
}
}
5.2. Users.html
<html>
<body>
<h2>Currently logged in users</h2>
<div th:each="user : ${users}">
<p th:text="${user}">user</p>
</div>
</body>
</html>
6.
SessionRegistry
を使用した代替方法
現在ログインしているユーザーを取得するもう1つの方法は、Springの
SessionRegistry
を利用することです。これはユーザーとセッションを管理するクラスです。このクラスには、ユーザーのリストを取得するためのメソッド
getAllPrincipals()
があります。
各ユーザーについて、メソッド
getAllSessions()
を呼び出すことで、すべてのセッションの一覧を見ることができます。現在ログインしているユーザーのみを取得するには、
getAllSessions()
の2番目のパラメーターを
false
に設定して、期限切れのセッションを除外する必要があります。
@Autowired
private SessionRegistry sessionRegistry;
@Override
public List<String> getUsersFromSessionRegistry() {
return sessionRegistry.getAllPrincipals().stream()
.filter(u -> !sessionRegistry.getAllSessions(u, false).isEmpty())
.map(Object::toString)
.collect(Collectors.toList());
}
SessionRegistry
クラスを使用するには、以下に示すようにBeanを定義し、それをセッション管理に適用する必要があります。
http
.sessionManagement()
.maximumSessions(1).sessionRegistry(sessionRegistry())
...
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
7. 結論
この記事では、現在ログインしているユーザーがSpring Securityアプリケーションで誰であるかを判断する方法を説明しました。
このチュートリアルの実装はhttps://github.com/eugenp/spring-security-registration[GitHubプロジェクト]にあります – これはMavenベースのプロジェクトなので、そのままインポートして実行するのは簡単なはずです。