Session失效时间:
springboot配置session失效时间,只需要在application.properties里配置
#session超时时间,低于60秒按60秒
server.session.timeout = 60
如果想自己定义session失效的提示信息,需要配置:
@Configuration //这是一个配置
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
//版本二:可配置的登录页
@Override
protected void configure(HttpSecurity http) throws Exception {
//~~~-------------> 图片验证码过滤器 <------------------
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
//验证码过滤器中使用自己的错误处理
validateCodeFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);
//配置的验证码过滤url
validateCodeFilter.setSecurityProperties(securityProperties);
validateCodeFilter.afterPropertiesSet();
//~~~-------------> 短信验证码过滤器 <------------------
SmsCodeFilter smsCodeFilter = new SmsCodeFilter();
//验证码过滤器中使用自己的错误处理
smsCodeFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);
//配置的验证码过滤url
smsCodeFilter.setSecurityProperties(securityProperties);
smsCodeFilter.afterPropertiesSet();
//实现需要认证的接口跳转表单登录,安全=认证+授权
//http.httpBasic() //这个就是默认的弹框认证
//
http
.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
// .apply(imoocSocialSecurityConfig)//社交登录
// .and()
//把验证码过滤器加载登录过滤器前边
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
//----------表单认证相关配置---------------
.formLogin()
.loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL) //处理用户认证BrowserSecurityController
//登录过滤器UsernamePasswordAuthenticationFilter默认登录的url是"/login",在这能改
.loginProcessingUrl(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM)
.successHandler(imoocAuthenticationSuccessHandler)//自定义的认证后处理器
.failureHandler(imoocAuthenticationFailureHandler) //登录失败后的处理
.and()
//------------记住我相关配置 -------------
.rememberMe()
.tokenRepository(persistentTokenRepository())//TokenRepository,登录成功后往数据库存token的
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//记住我秒数
.userDetailsService(userDetailsService) //记住我成功后,调用userDetailsService查询用户信息
.and()//-----------session相关配置---------------
.sessionManagement()
// .invalidSessionStrategy(invalidSessionStrategy)
// .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
// .maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
// .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())//阻止在登录
// .expiredSessionStrategy(sessionInformationExpiredStrategy) //session失效策略
.and() //?俩and为啥呢
// .and()
//-----------授权相关的配置 ---------------------
.authorizeRequests()
// /authentication/require:处理登录,securityProperties.getBrowser().getLoginPage():用户配置的登录页
.antMatchers(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
securityProperties.getBrowser().getLoginPage(),//放过登录页不过滤,否则报错
SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,
SecurityConstants.SESSION_INVALID_PAGE,
SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*").permitAll() //验证码
.anyRequest() //任何请求
.authenticated() //都需要身份认证
.and()
.csrf().disable() //关闭csrf防护
.apply(smsCodeAuthenticationSecurityConfig);//把短信验证码配置应用上
}
}
public static final String SESSION_INVALID_PAGE = "/session/invalid";
@GetMapping("/session/invalid")
@ResponseStatus(code = HttpStatus.UNAUTHORIZED)
public SimpleResponse toSessionInvalidPage(){
String message = "session 失效!";
return new SimpleResponse(message);
}
一个账户同时默认是可以在多处登录的,如果想要后边的登录踢出前边的登录,只要放开 .maximumSessions(1) 这句配置即可。
session并发控制:
也可以自定义session失效策略,自定义一个类ImoocExpiredSessionStrategy2:
package com.imooc.security.browser.session;
import java.io.IOException;
import javax.servlet.ServletException;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
/**
* session失效策略,简单版本
* ClassName: ImoocExpiredSessionStrategy
* @Description: TODO
* @author lihaoyang
* @date 2018年3月8日
*/
public class ImoocExpiredSessionStrategy2 implements SessionInformationExpiredStrategy{
/**
* SessionInformationExpiredEvent:session失效事件,能拿到request、response
*/
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
//可以从event中拿到request中的信息
event.getResponse().setContentType("application/json;charset=UTF-8");
event.getResponse().getWriter().write("并发登录!");
}
}
加上配置:
.sessionManagement()
// .invalidSessionStrategy(invalidSessionStrategy)
// .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
.maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
.expiredSessionStrategy(new ImoocExpiredSessionStrategy2()) //简洁版session失效策略
此时如果第二次登录,第一个登录就会提示:
如果想阻止多处登录,可以加上这句配置:
.sessionManagement()
// .invalidSessionStrategy(invalidSessionStrategy)
// .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
.maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
.expiredSessionStrategy(new ImoocExpiredSessionStrategy2()) //简洁版session失效策略
.maxSessionsPreventsLogin(true) //阻止并发登录
此时如果多出登录,后者就会提示
重构:将session失效策略自己实现
/**
*
*/
package com.imooc.security.browser.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.session.InvalidSessionStrategy;
/**
* @author zhailiang
*
*/
public class ImoocInvalidSessionStrategy extends AbstractSessionStrategy implements InvalidSessionStrategy {
public ImoocInvalidSessionStrategy(String invalidSessionUrl) {
super(invalidSessionUrl);
}
@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
onSessionInvalid(request, response);
}
}
session过期策略:
package com.imooc.security.browser.session;
import java.io.IOException;
import javax.servlet.ServletException;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
/**
* session失效策略
* ClassName: ImoocExpiredSessionStrategy
* @Description: TODO
* @author lihaoyang
* @date 2018年3月8日
*/
public class ImoocExpiredSessionStrategy extends AbstractSessionStrategy implements SessionInformationExpiredStrategy
{
/**
* SessionInformationExpiredEvent:session失效事件,能拿到request、response
*/
// @Override
// public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
// event.getResponse().setContentType("application/json;charset=UTF-8");
// event.getResponse().getWriter().write("并发登录!");
// }
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 {
onSessionInvalid(event.getRequest(), event.getResponse());
}
/* (non-Javadoc)
* @see com.imooc.security.browser.session.AbstractSessionStrategy#isConcurrency()
*/
@Override
protected boolean isConcurrency() {
return true;
}
}
AbstractSessionStrategy:
/**
*
*/
package com.imooc.security.browser.session;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.security.browser.support.SimpleResponse;
/**
* @author zhailiang
*
*/
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)'");
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 {
if (createNewSession) {
request.getSession();
}
String sourceUrl = request.getRequestURI();
String targetUrl;
if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
targetUrl = destinationUrl;//+".html";
logger.info("session失效,跳转到"+targetUrl);
redirectStrategy.sendRedirect(request, response, targetUrl);
}else{
String message = "session已失效";
if(isConcurrency()){
message = message + ",有可能是并发登录导致的";
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(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;
}
}
配置:
.sessionManagement()
//++++++=基本这样配置++++++++
// .invalidSessionUrl(SecurityConstants.SESSION_INVALID_PAGE) //session失效跳转地址,如果简单的处理只要这一个就够了
// .maximumSessions(1) //一个用户只能登录一次,踢出前边登录用户
// .expiredSessionStrategy(new ImoocExpiredSessionStrategy2()) //简洁版session失效策略
// .maxSessionsPreventsLogin(true) //阻止并发登录
//
//++++++++重构后+++++++
.invalidSessionStrategy(invalidSessionStrategy)
.maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())//阻止在登录
.expiredSessionStrategy(sessionInformationExpiredStrategy) //session失效策略