我是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中
<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-Boot时,如何添加此Listener以使sessionManagement工作,换句话说,如何配置我的WebConfig.java以使同一用户一次只能登录一次,第二次登录是在第一次登录过期或注销时阻止了util.My 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 :(得分: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>>();
因此它获取Principal的实例是CustomUserDetails,如果不重写EqualsAndHashCode,则principalals.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);
}
}