spring 如何限制每个用户只能进行一个会话并阻止后续的登录尝试?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12985862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:27:03  来源:igfitidea点击:

How to limit only one session per user and block the subsequent login attempt?

springspring-security

提问by abiieez

The default behavior of concurrency control is to expire the original session. However, I would like to block the second user which is logging in with the same credentials with displaying message "User has already logged in". How can I accomplish this ?

并发控制的默认行为是使原始会话过期。但是,我想阻止使用相同凭据登录并显示消息“用户已登录”的第二个用户。我怎样才能做到这一点?

Below is the configuration of spring-security.xml:

下面是 spring-security.xml 的配置:

<http auto-config="false" use-expressions="true">
    <intercept-url pattern="/login*" access="permitAll"
        requires-channel="https" />
    <intercept-url pattern="/userHasLoggedIn" access="permitAll"
        requires-channel="https" />
    <intercept-url pattern="/j_spring_security_*" access="permitAll"
        requires-channel="https" />
    <intercept-url pattern="/session*" access="permitAll"
        requires-channel="https" />
    <form-login login-page="/login" authentication-failure-url="/loginFailed" />
    <intercept-url pattern="/**" access="isAuthenticated()"
        requires-channel="https" />
    <session-management invalid-session-url="/sessionExpired" session-authentication-error-url="/loginAlready">
        <concurrency-control error-if-maximum-exceeded="false" expired-url="/userHasLoggedIn" max-sessions="1"/>
    </session-management>
    <logout delete-cookies="JSESSIONID" />
</http>

(Updated)My final spring security configuration:

(更新)我最终的 spring 安全配置:

<http auto-config="false" use-expressions="true">
        <intercept-url pattern="/login*" access="permitAll"
            requires-channel="https" />
        <form-login default-target-url="/home" login-page="/login" authentication-failure-url="/loginFailed" />
        <intercept-url pattern="/**" access="isFullyAuthenticated()"
            requires-channel="https" />
        <session-management session-authentication-error-url="/loginFailed">
            <concurrency-control expired-url="/loginFailed" error-if-maximum-exceeded="true" max-sessions="1"/>
        </session-management>
        <logout delete-cookies="JSESSIONID" />
    </http>

回答by Xaerxess

The solution is in the documentation:

解决方案在文档中

Often you would prefer to prevent a second login, in which case you can use

<http>
  ...
  <session-management>
      <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
  </session-management>
</http>

The second login will then be rejected. By “rejected”, we mean that the user will be sent to the authentication-failure-urlif form-based login is being used. If the second authentication takes place through another non-interactive mechanism, such as “remember-me”, an “unauthorized” (402) error will be sent to the client. If instead you want to use an error page, you can add the attribute session-authentication-error-urlto the session-managementelement.

通常,您希望防止第二次登录,在这种情况下,您可以使用

<http>
  ...
  <session-management>
      <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
  </session-management>
</http>

第二次登录将被拒绝。通过“拒绝”,我们的意思是authentication-failure-url如果使用基于表单的登录,用户将被发送到。如果第二次身份验证是通过另一种非交互机制(例如“记住我”)进行的,则会向客户端发送“未授权”(402)错误。如果您想使用错误页面,则可以将属性添加session-authentication-error-urlsession-management元素。

So basically set error-if-maximum-exceededto "true"and remove expired-urlattribute from <concurrency-control>.

所以基本上设置error-if-maximum-exceeded"true"expired-url从中删除属性<concurrency-control>