一、背景
在有些场景下,我们需要限制同一用户的登录数量限制。比如有些重要的账号,同一时刻只能有登录一次。
再比如类似爱奇艺的会员制,同一时刻只能登录5次。
此文对于登录的限制,采取的做法是:若发现同一用户登录了两次,则后者会将前者的 session 剔除,即要求前者再次登录。(有些场景下的限制是限制后者无法登录,本文暂不介绍)
二、实现
本文介绍的是基于 SpringSecurity 的一套实现逻辑,个人实现部分比较简单,底层实现交由框架处理了。本文介绍的是基于 SpringBoot 的注解式配置,xml 版本的配置大同小异。
① 配置
最重要的是下面代码的最后一行配置,设置 maximumSessions(2) 的值为2,代表同一个用户最大能同时登录2次,调整为1则代表同时只能登录一次。/** * Created by jet.chen on 2018/4/12. */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired SuccessLoginHandler successLoginHandler; @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.authorizeRequests() //所有静态资源及mobile资源都忽略权限控制 .antMatchers("/resources/**", "/staff/forgotPassword/**", "/sms/sendVaildateCode", "/sms/login", "/auth/**", "/api/**" ) .permitAll() //任意请求角色必须为用户或者管理员 // .anyRequest().hasAnyRole("USER", "ADMIN") .anyRequest().authenticated() .and() //下面标示的路径不用进行CSRF验证 .csrf().disable() //配置表单登陆 .formLogin() //配置登陆页面路径并允许所有人访问登陆页面 .loginPage("/login").permitAll() .successHandler(successLoginHandler) //登陆成功时的处理类 .and() //配置登出页面路径并允许所有人访问登陆页面 .logout().logoutUrl("/logout").permitAll() .and() .rememberMe() .rememberMeParameter("remember-me") .tokenValiditySeconds(30*60*1000) // cookie有效期是30分钟 .rememberMeCookieName("RM_COOKIE"); httpSecurity.sessionManagement().maximumSessions(2).expiredUrl("/login"); } }
② 用户实体类的改造
我们自定义了一个实体类 public class StaffProfile implements Serializable, UserDetails{ } 注意,UserDetails 来自如下包:org.springframework.security.core.userdetails.UserDetails; 关键点是实体类需要重写如下三个方法:toString、hashCode、equals, 原有下文介绍,代码如下:@Override public String toString() { return this.loginName; } @Override public int hashCode() { return loginName.hashCode(); } @Override public boolean equals(Object obj) { System.out.println(obj.getClass()); return obj instanceof UserDetails && this.toString().equals(obj.toString()); }
三、源码解析
此文所说的控制用户的登录数,实现方式其实就是控制同一用户创建的 session 数,达到阀值,则剔除最早的 session。关键代码是 org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy 类下的方法:onAuthentication() 大致流程是,当按照上文所述设置了maximumSessions()之后,所有的请求都会走这个方法,这个方法会先获取该用户建立的所有 session,如果已建立的 session数量大于预设值,则会删除最早建立的 session;
文章评论
如何配置,普通用户限制1次登录,vip用户限制5次登录