当前位置 博文首页 > 程序员石磊:spring security 个性化登录策略
最近做一个项目,安全框架采用spring security 。由于业务需要,要限制一个账户只能登录一次,不能在多个浏览器登录,也就是一个账户只能对应一个sessionid。这个很好实现,配置上默认的 session并发策略ConcurrentSessionControlAuthenticationStrategy类,设置maximumSessions值为1。代码如下:
<sec:http use-expressions="false" auto-config="true">
<sec:session-management invalid-session-url="/sessionexpired" session-authentication-strategy ref="sas" />
</sec:http>
<bean id="sas"
class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<bean
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
<property name="maximumSessions" value="1" />
<property name="exceptionIfMaximumExceeded" value="false" />
</bean>
</list>
</constructor-arg>
</bean>
但是这样如果账户a在一个地方登录,然后又换另外一个地方登录,后登录的会导致前一个用户session失效,也就是会踢掉前面登录的用户。这样是不允许的,而需要要求是,可以根据用户某个状态来判断,如果用户处在空闲状态,就允许同一个账号后登录的踢掉前面登录的,如果是繁忙状态就不允许登录。经过研究ConcurrentSessionControlAuthenticationStrategy类的源码,获得灵感,自定义一个SessionAuthenticationStrategy的实现类CloudqControlAuthenticationStrategy,里面增加状态判断,如果不满足条件就抛出异常,问题就可以解决了。配置代码如下:
<bean id="sas"
class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<bean
class="com.raymon.cloudq.security.CloudqControlAuthenticationStrategy">
</bean>
<bean
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
<property name="maximumSessions" value="1" />
<property name="exceptionIfMaximumExceeded" value="false" />
</bean>
</list>
</constructor-arg>
</bean>
自定义策略代码:
public class CloudqControlAuthenticationStrategy implements SessionAuthenticationStrategy {
private org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onAuthentication(Authentication authentication, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws SessionAuthenticationException {
AuthUserDetails authUserDetails=(AuthUserDetails)authentication.getPrincipal();
Integer branchesId=authUserDetails.getClientEmpUser().getBranchesId();
Integer empId=authUserDetails.getClientEmpUser().getEmpId();
if(条件不满足){//抛出异常
throw new SessionAuthenticationException(message);
}
}
}
注意自定义策略的放置顺序要在其他策略前面,否则可能会造成自己的业务逻辑执行过晚,进而达不到目的。
cs