目录
session超时处理
session并发控制
如果要进行其他的一些特殊处理,比如判断是谁挤掉了上一个session,在@configuration中
如果要保证第一个浏览器登录,不让其他浏览器登录
session集群管理
session超时处理
在配置文件加上时间
//单位是秒,默认是30分钟
server.session.timeout = 10
配置了上面的没有生效,我们查看源码的,找到TomcatEmbeddedServletContainerFactory
private void configureSession(Context context) {
long sessionTimeout = this.getSessionTimeoutInMinutes();
context.setSessionTimeout((int)sessionTimeout);
if (this.isPersistSession()) {
Manager manager = context.getManager();
if (manager == null) {
manager = new StandardManager();
context.setManager((Manager)manager);
}
this.configurePersistSession((Manager)manager);
} else {
context.addLifecycleListener(new
TomcatEmbeddedServletContainerFactory.DisablePersistSessionListener());
}
}
private long getSessionTimeoutInMinutes() {
long sessionTimeout = (long)this.getSessionTimeout();
if (sessionTimeout > 0L) {
//秒数转换成分钟,返回的是最小分钟数字,6s会变成1分钟
sessionTimeout = Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout), 1L);
}
return sessionTimeout;
}
在@configuration,SpringSecurity配置中加上
.and()
.sessionManagement()
//session失效的时候,跳转的地址
.invalidSessionUrl("/session/invalid")
.and()
session失效之后跳转
@GetMapping("/session/invalid")
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
public SimpleResponse valid(){
return new SimpleResponse("session失效了");
}
session并发控制
常见场景:一个用户只能有一个session,用户在另一个地方登陆的时候,把其他地方的session失效掉
设置session失效时间和最大session数
//单位是秒,默认是30分钟
server.session.timeout = 600
//session失效的时候,跳转的地址
.and()
.sessionManagement()
.invalidSessionUrl("/session/invalid")
//最大session在线数,可以通过配置文件加载
.maximumSessions(1)
.and()
如果要进行其他的一些特殊处理,比如判断是谁挤掉了上一个session,在@configuration中
//session失效的时候,跳转的地址
.sessionManagement()
.invalidSessionUrl("/session/invalid")
.maximumSessions(1)
//imoocExpiredSessionStrategy 中包含session过期之后,跳转到的页面
.expiredSessionStrategy(imoocExpiredSessionStrategy )
创建SessionInformationExpiredStrategy类
public class ImoocExpiredSessionStrategy extends AbstractSessionStrategy implements SessionInformationExpiredStrategy {
public ImoocExpiredSessionStrategy(String invalidSessionUrl) {
super(invalidSessionUrl);
}
/* (non-Javadoc)
* @see org.springframework.security.web.session.SessionInformationExpiredStrategy#onExpiredSessionDetected(org.springframework.security.web.session.SessionInformationExpiredEvent)
*/
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
//调用抽象方法,session失效
onSessionInvalid(event.getRequest(), event.getResponse());
}
/* (non-Javadoc)
* @see com.imooc.security.browser.session.AbstractSessionStrategy#isConcurrency()
*/
@Override
protected boolean isConcurrency() {
return true;
}
}
AbstractSessionStrategy
public class AbstractSessionStrategy {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 跳转的url
*/
private String destinationUrl;
/**
* 重定向策略
*/
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
/**
* 跳转前是否创建新的session
*/
private boolean createNewSession = true;
private ObjectMapper objectMapper = new ObjectMapper();
/**
* @param invalidSessionUrl
* @param invalidSessionHtmlUrl
*/
public AbstractSessionStrategy(String invalidSessionUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
Assert.isTrue(StringUtils.endsWithIgnoreCase(invalidSessionUrl, ".html"), "url must end with '.html'");
this.destinationUrl = invalidSessionUrl;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.web.session.InvalidSessionStrategy#
* onInvalidSessionDetected(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.info("session失效");
if (createNewSession) {
request.getSession();
}
String sourceUrl = request.getRequestURI();
String targetUrl;
if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
targetUrl = destinationUrl;
logger.info("跳转到:"+targetUrl);
redirectStrategy.sendRedirect(request, response, targetUrl);
} else {
Object result = buildResponseContent(request);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(result));
}
}
/**
* @param request
* @return
*/
protected Object buildResponseContent(HttpServletRequest request) {
String message = "session已失效";
if (isConcurrency()) {
message = message + ",有可能是并发登录导致的";
}
return new SimpleResponse(message);
}
/**
* session失效是否是并发导致的
*
* @return
*/
protected boolean isConcurrency() {
return false;
}
/**
* Determines whether a new session should be created before redirecting (to
* avoid possible looping issues where the same session ID is sent with the
* redirected request). Alternatively, ensure that the configured URL does
* not pass through the {@code SessionManagementFilter}.
*
* @param createNewSession
* defaults to {@code true}.
*/
public void setCreateNewSession(boolean createNewSession) {
this.createNewSession = createNewSession;
}
}
AbstractSessionStrategy
这个时候,启动两个浏览器,只能有一个浏览器登录成功
如果要保证第一个浏览器登录,不让其他浏览器登录
在@configuration加上配置
.and()
.sessionManagement()
//session失效的时候,跳转的地址
.invalidSessionUrl("/session/invalid")
.maximumSessions(1)
.invalidSessionStrategy(invalidSessionStrategy)
.maximumSessions(1)
//当session达到maximumSessions,阻止后来的session登录
.maxSessionsPreventsLogin(true)
.expiredSessionStrategy(sessionInformationExpiredStrategy)
.and()