Spring Security 3.2.5 - 并发登录

时间:2015-06-27 20:39:29

标签: java spring spring-mvc spring-security spring-session

经过多天的研究,我放弃了,我唯一的希望就是在这里,我可以找到我的帮助。

我的应用程序是登录部分是手动使用带有Spring Security 3.2.5的Spring 4。现在我需要控制登录并发,但不起作用。

我的代码:

弹簧security.xml文件

<http auto-config="true" use-expressions="true" disable-url-rewriting="true" create-session="always">
    <intercept-url pattern="/public/**" access="permitAll" />
    <intercept-url pattern="/protected/**" access="isAuthenticated()" />
    <!-- Necessário jogar a pasta template para fora do protected por causa do AngularJS ( $routeProvider ) -->
    <intercept-url pattern="/resources/template/**" access="isAuthenticated()" /> 

    <form-login login-page="/public/login"
                default-target-url="/protected/main"
                authentication-failure-url="/public/login?error=403"  
                always-use-default-target="true"/>

    <logout logout-success-url="/public/login"
            logout-url="/logout"
            delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"
            invalidate-session="true"/>

    <session-management invalid-session-url="/public/login" >
        <concurrency-control error-if-maximum-exceeded="false" max-sessions="1" expired-url="/logout"/>
    </session-management>

    <remember-me key="rememberkysecurity" services-ref="rememberMeServices"/>

    <headers >
        <cache-control />
        <frame-options />
        <hsts/>
    </headers>
</http>

<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
    <beans:property name="key" value="rememberkysecurity" />
    <beans:property name="userDetailsService" ref="userDetailsService" />
    <beans:property name="alwaysRemember" value="true" />
    <beans:property name="tokenValiditySeconds" value="10080" />
</beans:bean>

<authentication-manager alias="autenticationManagerDB" >
    <authentication-provider>
        <password-encoder hash="bcrypt" />
        <jdbc-user-service data-source-ref="dataSource" id="userDetailsService" 
                           users-by-username-query="SELECT username, password, enabled FROM user WHERE username = ?"
                           authorities-by-username-query= "SELECT usr_id, 'ROLE_ADMIN' AS role FROM user WHERE username = ?"/>
    </authentication-provider>
</authentication-manager>

的web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>APP</display-name>
<welcome-file-list>
    <welcome-file>/public/login</welcome-file>
</welcome-file-list>
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/spring/spring.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/spring.xml</param-value>
</context-param>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<session-config>
    <session-timeout>360</session-timeout>
    <cookie-config>
        <http-only>true</http-only>
        <secure>false</secure>
    </cookie-config>
    <tracking-mode>COOKIE</tracking-mode>
</session-config>   

Java登录

Authentication authenticatedUser = null;
    if ( keeplogged ) {
        UserDetails userDetails = userDetailsService.loadUserByUsername( user.getUsername() );
        RememberMeAuthenticationToken rememberMeAuthenticationToken = new RememberMeAuthenticationToken( "rememberkysecurity", userDetails, userDetails.getAuthorities() );

        rememberMeServices.loginSuccess(request, response, rememberMeAuthenticationToken);
        authenticatedUser = rememberMeAuthenticationToken;

    } else {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( user.getUsername(), user.getPassword() );

        authenticatedUser = this.autenticationManagerDB.authenticate( authenticationToken );

    }
    UserDetails userDetails = userDetailsService.loadUserByUsername( user.getUsername() );
    SecurityContextHolder.getContext().setAuthentication( authenticatedUser );

2 个答案:

答案 0 :(得分:0)

在会话管理配置中,只需将error-if-maximum-exceeded键设置为true:

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

请注意,通过将此键设置为false,允许用户登录,但spring仅使第一个会话无效。将其设置为true,将禁止用户再次登录

更新:看一下这个文档:http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/reference/htmlsingle/#concurrent-sessions

答案 1 :(得分:0)

使用UsernamePasswordAuthenticationFilter

您是否有理由不使用Spring Security的UsernamePasswordAuthenticationFilter?如果你是这样,你就可以开箱即用了。

自定义控制器

如果您要提供自己的控制器进行身份验证,则需要手动执行SessionAuthenticationStrategy。通常,这是使用CompositeSessionAuthenticationStrategy完成的,@Autowired CompositeSessionAuthenticationStrategy strategy; public void doLogin() { Authentication authenticatedUser = null; if ( keeplogged ) { UserDetails userDetails = userDetailsService.loadUserByUsername( user.getUsername() ); RememberMeAuthenticationToken rememberMeAuthenticationToken = new RememberMeAuthenticationToken( "rememberkysecurity", userDetails, userDetails.getAuthorities() ); rememberMeServices.loginSuccess(request, response, rememberMeAuthenticationToken); authenticatedUser = rememberMeAuthenticationToken; } else { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( user.getUsername(), user.getPassword() ); authenticatedUser = this.autenticationManagerDB.authenticate( authenticationToken ); } UserDetails userDetails = userDetailsService.loadUserByUsername( user.getUsername() ); sessionStrategy.onAuthentication(authenticatedUser, request, response); SecurityContextHolder.getContext().setAuthentication( authenticatedUser ); } 填充了以下实现(按此顺序):

  • ConcurrentSessionControlAuthenticationStrategy - 验证是否允许用户进行身份验证(即他们尚未登录该应用程序。
  • SessionFixationProtectionStrategy - 更改身份验证时的会话ID以确保未启动会话固定攻击
  • RegisterSessionAuthenticationStrategy - 将新用户注册为当前已通过身份验证

因此,要解决您的问题,您应该能够执行以下操作:

class Country: Object {
        dynamic var id = ""
        dynamic var name = ""
}