Verfolgen Sie angemeldete Benutzer mit Spring Security

Behalten Sie den Überblick über angemeldete Benutzer mit Spring Security

1. Überblick

In diesem kurzen Tutorial zeigen wir ein Beispiel, wie wirtrack the currently logged in users in an application using Spring Security können.

Zu diesem Zweck werden wir eine Liste der angemeldeten Benutzer nachverfolgen, indem wir den Benutzer beim Anmelden hinzufügen und ihn beim Abmelden entfernen.

Wir werden dieHttpSessionBindingListener nutzen, um die Liste der angemeldeten Benutzer zu aktualisieren, wenn Benutzerinformationen zur Sitzung hinzugefügt oder aus der Sitzung entfernt werden, basierend auf Benutzerprotokollen im System oder Abmeldungen vom System.

2. Aktiver Benutzerspeicher

Der Einfachheit halber definieren wir eine Klasse, die als In-Memory-Speicher für die angemeldeten Benutzer fungiert:

public class ActiveUserStore {

    public List users;

    public ActiveUserStore() {
        users = new ArrayList();
    }

    // standard getter and setter
}

Wir werden dies im Spring-Kontext als Standard-Bean definieren:

@Bean
public ActiveUserStore activeUserStore(){
    return new ActiveUserStore();
}

3. DieHTTPSessionBindingListener

Jetzt werden wir dieHTTPSessionBindingListener-Schnittstelle verwenden und eine Wrapper-Klasse erstellen, um einen Benutzer darzustellen, der derzeit angemeldet ist.

Dies hört grundsätzlich Ereignisse vom TypHttpSessionBindingEvent ab, die ausgelöst werden, wenn ein Wert gesetzt oder entfernt oder mit anderen Worten an die HTTP-Sitzung gebunden oder ungebunden wird:

@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 users = activeUserStore.getUsers();
        LoggedUser user = (LoggedUser) event.getValue();
        if (!users.contains(user.getUsername())) {
            users.add(user.getUsername());
        }
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        List users = activeUserStore.getUsers();
        LoggedUser user = (LoggedUser) event.getValue();
        if (users.contains(user.getUsername())) {
            users.remove(user.getUsername());
        }
    }

    // standard getter and setter
}

Der Listener verfügt über zwei Methoden, die implementiert werden müssen:valueBound() undvalueUnbound() für die beiden Arten von Aktionen, die das Ereignis auslösen, auf das er wartet. Immer wenn ein Wert des Typs, der den Listener implementiert, festgelegt oder aus der Sitzung entfernt oder die Sitzung ungültig gemacht wird, werden diese beiden Methoden aufgerufen.

In unserem Fall wird dievalueBound()-Methode aufgerufen, wenn sich der Benutzer anmeldet, und dievalueUnbound()-Methode wird aufgerufen, wenn sich der Benutzer abmeldet oder wenn die Sitzung abläuft.

Bei jeder der Methoden rufen wir den mit dem Ereignis verknüpften Wert ab und fügen dann den Benutzernamen zu unserer Liste der angemeldeten Benutzer hinzu oder entfernen ihn, je nachdem, ob der Wert in der Sitzung gebunden oder nicht gebunden war.

4. Tracking Login und Logout

Jetzt müssen wir nachverfolgen, wann der Benutzer erfolgreich angemeldet oder abgemeldet wurde, damit wir einen aktiven Benutzer zur Sitzung hinzufügen oder daraus entfernen können. In einer Spring Security-Anwendung kann dies durch Implementieren der SchnittstellenAuthenticationSuccessHandler undLogoutSuccessHandler erreicht werden.

4.1. AuthenticationSuccessHandler implementieren

Für die Anmeldeaktion legen wir den Benutzernamen des Benutzers fest, der sich in der Sitzung als Attribut anmeldet, indem wir die MethodeonAuthenticationSuccess()überschreiben, mit der wir auf die Objektesession undauthenticationzugreifen können:

@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 implementieren

Für die Abmeldeaktion entfernen wir das Benutzerattribut, indem wir dieonLogoutSuccess()-Methode derLogoutSuccessHandler-Schnittstelle überschreiben:

@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. Controller und Ansicht

Um all das oben Genannte in Aktion zu sehen, erstellen wir eine Controller-Zuordnung für die URL“/users”, die die Liste der Benutzer abruft, sie als Modellattribut hinzufügt und die Ansichtusers.htmlzurückgibt:

5.1. Regler

@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



    

Currently logged in users

user

6. Alternative Methode mitSessionregistry

Eine andere Methode zum Abrufen der aktuell angemeldeten Benutzer ist die Nutzung vonSessionRegistryvon Spring, einer Klasse, die Benutzer und Sitzungen verwaltet. Diese Klasse hat die MethodegetAllPrincipals(), um die Liste der Benutzer zu erhalten.

Für jeden Benutzer können wir eine Liste aller Sitzungen anzeigen, indem wir die MethodegetAllSessions() aufrufen. Um nur die aktuell angemeldeten Benutzer zu erhalten, müssen wir die abgelaufenen Sitzungen ausschließen, indem wir den zweiten Parameter vongetAllSessions() auffalse setzen:

@Autowired
private SessionRegistry sessionRegistry;

@Override
public List getUsersFromSessionRegistry() {
    return sessionRegistry.getAllPrincipals().stream()
      .filter(u -> !sessionRegistry.getAllSessions(u, false).isEmpty())
      .map(Object::toString)
      .collect(Collectors.toList());
}

Um die KlasseSessionRegistryzu verwenden, müssen Sie die Bean definieren und wie unten gezeigt auf die Sitzungsverwaltung anwenden:

http
  .sessionManagement()
  .maximumSessions(1).sessionRegistry(sessionRegistry())

...

@Bean
public SessionRegistry sessionRegistry() {
    return new SessionRegistryImpl();
}

7. Fazit

In diesem Artikel haben wir gezeigt, wie wir ermitteln können, wer die aktuell angemeldeten Benutzer in einer Spring Security-Anwendung sind.

Die Implementierung dieses Tutorials finden Sie inthe GitHub project - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein.