您的位置:首页 > 编程语言 > Java开发

springboot + security 自定义session过期处理方式

2017-12-27 10:26 916 查看
security校验session校验是在ConcurrentSessionFilter,在doFilter方法里可以看到如果session过期会执行方法

this.doLogout(request, response);
this.sessionInformationExpiredStrategy.onExpiredSessionDetected(new SessionInformationExpiredEvent(info, request, response));


先做退出操作,在执行session过期策略,这个策略的初始化是在SessionManagementConfigurer.getExpiredSessionStrategy

SessionInformationExpiredStrategy getExpiredSessionStrategy() {
if(this.expiredSessionStrategy != null) {
return this.expiredSessionStrategy;
} else if(this.expiredUrl == null) {
return null;
} else {
if(this.expiredSessionStrategy == null) {
this.expiredSessionStrategy = new SimpleRedirectSessionInformationExpiredStrategy(this.expiredUrl);
}

return this.expiredSessionStrategy;
}
}


所以如果你没有设置默认的策略和expiredUrl

private ConcurrentSessionFilter createConccurencyFilter(H http) {
SessionInformationExpiredStrategy expireStrategy = this.getExpiredSessionStrategy();
SessionRegistry sessionRegistry = this.getSessionRegistry(http);
return expireStrategy == null?new ConcurrentSessionFilter(sessionRegistry):new ConcurrentSessionFilter(sessionRegistry, expireStrategy);
}


构参里默认的是ResponseBodySessionInformationExpiredStrategy策略,

public ConcurrentSessionFilter(SessionRegistry sessionRegistry) {
Assert.notNull(sessionRegistry, "SessionRegistry required");
this.sessionRegistry = sessionRegistry;
this.sessionInformationExpiredStrategy = new ConcurrentSessionFilter.ResponseBodySessionInformationExpiredStrategy(null);
}


默认策略里如果session过期,退出后执行的是,就是往response里写了一段话,这不是我们想要的结果,所以这里只有自定义策略,复写onExpiredSessionDetected就可以了

public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
HttpServletResponse response = event.getResponse();
response.getWriter().print("This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).");
response.flushBuffer();
}


所以这里自定义

@Component
public class AjaxSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
HttpServletResponse response = event.getResponse();
HttpServletRequest request = event.getRequest();
JSONObject returnObj = new JSONObject();
if (RequestUtils.isAjax(request)) {
returnObj.put("status", "0");
} else {
returnObj.put("status", "-1");
returnObj.put("message", "非法登录");
}
response.setContentType("application/json;charset=UTF-8");
response.getWriter().print(returnObj.toJSONString());
response.flushBuffer();
}
}


这里设置contentType需要注意

如果是

response.getWriter().print(returnObj.toJSONString());
response.setContentType("application/json;charset=UTF-8");


那设置的编码格式就会失败,看源码就会知道

public void setContentType(String type) {
if(type != null && !this.insideInclude && !this.responseStarted()) {
ContentTypeInfo ct = this.servletContext.parseContentType(type);
this.contentType = ct.getContentType();
boolean useCharset = false;
if(ct.getCharset() != null && this.writer == null && !this.isCommitted()) {
this.charset = ct.getCharset();
this.charsetSet = true;
useCharset = true;
}

if(!useCharset && this.charsetSet) {
if(ct.getCharset() == null) {
this.exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ct.getHeader() + "; charset=" + this.charset);
} else {
this.exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ct.getContentType() + "; charset=" + this.charset);
}
} else {
this.exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, ct.getHeader());
}

}
}


如果先往writer里写入内容,那么this.writer == null就是false,useCharset 就是false,设置的编码就是ISO-8859-1,在客户端接受的中文会乱码。

之后再securityConfig里配置

http.sessionManagement().
/**
* 同一个账号只能在一个地方登陆
*/
maximumSessions(1).

4000
/**
* 自定义session过期策略,替代默认的{@link ConcurrentSessionFilter.ResponseBodySessionInformationExpiredStrategy},
* 复写onExpiredSessionDetected方法,默认方法只输出异常,没业务逻辑。这里需要返回json
*/
expiredSessionStrategy(ajaxSessionInformationExpiredStrategy);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐