Ich verwende Spring Security in meiner Webanwendung und möchte jetzt 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ühlingsrahmen? Wie SecurityContextHolder oder SecurityContextRepository ?
spring
web-applications
login
spring-security
Matin Kh
quelle
quelle
Antworten:
Um auf die Liste aller angemeldeten Benutzer zuzugreifen, müssen Sie die SessionRegistry-Instanz in Ihre 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 ) und im Abschnitt zur Parallelitätskontrolle den Alias für das Sitzungsregistrierungsobjekt ( Sitzungsregistrierung) festlegen. Alias ), mit dem Sie es injizieren.
<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>
quelle
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 dies
SecurityUser
meine eigene Klasse ist, die implementiertUserDetails
.quelle
Bitte korrigieren Sie mich, wenn ich falsch liege.
Ich denke, @ Adams Antwort ist unvollständig. Ich habe festgestellt, dass bereits abgelaufene Sitzungen in der Liste erneut 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.
quelle
Bitte korrigieren Sie mich, wenn ich mich auch irre.
Ich denke, die Antwort von @ Adam und @ elysch ist unvollständig. Mir ist aufgefallen, dass ein Listener hinzugefügt werden muss:
servletContext.addListener(HttpSessionEventPublisher.class);
zu
public class AppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) { ... servletContext.addListener(HttpSessionEventPublisher.class); }
mit Sicherheitskonf:
@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 erhalten Sie aktuelle Online-Nutzer!
quelle
Sie müssen injizieren
SessionRegistry
(wie bereits erwähnt) und können dies dann 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()); }
quelle
Fand diesen Hinweis sehr wichtig und relevant:
https://docs.spring.io/spring-security/site/docs/3.1.x/reference/session-mgmt.html#d0e4399
Außerdem haben anscheinend viele Leute Probleme, sessionRegistry.getAllPrincipals () dazu zu bringen , etwas anderes als ein leeres Array zurückzugeben. In meinem Fall habe ich das Problem behoben, indem ich die sessionAuthenticationStrategy zu meinem benutzerdefinierten Authentifizierungsfilter hinzugefügt habe :
@Bean public CustomUsernamePasswordAuthenticationFilter authenticationFilter() throws Exception { ... authenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy()); } @Bean public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } //cf. /programming/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; }
quelle
Ä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 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"); }
quelle