使用不同的用户名登录时,获取“此主体的最大会话数超过1”

时间:2015-12-11 05:12:14

标签: java spring spring-mvc spring-security

我将我的应用程序配置为每个帐户只允许一个会话 当我使用JdbcDaoImpl提供程序时,它工作正常 当我将DaoAuthenticationProvider与自定义用户对象扩展弹簧用户一起使用时,它也可以正常工作。
但是当我尝试使用自定义用户对象实现 UsersDetails接口设置spring security时,当我尝试使用其他帐户登录时,我收到了上面的消息。我无法弄清楚原因。

这是我的安全配置:

def Game(x, y):
    if __name__ == "__main__":
        main()

turtle.onscreenclick(Game)

我的自定义用户对象:

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

<authentication-manager>
    <authentication-provider ref="daoAuthenticationProvider"/>      
</authentication-manager>

<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <beans:property name="userDetailsService" ref="userDetailsServiceImplementation"></beans:property>
</beans:bean>

<beans:bean id="userDetailsServiceImplementation" class="com.company.service.implementation.UserServiceImpl" />

这是我的UserDetailsS​​ervice实现:

public class UserVo extends CommonVo implements UserDetails{
    private String username;
    private String password;
    private String firstName;
    private String lastName;
    private String enabled;

    private List<GrantedAuthority> userAuthorities;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEnabled() {
        return enabled;
    }
    public void setEnabled(String enabled) {
        this.enabled = enabled;
    }
    public List<GrantedAuthority> getUserAuthorities() {
        return userAuthorities;
    }
    public void setUserAuthorities(List<GrantedAuthority> userAuthorities) {
        this.userAuthorities = userAuthorities;
    }       

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return userAuthorities;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return "Y".equals(enabled) ? true : false;
    }

}

如果我返回扩展spring User类的对象,在这种情况下是LoginVo。

,这可以正常工作

4 个答案:

答案 0 :(得分:0)

对于并发控制,Spring Security使用SessionRegistry default implementation使用HashMap来存储内容。要使HashMap正常工作,您需要使用正确实施的hashCodeequals方法。如果您没有(或始终返回默认值),它将无法正常工作。

要解决,只需在自定义对象中实施正确的hashCodeequals方法。

答案 1 :(得分:0)

好的,我已经通过在原始问题的评论部分中关注@ m-deinum回答来解决我的问题。

我所做的是通过右键单击eclipse生成hashCode()equals() - &gt;来源 - &gt;在UserVo和CommonVo中生成hashCode()和equals()。

事实证明,如果我有自己的UsersDetail接口实现

,我必须重写上述两种方法

答案 2 :(得分:0)

如果有人在春季启动时遇到此问题,这是您必须在安全配置文件中添加的内容,除了M.Deinum Answer

//security configuration class for implementing spring security on urls
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    //for handling user success handler
    @Autowired
    private CustomizeAuthenticationSuccessHandler customizeAuthenticationSuccessHandler;
    @Override
    //this configuration is for handling user requests
    protected void configure(HttpSecurity http)  {
         try {
            http
                .authorizeRequests()
                .antMatchers("/orders").permitAll()
                .antMatchers("/createrole").permitAll()
                     .antMatchers("/login").permitAll()
                     .antMatchers("/admin/**").hasAuthority("admin")
                     .antMatchers("/agent/**").hasAuthority("agent")
                     .antMatchers("/distributor/**").hasAuthority("distributor")
                     .antMatchers("/home/**").hasAuthority("user").anyRequest()
                    .authenticated().and().csrf().disable().formLogin().successHandler(customizeAuthenticationSuccessHandler)
                    .loginPage("/login").failureUrl("/login?error=true")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .and().logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/logout.done").deleteCookies("JSESSIONID")
                    .invalidateHttpSession(true) 
                    .logoutSuccessUrl("/login").and().exceptionHandling().accessDeniedPage("/403");
            http.sessionManagement( ).maximumSessions(1). maxSessionsPreventsLogin(true);
            http.sessionManagement( ).sessionFixation( ).migrateSession( )
                    .sessionAuthenticationStrategy( registerSessionAuthStr( ) );

        } catch (Exception e) {
            // TODO Auto-generated catch block
            System.out.println("Exception here");
        }
    }


    //this method allows static resources to be neglected by spring security
    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring()
            .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**","/assets/**","/fonts/**","/dis/**","/vendor1/**","/mobile/**");
    }

    @Bean
    public SessionRegistry sessionRegistry( ) {
        SessionRegistry sessionRegistry = new SessionRegistryImpl( );
        return sessionRegistry;
    }
    @Bean
    public RegisterSessionAuthenticationStrategy registerSessionAuthStr( ) {
        return new RegisterSessionAuthenticationStrategy( sessionRegistry( ) );
    }
///Very important ,you wont login again after logout if you dont include this
    @Bean
    public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)  {
         //BCryptPasswordEncoder encoder = passwordEncoder();

    try {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    } catch (Exception e) {

        System.out.println("Login Failed");
    }
} 


}

答案 3 :(得分:0)

我正在开发没有任何启动配置的普通spring应用程序[Configure without xml] ...

我在客户中覆盖了我的hascode和equal方法。

5次或10次尝试获得味精后,我无法登录。[超过此主体的最大会话数为1]

我没有这种方法,如何在普通应用程序中实现。

 @Bean
    public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
    }

在控制台中-

会话被破坏-  会话是新建的-  会话被破坏-  会话是新建的-  会话被破坏- 会话是新创建的 会话是新建的---- 信息匿名用户..................