我如何拥有所有登录的用户列表(通过spring security)我的Web应用程序

Mat*_* Kh 66 spring login web-applications spring-security

我在我的Web应用程序中使用spring security,现在我想要列出所有登录我程序的用户.

我怎样才能访问该列表?它们不是已经存在于spring框架内的某个地方吗?像SecurityContextHolderSecurityContextRepository

dim*_*mas 59

要访问所有登录用户的列表,您需要将SessionRegistry实例注入您的bean.

@Autowired
@Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;
Run Code Online (Sandbox Code Playgroud)

然后使用受惩罚的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());
    }
}
Run Code Online (Sandbox Code Playgroud)

但是在注入会话注册表之前,您需要在spring-security.xml中定义会话管理部分(请参阅Spring Security参考文档中的会话管理部分),在并发控制部分中,您应该为会话注册表对象设置别名(会话注册表 -别名)你将通过它注入它.

    <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>
Run Code Online (Sandbox Code Playgroud)


Ada*_*dam 38

在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());
    }
}
Run Code Online (Sandbox Code Playgroud)

调用代码如下所示:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这SecurityUser是我自己的实现类UserDetails.

  • 这个答案似乎是正确的,但对我来说,它总是返回和空集合,任何想法? (14认同)
  • 对于记录,ServletListenerRegistrationBean类是Spring Boot的一部分,因此您必须使用Spring Boot添加依赖项.在我的组织中,只有Spring MVC和Spring Security被批准使用,因此我无法使用您的解决方案(顺便说一句,这看起来很棒).将不得不寻找另一种方法来实现这一目标.谢谢! (3认同)
  • 如果你使用手动身份验证,@ azerafati回答不起作用,所以请记住你还需要将用户放到sessionRegistry:sessionRegistry.registerNewSession(request.getSession().getId(),auth.getPrincipal()); (2认同)

ely*_*sch 8

如果我错了,请纠正我.

我认为@Adam的答案是不完整的.我注意到列表中已经过期的会话再次出现.

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);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.


小智 6

如果我错了也请纠正我.

我认为@ Adam和@ elysch的回答是不完整的.我注意到需要添加监听器:

 servletContext.addListener(HttpSessionEventPublisher.class);
Run Code Online (Sandbox Code Playgroud)

public class AppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) {
  ...
servletContext.addListener(HttpSessionEventPublisher.class);
}
Run Code Online (Sandbox Code Playgroud)

与安全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() {
        return new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你将获得当前的在线用户!


k13*_*13i 5

您需要注入SessionRegistry(如前所述),然后您可以在一个管道中执行此操作,如下所示:

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