Spring boot +Spring security4 config 配置同账号登录只允许一个在线


关于网上说的http方式配置无效问题,经验证,有点误导人,并且配置方式感觉过于复杂。

目前这种方式感觉是最简洁的一种方式。

一、核心配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private SessionRegistry sessionRegistry;

    /**
     * 设置URL的验证规则 Request层面的配置,对应XML Configuration中的<http>元素
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login.html", "/logout.html").permitAll()
                .anyRequest().authenticated(); //登陆和登出可以匿名访问,其他的请求都必须要有权限认证
        http.addFilterBefore(myValidCodeProcessingFilter(), UsernamePasswordAuthenticationFilter.class);//添加自定义验证规则

        http.formLogin()
                .loginPage("/login.html")//设置登陆页面
                .loginProcessingUrl("/login")//登陆处理路径

        http.logout()
                .logoutUrl("/logout.html")//设置登出处理的url
                .logoutSuccessUrl("/");//设置登出成功后跳转页面,默认是跳转到登录页面

        http.headers()
                .frameOptions()//解决不允许显示在iframe的问题
                .sameOrigin()
                .httpStrictTransportSecurity()
                .disable();

        http.csrf()
                .disable();//关闭crsf

        //session管理
        //session失效后跳转
        http.sessionManagement()
		.invalidSessionUrl("/login.html");  

	http.sessionManagement()//只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面
               	.maximumSessions(1) 
		.sessionRegistry(sessionRegistry) 
		.expiredUrl("/login.html");
    }


    //session失效跳转
    private SessionInformationExpiredStrategy sessionInformationExpiredStrategy() {
        return new SimpleRedirectSessionInformationExpiredStrategy("/login.html");
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    //SpringSecurity内置的session监听器
    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

    @Bean
    public MyValidCodeProcessingFilter myValidCodeProcessingFilter() throws Exception {
        MyValidCodeProcessingFilter filter = new MyValidCodeProcessingFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        //设置登陆成功后跳转的URL
        filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/index.html"));
        //设置登陆失败后跳转的URL
        //如果不设置这两个属性,会导致登陆成功后访问默认地址/
        filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login.html?error=1"));
        filter.setSessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry));
        return filter;
    }

    //其他代码省略···
}



二、重要的一步:重写User的hashCode、toString和equals方法。(如果继承的UserDetails,则重写UserDetails的三个方法)

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

/**
 * @author Xie Yuan You
 * <p>Created in 上午 11:30 2017/3/1 0001
 * @version v.0.0.1
 *	
 */
public class SecurityUser extends User {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private User sysUser;

	public SecurityUser(String username, String password, boolean enabled, boolean accountNonExpired,
                        boolean credentialsNonExpired, boolean accountNonLocked,
                        Collection<? extends GrantedAuthority> authorities) {
		super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);

	}

	public User getSysUser() {
		return sysUser;
	}

	public void setSysUser(User sysUser) {
		this.sysUser = sysUser;
	}

	/**
	 * 重写方法用于sessionRegistry
	 * @return
	 */
	@Override
	public String toString() {
		return super.getUsername();
	}

	/**
	 * 重写方法用于sessionRegistry
	 * @return
	 */
	@Override
	public boolean equals(Object rhs) {
		return this.toString().equals(rhs.toString());
	}

	/**
	 * 重写方法用于sessionRegistry
	 * @return
	 */
	@Override
	public int hashCode() {
		return super.getUsername().hashCode();
	}
}



三、重写UsernamePasswordAuthenticationFilter:用户名密码验证通过后,注册session

public class MyValidCodeProcessingFilter extends UsernamePasswordAuthenticationFilter {

    //省略部分代码......
    @Resource
    private SessionRegistry sessionRegistry;
	

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        
	//省略部分代码......
 
	UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
	//用户名密码验证通过后,注册session
        sessionRegistry.registerNewSession(request.getSession().getId(),token.getPrincipal());

        
	//省略部分代码......
 	this.setDetails(request, token); 
	return this.getAuthenticationManager().authenticate(token); 
	}
 }




















评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值