Отслеживайте зарегистрированных пользователей с помощью Spring Security

Отслеживайте зарегистрированных пользователей с помощью Spring Security

1. обзор

В этом кратком руководстве мы покажем пример того, как мы можемtrack the currently logged in users in an application using Spring Security.

Для этого мы собираемся отслеживать список зарегистрированных пользователей, добавляя пользователя при входе и удаляя его при выходе.

Мы будем использоватьHttpSessionBindingListener для обновления списка пользователей, вошедших в систему, всякий раз, когда информация о пользователе добавляется в сеанс или удаляется из сеанса в зависимости от входа пользователя в систему или выхода из системы.

2. Магазин активных пользователей

Для простоты мы определим класс, который действует как хранилище в памяти для вошедших в систему пользователей:

public class ActiveUserStore {

    public List users;

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

    // standard getter and setter
}

Мы определим это как стандартный компонент в контексте Spring:

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

3. HTTPSessionBindingListener

Теперь мы собираемся использовать интерфейс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 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
}

У слушателя есть два метода, которые необходимо реализовать,valueBound() иvalueUnbound() для двух типов действий, запускающих событие, которое он прослушивает. Всякий раз, когда значение типа, которое реализует прослушиватель, устанавливается или удаляется из сеанса, или сеанс становится недействительным, эти два метода будут вызваны.

В нашем случае методvalueBound() будет вызываться при входе пользователя в систему, а методvalueUnbound() будет вызываться при выходе пользователя из системы или по истечении сеанса.

В каждом из методов мы извлекаем значение, связанное с событием, затем добавляем или удаляем имя пользователя из нашего списка зарегистрированных пользователей, в зависимости от того, было ли значение привязано или не связано с сеансом.

4. Отслеживание входа в систему и выхода из системы

Теперь нам нужно отслеживать, когда пользователь успешно вошел в систему или вышел из нее, чтобы мы могли добавить или удалить активного пользователя из сеанса. В приложении Spring Security это может быть достигнуто путем реализации интерфейсовAuthenticationSuccessHandler иLogoutSuccessHandler.

4.1. РеализацияAuthenticationSuccessHandler

Для действия входа в систему мы установим имя пользователя, входящего в систему, в качестве атрибута сеанса, переопределив методonAuthenticationSuccess(), который предоставляет нам доступ к объектамsession иauthentication:

@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

Для действия выхода из системы мы удалим атрибут пользователя, переопределив методonLogoutSuccess() интерфейсаLogoutSuccessHandler:

@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. Контроллер и просмотр

Чтобы увидеть все вышеперечисленное в действии, мы создадим сопоставление контроллера для URL“/users”, которое будет извлекать список пользователей, добавлять его как атрибут модели и возвращать представлениеusers.html:

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



    

Currently logged in users

user

6. Альтернативный метод с использованиемSessionregistry

Другой метод получения пользователей, вошедших в систему в настоящий момент, - это использование SpringSessionRegistry, который представляет собой класс, который управляет пользователями и сеансами. В этом классе есть методgetAllPrincipals() для получения списка пользователей.

Для каждого пользователя мы можем увидеть список всех его сессий, вызвав методgetAllSessions(). Чтобы получить только текущих пользователей, вошедших в систему, мы должны исключить сеансы с истекшим сроком действия, установив второй параметрgetAllSessions() наfalse:

@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());
}

Чтобы использовать классSessionRegistry, мы должны определить компонент и применить его к управлению сеансом, как показано ниже:

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

...

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

7. Заключение

В этой статье мы продемонстрировали, как мы можем определить, кто в данный момент вошел в систему в приложении Spring Security.

Реализацию этого руководства можно найти вthe GitHub project - это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.