问题描述
在 SpringSecurity 中,我想配置一个关于session并发的控制,于是我是这样配置的
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.invalidSessionStrategy(new InvalidSessionStrategyImpl())
.maximumSessions(-1).expiredSessionStrategy(expiredSessionStrategy())//配置并发登录,-1表示不限制
.sessionRegistry(sessionRegistry());
}
上下文的配置我在此省略了
这里设置 maximumSessions 为 -1,表示不限制同一账号登录的客户端数
session过期后执行的逻辑是进入我自定义的类 expiredSessionStrategy() 中
因为我是构建的 rest 服务,所以我是返回的 http 状态码
public class ExpiredSessionStrategyImpl implements SessionInformationExpiredStrategy {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
event.getResponse().sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED,
JSONObject.toJSONString(MessageBody.failure(405,"not login or login has been expired")));
}
}
在这里,问题就来了
我测试的时候,把 -1 改成了 1,之后登录同一个用户,后面登录的用户会把前面一个已经登录的用户挤下线,就是说之前登录的那个用户的session 会过期
就是说他所在的页面再发送任何请求的话会收到我返回的 405 状态码
在这里是没问题的
问题就在发完一个请求后,在发一个请求,在浏览器的 network 上会看到发出的请求会被重定向的 /login 请求上
后续再发任何请求都会被重定向到 /login 上
问题思考
为什么会出现这样的情况呢?
为什么会第一个请求会收到405的状态码,后续的请求会被重定向到 /login 呢?
通过 debug 断点,我定位到过滤器的前置执行方法 beforeInvocation() 上
protected InterceptorStatusToken beforeInvocation(Object object) {
Assert.notNull(object, "Object was null");
final boolean debug = logger.isDebugEnabled();
if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
throw new IllegalArgumentException(
"Security invocation attempted for object "
+ object.getClass().getName()
+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "
+ getSecureObjectClass());
}
Collection attributes = this.obtainSecurityMetadataSource()
.getAttributes(object);
if (attributes == null || attributes.isEmpt