Commit b57f9f00 by naan1993

完善session机制

parent 75ff57bc
...@@ -6,13 +6,10 @@ import com.stylefeng.guns.common.page.PageInfoBT; ...@@ -6,13 +6,10 @@ import com.stylefeng.guns.common.page.PageInfoBT;
import com.stylefeng.guns.common.warpper.BaseControllerWarpper; import com.stylefeng.guns.common.warpper.BaseControllerWarpper;
import com.stylefeng.guns.core.support.HttpKit; import com.stylefeng.guns.core.support.HttpKit;
import com.stylefeng.guns.core.util.FileUtil; import com.stylefeng.guns.core.util.FileUtil;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
...@@ -20,8 +17,6 @@ import javax.servlet.http.HttpServletResponse; ...@@ -20,8 +17,6 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@Component
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST)
public class BaseController { public class BaseController {
protected static String SUCCESS = "SUCCESS"; protected static String SUCCESS = "SUCCESS";
...@@ -44,6 +39,10 @@ public class BaseController { ...@@ -44,6 +39,10 @@ public class BaseController {
return HttpKit.getRequest().getSession(); return HttpKit.getRequest().getSession();
} }
protected HttpSession getSession(Boolean flag) {
return HttpKit.getRequest().getSession(flag);
}
protected String getPara(String name) { protected String getPara(String name) {
return HttpKit.getRequest().getParameter(name); return HttpKit.getRequest().getParameter(name);
} }
......
package com.stylefeng.guns.common.controller; package com.stylefeng.guns.common.controller;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
/** /**
...@@ -22,4 +23,15 @@ public class GlobalController { ...@@ -22,4 +23,15 @@ public class GlobalController {
public String errorPage() { public String errorPage() {
return "/404.html"; return "/404.html";
} }
/**
* 跳转到session超时页面
*
* @author fengshuonan
*/
@RequestMapping(path = "/sessionError")
public String errorPageInfo(Model model) {
model.addAttribute("tips", "session超时");
return "/login.html";
}
} }
...@@ -47,6 +47,7 @@ public enum BizExceptionEnum { ...@@ -47,6 +47,7 @@ public enum BizExceptionEnum {
* 错误的请求 * 错误的请求
*/ */
REQUEST_NULL(400, "请求有错误"), REQUEST_NULL(400, "请求有错误"),
SESSION_TIMEOUT(400, "会话超时"),
SERVER_ERROR(500, "服务器异常"); SERVER_ERROR(500, "服务器异常");
BizExceptionEnum(int code, String message) { BizExceptionEnum(int code, String message) {
......
...@@ -28,7 +28,9 @@ public class GunsProperties { ...@@ -28,7 +28,9 @@ public class GunsProperties {
private Boolean haveCreatePath = false; private Boolean haveCreatePath = false;
private Integer sessionInvalidateTime = 10 * 60; //session 失效时间(默认为10分钟 单位:秒) private Integer sessionInvalidateTime = 30 * 60; //session 失效时间(默认为30分钟 单位:秒)
private Integer sessionValidationInterval = 15 * 60; //session 验证失效时间(默认为15分钟 单位:秒)
public String getFileUploadPath() { public String getFileUploadPath() {
//如果没有写文件上传路径,保存到临时目录 //如果没有写文件上传路径,保存到临时目录
...@@ -76,4 +78,12 @@ public class GunsProperties { ...@@ -76,4 +78,12 @@ public class GunsProperties {
public void setSessionInvalidateTime(Integer sessionInvalidateTime) { public void setSessionInvalidateTime(Integer sessionInvalidateTime) {
this.sessionInvalidateTime = sessionInvalidateTime; this.sessionInvalidateTime = sessionInvalidateTime;
} }
public Integer getSessionValidationInterval() {
return sessionValidationInterval;
}
public void setSessionValidationInterval(Integer sessionValidationInterval) {
this.sessionValidationInterval = sessionValidationInterval;
}
} }
package com.stylefeng.guns.config.web; package com.stylefeng.guns.config.web;
import com.stylefeng.guns.config.properties.GunsProperties;
import com.stylefeng.guns.core.shiro.ShiroDbRealm; import com.stylefeng.guns.core.shiro.ShiroDbRealm;
import org.apache.shiro.cache.CacheManager; import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.cache.ehcache.EhCacheManager;
...@@ -9,7 +10,10 @@ import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSource ...@@ -9,7 +10,10 @@ import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSource
import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.ShiroHttpSession;
import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
...@@ -33,15 +37,35 @@ public class ShiroConfig { ...@@ -33,15 +37,35 @@ public class ShiroConfig {
* 安全管理器 * 安全管理器
*/ */
@Bean @Bean
public DefaultWebSecurityManager securityManager(CookieRememberMeManager rememberMeManager, CacheManager cacheShiroManager) { public DefaultWebSecurityManager securityManager(CookieRememberMeManager rememberMeManager, CacheManager cacheShiroManager, DefaultWebSessionManager defaultWebSessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(this.shiroDbRealm()); securityManager.setRealm(this.shiroDbRealm());
securityManager.setCacheManager(cacheShiroManager); securityManager.setCacheManager(cacheShiroManager);
securityManager.setRememberMeManager(rememberMeManager); securityManager.setRememberMeManager(rememberMeManager);
securityManager.setSessionManager(defaultWebSessionManager);
return securityManager; return securityManager;
} }
/** /**
* session管理器
*/
@Bean
public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager, GunsProperties gunsProperties) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setCacheManager(cacheShiroManager);
sessionManager.setSessionValidationInterval(gunsProperties.getSessionValidationInterval() * 1000);
sessionManager.setGlobalSessionTimeout(gunsProperties.getSessionInvalidateTime() * 1000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
cookie.setName("shiroCookie");
cookie.setHttpOnly(true);
sessionManager.setSessionIdCookie(cookie);
return sessionManager;
}
/**
* 缓存管理器 使用Ehcache实现 * 缓存管理器 使用Ehcache实现
*/ */
@Bean @Bean
...@@ -111,6 +135,7 @@ public class ShiroConfig { ...@@ -111,6 +135,7 @@ public class ShiroConfig {
Map<String, String> hashMap = new HashMap<>(); Map<String, String> hashMap = new HashMap<>();
hashMap.put("/static/**", "anon"); hashMap.put("/static/**", "anon");
hashMap.put("/login", "anon"); hashMap.put("/login", "anon");
hashMap.put("/global/sessionError", "anon");
hashMap.put("/kaptcha", "anon"); hashMap.put("/kaptcha", "anon");
hashMap.put("/**", "user"); hashMap.put("/**", "user");
shiroFilter.setFilterChainDefinitionMap(hashMap); shiroFilter.setFilterChainDefinitionMap(hashMap);
...@@ -144,6 +169,7 @@ public class ShiroConfig { ...@@ -144,6 +169,7 @@ public class ShiroConfig {
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator(); return new DefaultAdvisorAutoProxyCreator();
} }
@Bean @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
......
...@@ -11,6 +11,8 @@ import org.apache.log4j.Logger; ...@@ -11,6 +11,8 @@ import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException; import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.DisabledAccountException; import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.UnknownSessionException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
...@@ -18,6 +20,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler; ...@@ -18,6 +20,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.UndeclaredThrowableException;
import static com.stylefeng.guns.core.support.HttpKit.getIp; import static com.stylefeng.guns.core.support.HttpKit.getIp;
...@@ -132,4 +136,40 @@ public class GlobalExceptionHandler { ...@@ -132,4 +136,40 @@ public class GlobalExceptionHandler {
return new ErrorTip(BizExceptionEnum.SERVER_ERROR); return new ErrorTip(BizExceptionEnum.SERVER_ERROR);
} }
/**
* session失效的异常拦截
*
* @author stylefeng
* @Date 2017/6/7 21:02
*/
@ExceptionHandler(InvalidSessionException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String sessionTimeout(InvalidSessionException e, Model model, HttpServletRequest request, HttpServletResponse response) {
model.addAttribute("tips", "session超时");
assertAjax(request, response);
return "/login.html";
}
/**
* session异常
*
* @author stylefeng
* @Date 2017/6/7 21:02
*/
@ExceptionHandler(UnknownSessionException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String sessionTimeout(UnknownSessionException e, Model model, HttpServletRequest request, HttpServletResponse response) {
model.addAttribute("tips", "session超时");
assertAjax(request, response);
return "/login.html";
}
private void assertAjax(HttpServletRequest request, HttpServletResponse response) {
if (request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
//如果是ajax请求响应头会有,x-requested-with
response.setHeader("sessionstatus", "timeout");//在响应头设置session状态
}
}
} }
package com.stylefeng.guns.core.intercept;
import com.stylefeng.guns.common.controller.BaseController;
import com.stylefeng.guns.core.shiro.ShiroKit;
import com.stylefeng.guns.core.support.HttpKit;
import org.apache.shiro.session.InvalidSessionException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
/**
* 验证session超时的拦截器
*
* @author fengshuonan
* @date 2017年6月7日21:08:48
*/
@Aspect
@Component
@ConditionalOnProperty(prefix = "guns", name = "session-open", havingValue = "true")
public class SessionTimeoutInterceptor extends BaseController {
@Pointcut("execution(* com.stylefeng.guns.*..controller.*.*(..))")
public void cutService() {
}
@Around("cutService()")
public Object sessionTimeoutValidate(ProceedingJoinPoint point) throws Throwable {
String servletPath = HttpKit.getRequest().getServletPath();
if (servletPath.equals("/kaptcha") || servletPath.equals("/login")) {
return point.proceed();
}else{
if(ShiroKit.getSession().getAttribute("sessionFlag") == null){
ShiroKit.getSubject().logout();
throw new InvalidSessionException();
}else{
return point.proceed();
}
}
}
}
...@@ -101,6 +101,8 @@ public class LoginController extends BaseController { ...@@ -101,6 +101,8 @@ public class LoginController extends BaseController {
LogManager.me().executeLog(LogTaskFactory.loginLog(shiroUser.getId(), getIp())); LogManager.me().executeLog(LogTaskFactory.loginLog(shiroUser.getId(), getIp()));
ShiroKit.getSession().setAttribute("sessionFlag",true);
return REDIRECT + "/"; return REDIRECT + "/";
} }
......
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
guns: guns:
swagger-open: true #是否开启swagger (true/false) swagger-open: true #是否开启swagger (true/false)
kaptcha-open: false #是否开启登录时验证码 (true/false) kaptcha-open: false #是否开启登录时验证码 (true/false)
session-open: false #是否开启session验证 (true/false)
#file-upload-path: d:/tmp #文件上传目录(不配置的话为java.io.tmpdir目录) #file-upload-path: d:/tmp #文件上传目录(不配置的话为java.io.tmpdir目录)
session-invalidate-time: 600 #session失效时间 单位:秒 session-invalidate-time: 1800 #session失效时间 单位:秒
session-validation-interval: 900 #多久检测一次失效的session 单位:秒
################### 项目启动端口 ################### ################### 项目启动端口 ###################
server: server:
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="renderer" content="webkit" /><!-- 让360浏览器默认选择webkit内核 --> <meta name="renderer" content="webkit"/><!-- 让360浏览器默认选择webkit内核 -->
<!-- 全局css --> <!-- 全局css -->
<link rel="shortcut icon" href="${ctxPath}/static/favicon.ico"> <link rel="shortcut icon" href="${ctxPath}/static/favicon.ico">
<link href="${ctxPath}/static/css/bootstrap.min.css?v=3.3.6" rel="stylesheet"> <link href="${ctxPath}/static/css/bootstrap.min.css?v=3.3.6" rel="stylesheet">
<link href="${ctxPath}/static/css/font-awesome.css?v=4.4.0" rel="stylesheet"> <link href="${ctxPath}/static/css/font-awesome.css?v=4.4.0" rel="stylesheet">
<link href="${ctxPath}/static/css/plugins/bootstrap-table/bootstrap-table.min.css" rel="stylesheet"> <link href="${ctxPath}/static/css/plugins/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
<link href="${ctxPath}/static/css/animate.css" rel="stylesheet"> <link href="${ctxPath}/static/css/animate.css" rel="stylesheet">
<link href="${ctxPath}/static/css/style.css?v=4.1.0" rel="stylesheet"> <link href="${ctxPath}/static/css/style.css?v=4.1.0" rel="stylesheet">
<link href="${ctxPath}/static/css/_fstyle.css" rel="stylesheet"> <link href="${ctxPath}/static/css/_fstyle.css" rel="stylesheet">
<link href="${ctxPath}/static/css/plugins/iCheck/custom.css" rel="stylesheet"> <link href="${ctxPath}/static/css/plugins/iCheck/custom.css" rel="stylesheet">
<link href="${ctxPath}/static/css/plugins/webuploader/webuploader.css" rel="stylesheet"> <link href="${ctxPath}/static/css/plugins/webuploader/webuploader.css" rel="stylesheet">
<link href="${ctxPath}/static/css/plugins/ztree/zTreeStyle.css" rel="stylesheet"> <link href="${ctxPath}/static/css/plugins/ztree/zTreeStyle.css" rel="stylesheet">
<link href="${ctxPath}/static/css/plugins/jquery-treegrid/css/jquery.treegrid.css" rel="stylesheet" /> <link href="${ctxPath}/static/css/plugins/jquery-treegrid/css/jquery.treegrid.css" rel="stylesheet"/>
<!-- <link href="${ctxPath}/static/css/plugins/ztree/demo.css" rel="stylesheet"> --> <!-- <link href="${ctxPath}/static/css/plugins/ztree/demo.css" rel="stylesheet"> -->
<!-- 全局js --> <!-- 全局js -->
<script src="${ctxPath}/static/js/jquery.min.js?v=2.1.4"></script> <script src="${ctxPath}/static/js/jquery.min.js?v=2.1.4"></script>
<script src="${ctxPath}/static/js/bootstrap.min.js?v=3.3.6"></script> <script src="${ctxPath}/static/js/bootstrap.min.js?v=3.3.6"></script>
<script src="${ctxPath}/static/js/plugins/ztree/jquery.ztree.all.min.js"></script> <script src="${ctxPath}/static/js/plugins/ztree/jquery.ztree.all.min.js"></script>
<script src="${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table.min.js"></script> <script src="${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table.min.js"></script>
<script src="${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script> <script src="${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
<script src="${ctxPath}/static/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script> <script src="${ctxPath}/static/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.min.js"></script> <script src="${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.min.js"></script>
<script src="${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.bootstrap3.js"></script> <script src="${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.bootstrap3.js"></script>
<script src="${ctxPath}/static/js/plugins/jquery-treegrid/extension/jquery.treegrid.extension.js"></script> <script src="${ctxPath}/static/js/plugins/jquery-treegrid/extension/jquery.treegrid.extension.js"></script>
<script src="${ctxPath}/static/js/plugins/layer/layer.min.js"></script> <script src="${ctxPath}/static/js/plugins/layer/layer.min.js"></script>
<script src="${ctxPath}/static/js/plugins/iCheck/icheck.min.js"></script> <script src="${ctxPath}/static/js/plugins/iCheck/icheck.min.js"></script>
<script src="${ctxPath}/static/js/plugins/layer/laydate/laydate.js"></script> <script src="${ctxPath}/static/js/plugins/layer/laydate/laydate.js"></script>
<script src="${ctxPath}/static/js/plugins/webuploader/webuploader.min.js"></script> <script src="${ctxPath}/static/js/plugins/webuploader/webuploader.min.js"></script>
<script src="${ctxPath}/static/js/common/ajax-object.js"></script> <script src="${ctxPath}/static/js/common/ajax-object.js"></script>
<script src="${ctxPath}/static/js/common/bootstrap-table-object.js"></script> <script src="${ctxPath}/static/js/common/bootstrap-table-object.js"></script>
<script src="${ctxPath}/static/js/common/tree-table-object.js"></script> <script src="${ctxPath}/static/js/common/tree-table-object.js"></script>
<script src="${ctxPath}/static/js/common/web-upload-object.js"></script> <script src="${ctxPath}/static/js/common/web-upload-object.js"></script>
<script src="${ctxPath}/static/js/common/ztree-object.js"></script> <script src="${ctxPath}/static/js/common/ztree-object.js"></script>
<script src="${ctxPath}/static/js/common/Feng.js"></script> <script src="${ctxPath}/static/js/common/Feng.js"></script>
<script type="text/javascript"> <script type="text/javascript">
Feng.addCtx("${ctxPath}"); Feng.addCtx("${ctxPath}");
</script> Feng.sessionTimeoutRegistry();
</script>
</head> </head>
<body class="gray-bg"> <body class="gray-bg">
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
${layoutContent} ${layoutContent}
</div> </div>
<script src="${ctxPath}/static/js/content.js?v=1.0.0"></script> <script src="${ctxPath}/static/js/content.js?v=1.0.0"></script>
</body> </body>
</html> </html>
...@@ -112,5 +112,18 @@ var Feng = { ...@@ -112,5 +112,18 @@ var Feng = {
event = event ? event : window.event; event = event ? event : window.event;
var obj = event.srcElement ? event.srcElement : event.target; var obj = event.srcElement ? event.srcElement : event.target;
return $(obj); return $(obj);
},
sessionTimeoutRegistry: function () {
$.ajaxSetup({
contentType: "application/x-www-form-urlencoded;charset=utf-8",
complete: function (XMLHttpRequest, textStatus) {
//通过XMLHttpRequest取得响应头,sessionstatus,
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionstatus");
if (sessionstatus == "timeout") {
//如果超时就处理 ,指定要跳转的页面
window.location = Feng.ctxPath + "/global/sessionError";
}
}
});
} }
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment