it-swarm.com.de

Wie kann ich eine Liste aller Benutzer (über Spring Security) meiner Webanwendung angemeldet haben?

Ich verwende die Frühlingssicherheit in meiner Webanwendung und jetzt möchte ich eine Liste aller Benutzer haben, die in meinem Programm angemeldet sind.

Wie kann ich auf diese Liste zugreifen? Sind sie nicht schon irgendwo im Frühling untergebracht? WieSecurityContextHolderoderSecurityContextRepository?

59
Matin Kh

Um auf die Liste aller angemeldeten Benutzer zuzugreifen, müssen Sie die SessionRegistry-Instanz in Ihr Bean einfügen. 

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

Und dann können Sie mit der verletzten SessionRegistry auf die Liste aller Principals zugreifen:

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

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

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

Bevor Sie jedoch die Sitzungsregistrierung einfügen, müssen Sie den Sitzungsverwaltungsteil in Ihrer spring-security.xml definieren (siehe Abschnitt Sitzungsverwaltung in der Spring Security-Referenzdokumentation ). Im Abschnitt Parallelitätskontrolle sollten Sie einen Alias ​​für das Sitzungsregistrierungsobjekt festlegen ( Sitzungsregistrierungsalias), durch den Sie es einfügen werden.

    <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>
58
dimas

In JavaConfig würde es so aussehen:

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

Der Aufrufcode sieht folgendermaßen aus:

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

Beachten Sie, dass SecurityUser meine eigene Klasse ist, die UserDetails implementiert.

29
Adam

Bitte korrigieren Sie mich, wenn ich falsch liege.

Ich denke, @ Adams Antwort ist unvollständig. Ich habe festgestellt, dass Sitzungen, die bereits in der Liste abgelaufen sind, wieder angezeigt werden.

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

Ich hoffe es hilft.

7
elysch

Bitte korrigieren Sie mich, wenn ich auch falsch liege.

Ich denke, @ Adams und @ elyschs Antwort ist unvollständig. Ich habe bemerkt, dass es notwendig ist, Listener hinzuzufügen:

 servletContext.addListener(HttpSessionEventPublisher.class);

zu

public class AppInitializer implements WebApplicationInitializer {

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

mit Sicherheitskonvertierung:

@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 HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}

Und dann bekommst du aktuelle Online-Nutzer!

6
rolyanos

Sie müssen SessionRegistry (wie bereits erwähnt) injizieren, und dann können Sie dies in einer Pipeline wie folgt tun:

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

Ähnlich wie bei der @rolyanos-Lösung funktioniert meine für mich immer:

- für die Steuerung

@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";
}

- für das Frontend

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

- für die Frühlingskonfektion

@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");
}
0
cyberdemon

Fand diesen Hinweis für recht wichtig und relevant:

"[21] Die Authentifizierung durch Mechanismen, die eine Umleitung nach Der Authentifizierung durchführen (wie Formular-Login), wird von SessionManagementFilter nicht erkannt, da der Filter nicht während der Authentifizierungsanforderung aufgerufen wird. Die Verwaltungsfunktionalität muss in diesen Fällen separat behandelt werden. "

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

Anscheinend haben viele Leute Probleme, sessionRegistry.getAllPrincipals () zu erhalten, die etwas anderes als ein leeres Array zurückgeben. In meinem Fall habe ich das Problem behoben, indem ich sessionAuthenticationStrategy zu meinem benutzerdefinierten authenticationFilter hinzugefügt habe:

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