Вопрос по web-applications, spring, login, spring-security – Как я могу получить список всех пользователей, вошедших (через Spring Security) в мое веб-приложение?

60

Я использую Spring Security в своем веб-приложении, и теперь я хочу получить список всех пользователей, которые вошли в мою программу.

Как я могу получить доступ к этому списку? Разве они не находятся где-то в рамках весенних рамок? подобноSecurityContextHolder или жеSecurityContextRepository?

Ваш Ответ

7   ответов
7

Пожалуйста, исправьте меня, если я ошибаюсь.

Я думаю@ Адам & APOS; s ответ неполный. Я заметил, что сеансы, которые уже истекли в списке, появляются снова.

public class UserController {
    @Autowired
    private SessionRegistry sessionRegistry;

    public void listLoggedInUsers() {
        final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();

        for (final Object principal : allPrincipals) {
            if (principal instanceof SecurityUser) {
                final SecurityUser user = (SecurityUser) principal;

                List<SessionInformation> activeUserSessions =
                        sessionRegistry.getAllSessions(principal,
                                /* includeExpiredSessions */ false); // Should not return null;

                if (!activeUserSessions.isEmpty()) {
                    // Do something with user
                    System.out.println(user);
                }
            }
        }
    }
}

Надеюсь, поможет.

Сейчас я не могу получить доступ к исходному коду, но могу сказать, что он работает. Я надеюсь найти время, чтобы разобраться с этим в ближайшее время, но я не могу обещать только сейчас. сожалею
Я не понимаю, как вы говорите, что основной объект является экземпляром bean-компонента SecurityUser. Вы можете объяснить? Есть ли какая-либо конфигурация для соединения сессионной регистрации с компонентом SecurityUser? Как bean-компонент SecurityUser хранится в принципалах Sessionregistry?
0

Нашел это примечание весьма важным и актуальным:

"[21] Authentication by mechanisms which perform a redirect after authenticating (such as form-login) will not be detected by SessionManagementFilter, as the filter will not be invoked during the authenticating request. Session-management functionality has to be handled separately in these cases."

https://docs.spring.io/spring-security/site/docs/3.1.x/reference/session-mgmt.html#d0e4399

Кроме того, по-видимому, у многих людей возникают проблемы с получениемsessionRegistry.getAllPrincipals() возвращая что-то отличное от пустого массива. В моем случае я исправил это, добавивsessionAuthenticationStrategy по моему обычаюauthenticationFilter:

@Bean
public CustomUsernamePasswordAuthenticationFilter authenticationFilter() throws Exception {
...

  authenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
}

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

//cf. https://stackoverflow.com/questions/32463022/sessionregistry-is-empty-when-i-use-concurrentsessioncontrolauthenticationstrate
public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    List<SessionAuthenticationStrategy> stratList = new ArrayList<>();
    SessionFixationProtectionStrategy concStrat = new SessionFixationProtectionStrategy();
    stratList.add(concStrat);
    RegisterSessionAuthenticationStrategy regStrat = new RegisterSessionAuthenticationStrategy(sessionRegistry());
    stratList.add(regStrat);
    CompositeSessionAuthenticationStrategy compStrat = new CompositeSessionAuthenticationStrategy(stratList);
    return compStrat;
}
0

Как и в случае решения @rolyanos, у меня всегда работает:

- for the controller

@RequestMapping(value = "/admin")
public String admin(Map<String, Object> model) {

    if(sessionRegistry.getAllPrincipals().size() != 0) {
        logger.info("ACTIVE USER: " + sessionRegistry.getAllPrincipals().size());
        model.put("activeuser",  sessionRegistry.getAllPrincipals().size());
    }
    else
        logger.warn("EMPTY" );

    logger.debug(log_msg_a + " access ADMIN page. Access granted." + ANSI_RESET);
    return "admin";
}

- for the front end

<tr th:each="activeuser, iterStat: ${activeuser}">
    <th><b>Active users: </b></th> <td align="center" th:text="${activeuser}"></td>
    </tr>

- for spring confing

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

@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
    return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}


@Override
protected void configure(HttpSecurity http) throws Exception {

    http.logout()
    .logoutSuccessUrl("/home")
    .logoutUrl("/logout")
    .invalidateHttpSession(true)
    .deleteCookies("JSESSIONID");


    http.authorizeRequests()
    .antMatchers("/", "/home")
    .permitAll()

    .antMatchers("/admin")
    .hasRole("ADMIN") 
    .anyRequest()
    .authenticated()

    .and()
    .formLogin()
    .loginPage("/home")
    .defaultSuccessUrl("/main")
    .permitAll()
    .and()
    .logout()
    .permitAll();

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

    http.authorizeRequests().antMatchers("/webjars/**").permitAll();

    http.exceptionHandling().accessDeniedPage("/403");
}
30

В JavaConfig это будет выглядеть так:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        // ...
        http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
    }

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

    @Bean
    public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
    }
}

С кодом вызова, похожим на это:

public class UserController {
    @Autowired
    private SessionRegistry sessionRegistry;

    public void listLoggedInUsers() {
        final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();

        for(final Object principal : allPrincipals) {
            if(principal instanceof SecurityUser) {
                final SecurityUser user = (SecurityUser) principal;

                // Do something with user
                System.out.println(user);
            }
        }
    }
}

Обратите внимание, чтоSecurityUser мой собственный класс, который реализуетUserDetails.

@mailman, дайте мне знать, если вам нужна помощь, или же вы можете войти в систему всех пользователей, используя httpListeners
эти ответы кажутся правильными, но для меня это всегда возвращающаяся и пустая коллекция, любая идея ??
Для записи, класс ServletListenerRegistrationBean является частью Spring Boot, поэтому вам придется добавить зависимость с Spring Boot. В моей организации только Spring MVC и Spring Security одобрены для использования, поэтому я не могу использовать ваше решение (кстати, это выглядит потрясающе). Нужно будет найти другой способ добиться этого. Спасибо!
@mailman да, я сохраняю сессию, и из этой сессии я получаю список зарегистрированных пользователей
Ответ @azerafati не работает, если вы используете ручную аутентификацию, поэтому помните, что вам также нужно поместить пользователя в sessionRegistry: sessionRegistry.registerNewSession (request.getSession (). getId (), auth.getPrincipal ());
6

Пожалуйста, исправьте меня, если я тоже ошибаюсь.

Я думаю, что ответ @ Adam 's и @ elysch является неполным. Я заметил, что нужно добавить слушателя:

 servletContext.addListener(HttpSessionEventPublisher.class);

в

public class AppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) {
  ...
servletContext.addListener(HttpSessionEventPublisher.class);
}

с безопасностью conf:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        // ...
        http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        retur,n new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}

И тогда вы получите текущие пользователи онлайн!

Я использую Spring Boot, и после объявления бина HttpSessionEventPublisher он был выбран и использован автоматически.
58

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

@Autowired
@Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;

И затем с помощью поврежденного SessionRegistry вы можете получить доступ к списку всех принципалов:

List<Object> principals = sessionRegistry.getAllPrincipals();

List<String> usersNamesList = new ArrayList<String>();

for (Object principal: principals) {
    if (principal instanceof User) {
        usersNamesList.add(((User) principal).getUsername());
    }
}

Но перед внедрением реестра сеанса вам нужно определить часть управления сеансом в вашем spring-security.xml (посмотрите наРаздел «Управление сессиями» в справочной документации Spring Security) и в разделе контроля параллелизма вы должны установить псевдоним для объекта реестра сеанса (session-registry-alias) с помощью которого вы будете вводить его.

    <security:http access-denied-page="/error403.jsp" use-expressions="true" auto-config="false">
        <security:session-management session-fixation-protection="migrateSession" session-authentication-error-url="/login.jsp?authFailed=true"> 
            <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.html" session-registry-alias="sessionRegistry"/>
        </security:session-management>

    ...
    </security:http>
Я не понимаю, как вы говорите, что основной объект является экземпляром пользовательского компонента. Вы можете объяснить? Есть ли какая-либо конфигурация для соединения сессионной регистрации с пользовательским бином? Как пользовательские бины хранятся в принципалах Sessionregistry?
1

Вам нужно ввестиSessionRegistry (как упоминалось ранее), а затем вы можете сделать это в одном конвейере, как это:

public List<UserDetails> findAllLoggedInUsers() {
    return sessionRegistry.getAllPrincipals()
            .stream()
            .filter(principal -> principal instanceof UserDetails)
            .map(UserDetails.class::cast)
            .collect(Collectors.toList());
}

Похожие вопросы