2016-05-31 88 views
0

我是Spring Boot和Spring Security的新成员,我在Spring Boot和Spring Security的github上观看了示例。我想将示例“spring-security-samples-concurrency-jc”与示例“spring-boot-sample-web-method-security”结合起来。当我在我的SecurityConfig中对sessionManagement的设置进行改动时扩展WebSecurityConfigurerAdapter.It不起作用。我的问题是如何在Springboot中添加HttpSessionEventPublisher Listenier。 在web.xml中Spring-Boot并发会话管理

<listener> 
<listener-class> 
org.springframework.security.web.session.HttpSessionEventPublisher 
</listener-class> 
</listener> 

在javaconfig

public class MessageSecurityWebApplicationInitializer extends 
     AbstractSecurityWebApplicationInitializer { 

    @Override 
    protected boolean enableHttpSessionEventPublisher() { 
     return true; 
    } 
} 

但是当我使用Spring的引导,如何增加这个监听器,使sessionManagement工作,换句话说,如何配置我的WebConfig.java使同一个用户每次只能登录一次,第二次登录被阻止在第一次登录失效或注销时使用。我的SecurityConfig.java如下图所示,对不起我的英文池:)

package com.eexcel.branch.config; 

import javax.sql.DataSource; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.autoconfigure.security.SecurityProperties; 
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.Ordered; 
import org.springframework.core.annotation.Order; 
import org.springframework.data.domain.AuditorAware; 
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; 
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 
import org.springframework.security.core.session.SessionRegistry; 
import org.springframework.security.core.session.SessionRegistryImpl; 
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 
import org.springframework.security.crypto.password.PasswordEncoder; 
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; 
import org.springframework.security.web.session.HttpSessionEventPublisher; 
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 

import com.eexcel.common.domain.SpringSecurityAuditorAware; 
import com.eexcel.common.service.distributor.DistributorService; 

@Configuration 
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) 
public class WebConfig extends WebMvcConfigurerAdapter { 
    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
     registry.addViewController("/login").setViewName("login"); 
    } 
    @Bean 
    public AuditorAware<String> auditor() { 
     return new SpringSecurityAuditorAware(); 
    } 
    @Bean 
    public SecurityEvaluationContextExtension expressionEvaluationContextProvider() { 
     return new SecurityEvaluationContextExtension(); 
    } 
    @Bean 
    public PasswordEncoder passwordEncoder() { 
     return new BCryptPasswordEncoder(); 
    } 
    @Bean 
    public ApplicationSecurity applicationSecurity() { 
     return new ApplicationSecurity(); 
    } 
    @Bean 
    public static SessionRegistry sessionRegistry() { 
     SessionRegistry sessionRegistry = new SessionRegistryImpl(); 
     return sessionRegistry; 
    } 
    @Bean 
    public static ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() { 
     return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(
       new HttpSessionEventPublisher()); 
    } 
    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
    protected static class ApplicationSecurity extends 
      WebSecurityConfigurerAdapter { 
     @Override 
     protected void configure(HttpSecurity http) throws Exception { 
      http.authorizeRequests().anyRequest().fullyAuthenticated().and() 
        .formLogin().loginPage("/login").failureUrl("/login?error") 
        .permitAll().and().logout() 
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) 
        .logoutSuccessUrl("/login?logout").permitAll().and() 
        .rememberMe().and().sessionManagement().maximumSessions(1) 
        .maxSessionsPreventsLogin(true) 
        .expiredUrl("/login?expired") 
        .sessionRegistry(sessionRegistry()); 
     } 
    } 
    @Order(Ordered.HIGHEST_PRECEDENCE) 
    @Configuration 
    protected static class AuthenticationManagerConfiguration extends 
      GlobalAuthenticationConfigurerAdapter { 
     @Autowired 
     private DataSource dataSource; 
     @Autowired 
     private PasswordEncoder passwordEncoder; 
     @Autowired 
     private DistributorService userDetailsService; 

     @Override 
     public void init(AuthenticationManagerBuilder auth) throws Exception { 
      auth.userDetailsService(userDetailsService).passwordEncoder(
        passwordEncoder); 
     } 
    } 
} 

回答

0

我的配置是正确的,为什么它不工作的原因是,我定义对象“CustomUserDetails”工具springsecurity的接口“的UserDetails”,而在SessionRegistryImpl方法

public List<SessionInformation> getAllSessions(Object principal, 
      boolean includeExpiredSessions) { 
     final Set<String> sessionsUsedByPrincipal = principals.get(principal); 

     if (sessionsUsedByPrincipal == null) { 
      return Collections.emptyList(); 
     } 

     List<SessionInformation> list = new ArrayList<SessionInformation>(
       sessionsUsedByPrincipal.size()); 

     for (String sessionId : sessionsUsedByPrincipal) { 
      SessionInformation sessionInformation = getSessionInformation(sessionId); 

      if (sessionInformation == null) { 
       continue; 
      } 

      if (includeExpiredSessions || !sessionInformation.isExpired()) { 
       list.add(sessionInformation); 
      } 
     } 

     return list; 
    } 

校长是

private final ConcurrentMap<Object, Set<String>> principals = new ConcurrentHashMap<Object, Set<String>>(); 

所以它得到的主体实例是CustomUserDetails,如果不重写EqualsAndHashCode,则principals.get(principal)始终为null。 终于我重写我的CustomUserDetails,它的作品。

@EqualsAndHashCode(callSuper = true, exclude = { "authorities", "sysOperator" }) 
public class CustomUserDetails extends SysOperator implements UserDetails { 
    private static final long serialVersionUID = 1L; 
    private List<String> authorities; 
    private SysOperator sysOperator; 

    public CustomUserDetails(SysOperator sysOperator, 
      final List<String> authorities) { 
     super(sysOperator); 
     this.authorities = authorities; 
     this.sysOperator = sysOperator; 
    } 

    @Override 
    public Collection<? extends GrantedAuthority> getAuthorities() { 
     String[] tmp = authorities.toArray(new String[authorities.size()]); 
     return AuthorityUtils.createAuthorityList(tmp); 
    } 

    @Override 
    public boolean isAccountNonExpired() { 
     return true; 
    } 

    @Override 
    public boolean isAccountNonLocked() { 
     return true; 
    } 

    @Override 
    public boolean isCredentialsNonExpired() { 
     return true; 
    } 

    @Override 
    public boolean isEnabled() { 
     return sysOperator.getEnable(); 
    } 

    @Override 
    public String getUsername() { 
     return sysOperator.getLoginName(); 
    } 
} 

@Entity 
@Table(name = "sys_operator") 
@EqualsAndHashCode(callSuper = false, exclude = { "realName", "password", 
     "mobile", "email", "enable", "remark", "roleIds", "branchNo", 
     "birthday" }) 
public class SysOperator extends IdEntity { 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 
    @Column(nullable = false, unique = true, length = 32) 
    private String loginName; 
    private String realName; 
    @Column(nullable = false) 
    private String password; 
    private String mobile; 
    @Column(nullable = false, unique = true, length = 32) 
    private String email; 
    @Column(nullable = false) 
    private Boolean enable; 
    private String remark; 
    @Column(nullable = true) 
    private String roleIds; 

    private String branchNo; 

    @Past 
    @Temporal(TemporalType.DATE) 
    private Date birthday; 

    public SysOperator(SysOperator sysOperator) { 
     BeanUtils.copyProperties(sysOperator, this); 
    } 

    public SysOperator() { 
     super(); 
    } 

    @Transient 
    public boolean isAdmin() { 
     return (AuthConsts.ADMIN.equalsIgnoreCase(this.loginName) || Arrays 
       .asList(AuthConsts.ADMIN_GROUP).contains(this.loginName)); 
    } 

    public String getLoginName() { 
     return loginName; 
    } 

    public void setLoginName(String loginName) { 
     this.loginName = loginName; 
    } 

    public String getRealName() { 
     return realName; 
    } 

    public void setRealName(String realName) { 
     this.realName = realName; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    public String getMobile() { 
     return mobile; 
    } 

    public void setMobile(String mobile) { 
     this.mobile = mobile; 
    } 

    public String getEmail() { 
     return email; 
    } 

    public void setEmail(String email) { 
     this.email = email; 
    } 

    public String getRemark() { 
     return remark; 
    } 

    public void setRemark(String remark) { 
     this.remark = remark; 
    } 

    public String getRoleIds() { 
     return roleIds; 
    } 

    public void setRoleIds(String roleIds) { 
     this.roleIds = roleIds; 
    } 

    public Boolean getEnable() { 
     return enable; 
    } 

    public void setEnable(Boolean enable) { 
     this.enable = enable; 
    } 

    public String getBranchNo() { 
     return branchNo; 
    } 

    public void setBranchNo(String branchNo) { 
     this.branchNo = branchNo; 
    } 

    public Date getBirthday() { 
     return birthday; 
    } 

    public void setBirthday(Date birthday) { 
     this.birthday = birthday; 
    } 

    @Override 
    public String toString() { 
     return ToStringBuilder.reflectionToString(this); 
    } 
}