diff --git a/src/main/java/com/ruoyi/common/constant/CommonConstant.java b/src/main/java/com/ruoyi/common/constant/CommonConstant.java index 8ba75be59..f14a983d8 100644 --- a/src/main/java/com/ruoyi/common/constant/CommonConstant.java +++ b/src/main/java/com/ruoyi/common/constant/CommonConstant.java @@ -23,6 +23,11 @@ public class CommonConstant */ public static final String LOGIN_SUCCESS = "Success"; + /** + * 注销 + */ + public static final String Logout = "Logout"; + /** * 登录失败 */ diff --git a/src/main/java/com/ruoyi/common/utils/HttpContextUtils.java b/src/main/java/com/ruoyi/common/utils/HttpContextUtils.java deleted file mode 100644 index 648f65ee4..000000000 --- a/src/main/java/com/ruoyi/common/utils/HttpContextUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.ruoyi.common.utils; - -import javax.servlet.http.HttpServletRequest; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -/** - * 客户端工具类 - * - * @author ruoyi - */ -public class HttpContextUtils -{ - public static HttpServletRequest getHttpServletRequest() - { - return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); - } -} diff --git a/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/src/main/java/com/ruoyi/common/utils/ServletUtils.java new file mode 100644 index 000000000..45e246d51 --- /dev/null +++ b/src/main/java/com/ruoyi/common/utils/ServletUtils.java @@ -0,0 +1,54 @@ +package com.ruoyi.common.utils; + +import javax.servlet.http.HttpServletRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * 客户端工具类 + * + * @author ruoyi + */ +public class ServletUtils +{ + /** + * 获取request对象 + */ + public static HttpServletRequest getHttpServletRequest() + { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + /** + * 是否是Ajax异步请求 + */ + public static boolean isAjaxRequest(HttpServletRequest request) + { + + String accept = request.getHeader("accept"); + if (accept != null && accept.indexOf("application/json") != -1) + { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) + { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) + { + return true; + } + + String ajax = request.getParameter("__ajax"); + if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) + { + return true; + } + + return false; + } +} diff --git a/src/main/java/com/ruoyi/common/utils/StringUtils.java b/src/main/java/com/ruoyi/common/utils/StringUtils.java index 3ce78aa28..f8186b89e 100644 --- a/src/main/java/com/ruoyi/common/utils/StringUtils.java +++ b/src/main/java/com/ruoyi/common/utils/StringUtils.java @@ -153,4 +153,25 @@ public class StringUtils return (str == null ? "" : str.trim()); } + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { + return true; + } + } + } + return false; + } } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/common/utils/SystemLogUtils.java b/src/main/java/com/ruoyi/common/utils/SystemLogUtils.java index 9887eab51..22ce7ce9a 100644 --- a/src/main/java/com/ruoyi/common/utils/SystemLogUtils.java +++ b/src/main/java/com/ruoyi/common/utils/SystemLogUtils.java @@ -41,7 +41,7 @@ public class SystemLogUtils sys_user_logger.info(s.toString(), args); - if (CommonConstant.LOGIN_SUCCESS.equals(status)) + if (CommonConstant.LOGIN_SUCCESS.equals(status) || CommonConstant.Logout.equals(status)) { saveOpLog(username, msg, CommonConstant.SUCCESS); } @@ -53,7 +53,7 @@ public class SystemLogUtils public static void saveOpLog(String username, String message, String status) { - UserAgent userAgent = UserAgent.parseUserAgentString(HttpContextUtils.getHttpServletRequest().getHeader("User-Agent")); + UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getHttpServletRequest().getHeader("User-Agent")); // 获取客户端操作系统 String os = userAgent.getOperatingSystem().getName(); // 获取客户端浏览器 diff --git a/src/main/java/com/ruoyi/common/utils/security/ShiroUtils.java b/src/main/java/com/ruoyi/common/utils/security/ShiroUtils.java index 32c900742..726f0e859 100644 --- a/src/main/java/com/ruoyi/common/utils/security/ShiroUtils.java +++ b/src/main/java/com/ruoyi/common/utils/security/ShiroUtils.java @@ -33,6 +33,11 @@ public class ShiroUtils return getUser().getUserId().longValue(); } + public static String getLoginName() + { + return getUser().getLoginName(); + } + public static String getIp() { return getSubjct().getSession().getHost(); diff --git a/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java index 311895e3d..f57361252 100644 --- a/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java +++ b/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java @@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.constant.UserConstants; -import com.ruoyi.common.utils.HttpContextUtils; +import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.security.ShiroUtils; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.project.monitor.operlog.domain.OperLog; @@ -85,7 +85,7 @@ public class LogAspect // 请求的地址 String ip = ShiroUtils.getIp(); operLog.setOperIp(ip); - operLog.setOperUrl(HttpContextUtils.getHttpServletRequest().getRequestURI()); + operLog.setOperUrl(ServletUtils.getHttpServletRequest().getRequestURI()); if (currentUser != null) { operLog.setLoginName(currentUser.getLoginName()); @@ -146,7 +146,7 @@ public class LogAspect */ private static void setRequestValue(OperLog operLog) { - Map map = HttpContextUtils.getHttpServletRequest().getParameterMap(); + Map map = ServletUtils.getHttpServletRequest().getParameterMap(); String params = JSONObject.toJSONString(map); operLog.setOperParam(params); } diff --git a/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/src/main/java/com/ruoyi/framework/config/ShiroConfig.java index f3d81b33c..7ba40eec6 100644 --- a/src/main/java/com/ruoyi/framework/config/ShiroConfig.java +++ b/src/main/java/com/ruoyi/framework/config/ShiroConfig.java @@ -7,7 +7,6 @@ import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; -import org.apache.shiro.web.filter.authc.LogoutFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; @@ -15,10 +14,10 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - import com.ruoyi.framework.shiro.realm.UserRealm; import com.ruoyi.framework.shiro.session.OnlineSessionDAO; import com.ruoyi.framework.shiro.session.OnlineSessionFactory; +import com.ruoyi.framework.shiro.web.filter.LogoutFilter; import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter; import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter; import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager; @@ -173,6 +172,16 @@ public class ShiroConfig return securityManager; } + /** + * 退出过滤器 + */ + public LogoutFilter logoutFilter() + { + LogoutFilter logoutFilter = new LogoutFilter(); + logoutFilter.setLoginUrl(loginUrl); + return logoutFilter; + } + /** * Shiro过滤器配置 */ @@ -186,9 +195,6 @@ public class ShiroConfig shiroFilterFactoryBean.setLoginUrl(loginUrl); // 权限认证失败,则跳转到指定页面 shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); - // 注销成功,则跳转到指定页面 - LogoutFilter logoutFilter = new LogoutFilter(); - logoutFilter.setRedirectUrl(loginUrl); // Shiro连接约束配置,即过滤链的定义 LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); // 对静态资源设置匿名访问 @@ -212,6 +218,8 @@ public class ShiroConfig Map filters = new LinkedHashMap<>(); filters.put("onlineSession", onlineSessionFilter()); filters.put("syncOnlineSession", syncOnlineSessionFilter()); + // 注销成功,则跳转到指定页面 + filters.put("logout", logoutFilter()); shiroFilterFactoryBean.setFilters(filters); // 所有请求需要认证 diff --git a/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java b/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java index f9391b84f..135a164c5 100644 --- a/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java +++ b/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java @@ -6,7 +6,7 @@ import org.apache.shiro.session.mgt.SessionContext; import org.apache.shiro.session.mgt.SessionFactory; import org.apache.shiro.web.session.mgt.WebSessionContext; import org.springframework.stereotype.Component; -import com.ruoyi.common.utils.HttpContextUtils; +import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.IpUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.project.monitor.online.domain.OnlineSession; @@ -43,7 +43,7 @@ public class OnlineSessionFactory implements SessionFactory if (request != null) { UserAgent userAgent = UserAgent - .parseUserAgentString(HttpContextUtils.getHttpServletRequest().getHeader("User-Agent")); + .parseUserAgentString(ServletUtils.getHttpServletRequest().getHeader("User-Agent")); // 获取客户端操作系统 String os = userAgent.getOperatingSystem().getName(); // 获取客户端浏览器 diff --git a/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java b/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java new file mode 100644 index 000000000..ab5f21996 --- /dev/null +++ b/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java @@ -0,0 +1,81 @@ +package com.ruoyi.framework.shiro.web.filter; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.session.SessionException; +import org.apache.shiro.subject.Subject; +import com.ruoyi.common.constant.CommonConstant; +import com.ruoyi.common.utils.MessageUtils; +import com.ruoyi.common.utils.SystemLogUtils; +import com.ruoyi.common.utils.security.ShiroUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 退出过滤器 + * + * @author ruoyi + */ +@Slf4j +public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter +{ + + /** + * 退出后重定向的地址 + */ + private String loginUrl; + + public String getLoginUrl() + { + return loginUrl; + } + + public void setLoginUrl(String loginUrl) + { + this.loginUrl = loginUrl; + } + + @Override + protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception + { + try + { + Subject subject = getSubject(request, response); + String redirectUrl = getRedirectUrl(request, response, subject); + try + { + String loginName = ShiroUtils.getLoginName(); + // 记录用户退出日志 + SystemLogUtils.log(loginName, CommonConstant.Logout, MessageUtils.message("user.logout.success")); + // 退出登录 + subject.logout(); + } + catch (SessionException ise) + { + log.error("logout fail.", ise); + } + issueRedirect(request, response, redirectUrl); + } + catch (Exception e) + { + log.debug("Encountered session exception during logout. This can generally safely be ignored.", e); + } + return false; + } + + /** + * 退出跳转URL + */ + @Override + protected String getRedirectUrl(ServletRequest request, ServletResponse response, Subject subject) + { + String url = getLoginUrl(); + if (StringUtils.isNoneBlank(url)) + { + return url; + } + return super.getRedirectUrl(request, response, subject); + } + +} diff --git a/src/main/java/com/ruoyi/framework/web/support/TableSupport.java b/src/main/java/com/ruoyi/framework/web/support/TableSupport.java index b10344006..9dff84ff7 100644 --- a/src/main/java/com/ruoyi/framework/web/support/TableSupport.java +++ b/src/main/java/com/ruoyi/framework/web/support/TableSupport.java @@ -2,7 +2,7 @@ package com.ruoyi.framework.web.support; import javax.servlet.http.HttpServletRequest; -import com.ruoyi.common.utils.HttpContextUtils; +import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.MapDataUtil; import com.ruoyi.framework.web.page.PageUtilEntity; @@ -18,7 +18,7 @@ public class TableSupport */ public static PageUtilEntity getPageUtilEntity() { - HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); + HttpServletRequest request = ServletUtils.getHttpServletRequest(); PageUtilEntity pageUtilEntity = new PageUtilEntity(); pageUtilEntity.setPage(Integer.valueOf(request.getParameter("offset"))); pageUtilEntity.setSize(Integer.valueOf(request.getParameter("limit"))); diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties index 6a754399c..78144fa06 100644 --- a/src/main/resources/i18n/messages.properties +++ b/src/main/resources/i18n/messages.properties @@ -6,6 +6,7 @@ user.password.retry.limit.count=密码输入错误{0}次,{1} user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 user.blocked=用户已封禁,原因:{0} role.blocked=角色已封禁,原因:{0} +user.logout.success=退出成功 length.not.valid=长度必须在{min}到{max}个字符之间 @@ -16,7 +17,6 @@ user.jcaptcha.error=验证码错误 user.email.not.valid=邮箱格式错误 user.mobile.phone.number.not.valid=手机号格式错误 -user.logout.success=退出成功 user.login.success=登录成功 user.notfound=请重新登录 user.forcelogout=管理员强制退出,请重新登录 diff --git a/src/main/resources/static/ruoyi/monitor/logininfor/logininfor.js b/src/main/resources/static/ruoyi/monitor/logininfor/logininfor.js index 271449daf..083e7548c 100644 --- a/src/main/resources/static/ruoyi/monitor/logininfor/logininfor.js +++ b/src/main/resources/static/ruoyi/monitor/logininfor/logininfor.js @@ -26,7 +26,7 @@ $(function() { }, { field: 'status', - title: '登录状态', + title: '状态', align: 'center', formatter: function(value, row, index) { if (value == 0) { @@ -36,6 +36,10 @@ $(function() { } } }, + { + field: 'msg', + title: '操作信息' + }, { field: 'loginTime', title: '登录时间'