Spring限制最大会话数;限制最大用户数。

5

我能知道是否可以使用Spring Security来限制同时登录网站的最大用户数吗?

当然可以,但需要使用“concurrent-session-control”参数。例如,如果您希望最多只允许1000个用户同时登录,则可以进行相应的配置。如果超过这个数目,则会重定向到提示页面,说明已经超出了最大用户数。

3个回答

9

您可以通过访问SessionRegistry来使用Spring Security的并发会话控制,以查找当前有多少个用户已登录。在Spring Security 3中,ConcurrentSessionControlStrategy负责控制用户在登录后是否允许创建会话。您可以扩展此类并基于用户数添加额外的检查:

public class MySessionAuthenticationStrategy extends ConcurrentSessionControlStrategy {
    int MAX_USERS = 1000; // Whatever
    SessionRegistry sr;

    public MySessionAuthenticationStrategy(SessionRegistry sr) {
        super(sr);
        this.sr = sr;
    }

    @Override
    public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        if (sr.getAllPrincipals().size() > MAX_USERS) {
            throw new SessionAuthenticationException("Maximum number of users exceeded");
        }
        super.onAuthentication(authentication, request, response);
    }
}

按照Spring Security参考手册中的描述,您需要将其注入到安全命名空间中。

在Spring Security 2.0中,会话控制的实现略有不同,您需要自定义ConcurrentSessionController。


5
关于getAllPrincipals方法的一个要点是,它也会返回已过期的会话中的主体。我发现自己需要使用sr.getAllSessions()循环遍历所有会话以检查我没有计算过期的会话。我的max_users比较小,而过期的会话没有被及时清除。 - mut1na

1

我没有足够的声望来添加评论。但是getAllPrincipals返回所有主体,包括过期会话中的主体。使用以下方法之一来获取所有活动会话。

private List<SessionInformation> getActiveSessions(SessionRegistry sessionRegistry) {
    final List<Object> principals = sessionRegistry.getAllPrincipals();
    if (principals != null) {
        List<SessionInformation> sessions = new ArrayList<>();
        for (Object principal : principals) {
            sessions.addAll(sessionRegistry.getAllSessions(principal,     false));
        }
        return sessions;
    }
    return Collections.emptyList();
}

0

这篇文章有点旧,但我在Spring Security 4.1中遇到了同样的问题,并且我已经解决了它。

会话管理

<security:http disable-url-rewriting="true" use-expressions="true" auto-config="true">
    <security:session-management  invalid-session-url="/app/login" session-authentication-strategy-ref="sessionAuthenticationStrategy">                                   
    </security:session-management>
</security:http>

会话认证策略引用

<bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
    <list>
        <bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
            <constructor-arg ref="sessionRegistry"/>
            <property name="maximumSessions" value="1" />
            <property name="exceptionIfMaximumExceeded" value="true" />
        </bean>
        <bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
        </bean>
        <bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
            <constructor-arg ref="sessionRegistry"/>
        </bean>
    </list>
</constructor-arg>
</bean>

会话注册表

@Autowired
private SessionRegistry sessionRegistry;

身份验证

List<SessionInformation> sessions = new ArrayList<>();
for (Object principal : sessionRegistry.getAllPrincipals()) {
    sessions.addAll(sessionRegistry.getAllSessions(principal, false));
}
LOGGER.info("Sessiones Activas: " + sessions.size());
// filtro para limite de sessiones
if (sessions.size() < max_sessions) {
//authentication
} else {
    throw new SessionAuthenticationException("Maximo numero de Usuarios exedido.");
}

我这样做是因为我基于安全性进行身份验证:自定义过滤器


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接