一、配置文件

upms-server/springMVC-servlet.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:mvc="http://www.springframework.org/schema/mvc"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/mvc
  8. http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  9.  
  10. <!-- 根目录'/'对应页面 -->
  11. <mvc:view-controller path="/" view-name="/index.jsp"/>
  12.  
  13. <!-- 拦截器 -->
  14. <mvc:interceptors>
  15. <!-- 获取登录信息 -->
  16. <mvc:interceptor>
  17. <mvc:mapping path="/manage/**"/>
  18. <bean class="com.zheng.upms.server.interceptor.UpmsInterceptor"></bean>
  19. </mvc:interceptor>
  20. </mvc:interceptors>
  21.  
  22. <!-- Jsp视图 -->
  23. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  24. <property name="order" value=""/>
  25. <property name="prefix" value="/WEB-INF/jsp"/>
  26. <property name="suffix" value=""/>
  27. <property name="contentType" value="text/html; charset=utf-8"/>
  28. <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
  29. </bean>
  30.  
  31. </beans>

登陆信息拦截器:

  1. package com.zheng.upms.server.interceptor;
  2.  
  3. import com.zheng.common.util.PropertiesFileUtil;
  4. import com.zheng.upms.dao.model.UpmsUser;
  5. import com.zheng.upms.rpc.api.UpmsApiService;
  6. import com.zheng.upms.server.controller.manage.UpmsOrganizationController;
  7. import org.apache.shiro.SecurityUtils;
  8. import org.apache.shiro.subject.Subject;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.web.servlet.ModelAndView;
  13. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  14.  
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17.  
  18. /**
  19. * 登录信息拦截器
  20. * Created by shuzheng on 2017/2/11.
  21. */
  22. public class UpmsInterceptor extends HandlerInterceptorAdapter {
  23.  
  24. private static final Logger LOGGER = LoggerFactory.getLogger(UpmsInterceptor.class);
  25. private static final String ZHENG_OSS_ALIYUN_OSS_POLICY = PropertiesFileUtil.getInstance("zheng-oss-client").get("zheng.oss.aliyun.oss.policy");
  26.  
  27. @Autowired
  28. UpmsApiService upmsApiService;
  29.  
  30. @Override
  31. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  32. request.setAttribute("ZHENG_OSS_ALIYUN_OSS_POLICY", ZHENG_OSS_ALIYUN_OSS_POLICY);
  33. // 过滤ajax
  34. if (null != request.getHeader("X-Requested-With") && "XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"))) {
  35. return true;
  36. }
  37. // 登录信息
  38. Subject subject = SecurityUtils.getSubject();
  39. String username = (String) subject.getPrincipal();
  40. UpmsUser upmsUser = upmsApiService.selectUpmsUserByUsername(username);
  41. request.setAttribute("upmsUser", upmsUser);
  42. return true;
  43. }
  44.  
  45. @Override
  46. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  47. super.postHandle(request, response, handler, modelAndView);
  48. }
  49.  
  50. @Override
  51. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  52. super.afterCompletion(request, response, handler, ex);
  53. }
  54.  
  55. @Override
  56. public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  57. super.afterConcurrentHandlingStarted(request, response, handler);
  58. }
  59.  
  60. }

zheng-upms-server:resources/profiles:dev.properties

  1. app.name=zheng-upms-server
  2. profile.env=dev
  3.  
  4. ##### redis #####
  5. master.redis.ip=rdserver
  6. master.redis.port=
  7. master.redis.password=FNFl9F2O2Skb8yoKM0jhHA==
  8. master.redis.max_active=
  9. master.redis.max_idle=
  10. master.redis.max_wait=
  11. master.redis.timeout=
  12.  
  13. ##### zheng-admin #####
  14. zheng.admin.version=1.0.
  15.  
  16. ##### zheng-config #####
  17. #zheng.config.path=http://config.zhangshuzheng.cn:1000/${app.name}/${profile.env}
  18. zheng.config.path=http://127.0.0.1:1000/${app.name}/${profile.env}
  19. ##### zheng-upms #####
  20. # \u7EC8\u7AEF\u7C7B\u578B
  21. zheng.upms.type=server
  22. # \u7EC8\u7AEFsession\u540D\u79F0
  23. zheng.upms.session.id=zheng-upms-server-session-id
  24. # \u4F1A\u8BDD\u65F6\u957F,\u534A\u5C0F\u65F6\uFF08\u5355\u4F4D\u6BEB\u79D2\uFF09
  25. zheng.upms.session.timeout=
  26. # \u5355\u70B9\u767B\u5F55\u8BA4\u8BC1\u4E2D\u5FC3\u5730\u5740
  27. #zheng.upms.sso.server.url=http://upms.zhangshuzheng.cn:1111
  28. zheng.upms.sso.server.url=http://127.0.0.1:1111
  29. # \u767B\u5F55\u6210\u529F\u56DE\u8C03\u5730\u5740
  30. zheng.upms.successUrl=/manage/index
  31. # \u672A\u6388\u6743\u5730\u5740
  32. zheng.upms.unauthorizedUrl=/
  33. # \u8BB0\u4F4F\u5BC6\u7801\u65F6\u957F30\u5929
  34. zheng.upms.rememberMe.timeout=
  35.  
  36. ##### zheng-oss #####
  37. #zheng.oss.aliyun.oss.policy=http://oss.zhangshuzheng.cn:7771/aliyun/oss/policy
  38. zheng.oss.aliyun.oss.policy=http://127.0.0.1:7771/aliyun/oss/policy

zheng-upms-client:resources/applicationContext-shiro.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  7.  
  8. <description>zheng-upms</description>
  9.  
  10. <context:property-placeholder location="classpath*:zheng-upms-client.properties"/>
  11.  
  12. <!-- Shiro的Web过滤器 -->
  13. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  14. <property name="securityManager" ref="securityManager"/>
  15. <property name="loginUrl" value="${zheng.upms.sso.server.url}"/>
  16. <property name="successUrl" value="${zheng.upms.successUrl}"/>
  17. <property name="unauthorizedUrl" value="${zheng.upms.unauthorizedUrl}"/>
  18. <property name="filters">
  19. <util:map>
  20. <entry key="authc" value-ref="upmsAuthenticationFilter"/>
  21. </util:map>
  22. </property>
  23. <property name="filterChainDefinitions">
  24. <value>
  25. /manage/** = upmsSessionForceLogout,authc
  26. /manage/index = user
  27. /druid/** = user
  28. /swagger-ui.html = user
  29. /resources/** = anon
  30. /** = anon
  31. </value>
  32. </property>
  33. </bean>
  34.  
  35. <!-- 重写authc过滤器 -->
  36. <bean id="upmsAuthenticationFilter" class="com.zheng.upms.client.shiro.filter.UpmsAuthenticationFilter"/>
  37.  
  38. <!-- 强制退出会话过滤器 -->
  39. <bean id="upmsSessionForceLogout" class="com.zheng.upms.client.shiro.filter.UpmsSessionForceLogoutFilter"/>
  40.  
  41. <!-- 安全管理器 -->
  42. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  43. <property name="realms">
  44. <list><ref bean="upmsRealm"/></list>
  45. </property>
  46. <property name="sessionManager" ref="sessionManager"/>
  47. <property name="rememberMeManager" ref="rememberMeManager"/>
  48. </bean>
  49.  
  50. <!-- realm实现,继承自AuthorizingRealm -->
  51. <bean id="upmsRealm" class="com.zheng.upms.client.shiro.realm.UpmsRealm"></bean>
  52.  
  53. <!-- 会话管理器 -->
  54. <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
  55. <!-- 全局session超时时间 -->
  56. <property name="globalSessionTimeout" value="${zheng.upms.session.timeout}"/>
  57. <!-- sessionDAO -->
  58. <property name="sessionDAO" ref="sessionDAO"/>
  59. <property name="sessionIdCookieEnabled" value="true"/>
  60. <property name="sessionIdCookie" ref="sessionIdCookie"/>
  61. <property name="sessionValidationSchedulerEnabled" value="false"/>
  62. <property name="sessionListeners">
  63. <list><ref bean="sessionListener"/></list>
  64. </property>
  65. <property name="sessionFactory" ref="sessionFactory"/>
  66. </bean>
  67.  
  68. <!-- 会话DAO,可重写,持久化session -->
  69. <bean id="sessionDAO" class="com.zheng.upms.client.shiro.session.UpmsSessionDao"/>
  70.  
  71. <!-- 会话Cookie模板 -->
  72. <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
  73. <!-- 不会暴露给客户端 -->
  74. <property name="httpOnly" value="true"/>
  75. <!-- 设置Cookie的过期时间,秒为单位,默认-1表示关闭浏览器时过期Cookie -->
  76. <property name="maxAge" value="-1"/>
  77. <!-- Cookie名称 -->
  78. <property name="name" value="${zheng.upms.session.id}"/>
  79. </bean>
  80.  
  81. <!-- 会话监听器 -->
  82. <bean id="sessionListener" class="com.zheng.upms.client.shiro.listener.UpmsSessionListener"/>
  83.  
  84. <!-- session工厂 -->
  85. <bean id="sessionFactory" class="com.zheng.upms.client.shiro.session.UpmsSessionFactory"/>
  86.  
  87. <!-- rememberMe管理器 -->
  88. <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
  89. <!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)-->
  90. <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
  91. <property name="cookie" ref="rememberMeCookie"/>
  92. </bean>
  93.  
  94. <!-- rememberMe缓存cookie -->
  95. <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
  96. <constructor-arg value="rememberMe"/>
  97. <!-- 不会暴露给客户端 -->
  98. <property name="httpOnly" value="true"/>
  99. <!-- 记住我cookie生效时间 -->
  100. <property name="maxAge" value="${zheng.upms.rememberMe.timeout}"/>
  101. </bean>
  102.  
  103. <!-- 设置SecurityUtils,相当于调用SecurityUtils.setSecurityManager(securityManager) -->
  104. <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  105. <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
  106. <property name="arguments" ref="securityManager"/>
  107. </bean>
  108.  
  109. <!-- 开启Shiro Spring AOP权限注解@RequiresPermissions的支持 -->
  110. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
  111. <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
  112. <property name="securityManager" ref="securityManager"/>
  113. </bean>
  114.  
  115. <!-- Shiro生命周期处理器-->
  116. <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
  117.  
  118. </beans>

authc过滤器:

  1. package com.zheng.upms.client.shiro.filter;
  2.  
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.zheng.common.util.PropertiesFileUtil;
  5. import com.zheng.common.util.RedisUtil;
  6. import com.zheng.upms.client.shiro.session.UpmsSessionDao;
  7. import com.zheng.upms.client.util.RequestParameterUtil;
  8. import com.zheng.upms.common.constant.UpmsConstant;
  9. import org.apache.commons.lang.StringUtils;
  10. import org.apache.http.HttpEntity;
  11. import org.apache.http.HttpResponse;
  12. import org.apache.http.HttpStatus;
  13. import org.apache.http.NameValuePair;
  14. import org.apache.http.client.HttpClient;
  15. import org.apache.http.client.entity.UrlEncodedFormEntity;
  16. import org.apache.http.client.methods.HttpPost;
  17. import org.apache.http.impl.client.DefaultHttpClient;
  18. import org.apache.http.message.BasicNameValuePair;
  19. import org.apache.http.util.EntityUtils;
  20. import org.apache.shiro.authc.UsernamePasswordToken;
  21. import org.apache.shiro.session.Session;
  22. import org.apache.shiro.subject.Subject;
  23. import org.apache.shiro.web.filter.authc.AuthenticationFilter;
  24. import org.apache.shiro.web.util.WebUtils;
  25. import org.slf4j.Logger;
  26. import org.slf4j.LoggerFactory;
  27. import org.springframework.beans.factory.annotation.Autowired;
  28. import redis.clients.jedis.Jedis;
  29.  
  30. import javax.servlet.ServletRequest;
  31. import javax.servlet.ServletResponse;
  32. import javax.servlet.http.HttpServletRequest;
  33. import javax.servlet.http.HttpServletResponse;
  34. import java.io.IOException;
  35. import java.net.URLEncoder;
  36. import java.util.ArrayList;
  37. import java.util.List;
  38.  
  39. /**
  40. * 重写authc过滤器
  41. * Created by shuzheng on 2017/3/11.
  42. */
  43. public class UpmsAuthenticationFilter extends AuthenticationFilter {
  44.  
  45. private static final Logger LOGGER = LoggerFactory.getLogger(UpmsAuthenticationFilter.class);
  46.  
  47. // 局部会话key
  48. private final static String ZHENG_UPMS_CLIENT_SESSION_ID = "zheng-upms-client-session-id";
  49. // 单点同一个code所有局部会话key
  50. private final static String ZHENG_UPMS_CLIENT_SESSION_IDS = "zheng-upms-client-session-ids";
  51.  
  52. @Autowired
  53. UpmsSessionDao upmsSessionDao;
  54.  
  55. @Override
  56. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
  57. Subject subject = getSubject(request, response);
  58. Session session = subject.getSession();
  59. // 判断请求类型
  60. String upmsType = PropertiesFileUtil.getInstance("zheng-upms-client").get("zheng.upms.type");
  61. session.setAttribute(UpmsConstant.UPMS_TYPE, upmsType);
  62. if ("client".equals(upmsType)) {
  63. return validateClient(request, response);
  64. }
  65. if ("server".equals(upmsType)) {
  66. return subject.isAuthenticated();
  67. }
  68. return false;
  69. }
  70.  
  71. @Override
  72. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
  73. StringBuffer ssoServerUrl = new StringBuffer(PropertiesFileUtil.getInstance("zheng-upms-client").get("zheng.upms.sso.server.url"));
  74. // server需要登录
  75. String upmsType = PropertiesFileUtil.getInstance("zheng-upms-client").get("zheng.upms.type");
  76. if ("server".equals(upmsType)) {
  77. WebUtils.toHttp(response).sendRedirect(ssoServerUrl.append("/sso/login").toString());
  78. return false;
  79. }
  80. ssoServerUrl.append("/sso/index").append("?").append("appid").append("=").append(PropertiesFileUtil.getInstance("zheng-upms-client").get("zheng.upms.appID"));
  81. // 回跳地址
  82. HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
  83. StringBuffer backurl = httpServletRequest.getRequestURL();
  84. String queryString = httpServletRequest.getQueryString();
  85. if (StringUtils.isNotBlank(queryString)) {
  86. backurl.append("?").append(queryString);
  87. }
  88. ssoServerUrl.append("&").append("backurl").append("=").append(URLEncoder.encode(backurl.toString(), "utf-8"));
  89. WebUtils.toHttp(response).sendRedirect(ssoServerUrl.toString());
  90. return false;
  91. }
  92.  
  93. /**
  94. * 认证中心登录成功带回code
  95. * @param request
  96. */
  97. private boolean validateClient(ServletRequest request, ServletResponse response) {
  98. Subject subject = getSubject(request, response);
  99. Session session = subject.getSession();
  100. String sessionId = session.getId().toString();
  101. int timeOut = (int) session.getTimeout() / ;
  102. // 判断局部会话是否登录
  103. String cacheClientSession = RedisUtil.get(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + session.getId());
  104. if (StringUtils.isNotBlank(cacheClientSession)) {
  105. // 更新code有效期
  106. RedisUtil.set(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + sessionId, cacheClientSession, timeOut);
  107. Jedis jedis = RedisUtil.getJedis();
  108. jedis.expire(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + cacheClientSession, timeOut);
  109. jedis.close();
  110. // 移除url中的code参数
  111. if (null != request.getParameter("code")) {
  112. String backUrl = RequestParameterUtil.getParameterWithOutCode(WebUtils.toHttp(request));
  113. HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
  114. try {
  115. httpServletResponse.sendRedirect(backUrl.toString());
  116. } catch (IOException e) {
  117. LOGGER.error("局部会话已登录,移除code参数跳转出错:", e);
  118. }
  119. } else {
  120. return true;
  121. }
  122. }
  123. // 判断是否有认证中心code
  124. String code = request.getParameter("upms_code");
  125. // 已拿到code
  126. if (StringUtils.isNotBlank(code)) {
  127. // HttpPost去校验code
  128. try {
  129. StringBuffer ssoServerUrl = new StringBuffer(PropertiesFileUtil.getInstance("zheng-upms-client").get("zheng.upms.sso.server.url"));
  130. HttpClient httpclient = new DefaultHttpClient();
  131. HttpPost httpPost = new HttpPost(ssoServerUrl.toString() + "/sso/code");
  132.  
  133. List<NameValuePair> nameValuePairs = new ArrayList<>();
  134. nameValuePairs.add(new BasicNameValuePair("code", code));
  135. httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
  136.  
  137. HttpResponse httpResponse = httpclient.execute(httpPost);
  138. if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
  139. HttpEntity httpEntity = httpResponse.getEntity();
  140. JSONObject result = JSONObject.parseObject(EntityUtils.toString(httpEntity));
  141. if ( == result.getIntValue("code") && result.getString("data").equals(code)) {
  142. // code校验正确,创建局部会话
  143. RedisUtil.set(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + sessionId, code, timeOut);
  144. // 保存code对应的局部会话sessionId,方便退出操作
  145. RedisUtil.sadd(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code, sessionId, timeOut);
  146. LOGGER.debug("当前code={},对应的注册系统个数:{}个", code, RedisUtil.getJedis().scard(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code));
  147. // 移除url中的token参数
  148. String backUrl = RequestParameterUtil.getParameterWithOutCode(WebUtils.toHttp(request));
  149. // 返回请求资源
  150. try {
  151. // client无密认证
  152. String username = request.getParameter("upms_username");
  153. subject.login(new UsernamePasswordToken(username, ""));
  154. HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
  155. httpServletResponse.sendRedirect(backUrl.toString());
  156. return true;
  157. } catch (IOException e) {
  158. LOGGER.error("已拿到code,移除code参数跳转出错:", e);
  159. }
  160. } else {
  161. LOGGER.warn(result.getString("data"));
  162. }
  163. }
  164. } catch (IOException e) {
  165. LOGGER.error("验证token失败:", e);
  166. }
  167. }
  168. return false;
  169. }
  170.  
  171. }

强制退出会话过滤器:

  1. package com.zheng.upms.client.shiro.filter;
  2.  
  3. import org.apache.shiro.session.Session;
  4. import org.apache.shiro.web.filter.AccessControlFilter;
  5. import org.apache.shiro.web.util.WebUtils;
  6.  
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9.  
  10. /**
  11. * 强制退出会话过滤器
  12. * Created by shuzheng on 2017/3/1.
  13. */
  14. public class UpmsSessionForceLogoutFilter extends AccessControlFilter {
  15.  
  16. @Override
  17. protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
  18. Session session = getSubject(request, response).getSession(false);
  19. if(session == null) {
  20. return true;
  21. }
  22. boolean forceout = session.getAttribute("FORCE_LOGOUT") == null;
  23. return forceout;
  24. }
  25.  
  26. @Override
  27. protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
  28. getSubject(request, response).logout();
  29. String loginUrl = getLoginUrl() + (getLoginUrl().contains("?") ? "&" : "?") + "forceLogout=1";
  30. WebUtils.issueRedirect(request, response, loginUrl);
  31. return false;
  32. }
  33.  
  34. }

realm自定义实现:

  1. package com.zheng.upms.client.shiro.realm;
  2.  
  3. import com.zheng.common.util.MD5Util;
  4. import com.zheng.common.util.PropertiesFileUtil;
  5. import com.zheng.upms.dao.model.UpmsPermission;
  6. import com.zheng.upms.dao.model.UpmsRole;
  7. import com.zheng.upms.dao.model.UpmsUser;
  8. import com.zheng.upms.rpc.api.UpmsApiService;
  9. import org.apache.commons.lang.StringUtils;
  10. import org.apache.shiro.authc.*;
  11. import org.apache.shiro.authz.AuthorizationInfo;
  12. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  13. import org.apache.shiro.realm.AuthorizingRealm;
  14. import org.apache.shiro.subject.PrincipalCollection;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18.  
  19. import java.util.HashSet;
  20. import java.util.List;
  21. import java.util.Set;
  22.  
  23. /**
  24. * 用户认证和授权
  25. * Created by shuzheng on 2017/1/20.
  26. */
  27. public class UpmsRealm extends AuthorizingRealm {
  28.  
  29. private static final Logger LOGGER = LoggerFactory.getLogger(UpmsRealm.class);
  30.  
  31. @Autowired
  32. private UpmsApiService upmsApiService;
  33.  
  34. /**
  35. * 授权:验证权限时调用
  36. * @param principalCollection
  37. * @return
  38. */
  39. @Override
  40. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  41. String username = (String) principalCollection.getPrimaryPrincipal();
  42. UpmsUser upmsUser = upmsApiService.selectUpmsUserByUsername(username);
  43.  
  44. // 当前用户所有角色
  45. List<UpmsRole> upmsRoles = upmsApiService.selectUpmsRoleByUpmsUserId(upmsUser.getUserId());
  46. Set<String> roles = new HashSet<>();
  47. for (UpmsRole upmsRole : upmsRoles) {
  48. if (StringUtils.isNotBlank(upmsRole.getName())) {
  49. roles.add(upmsRole.getName());
  50. }
  51. }
  52.  
  53. // 当前用户所有权限
  54. List<UpmsPermission> upmsPermissions = upmsApiService.selectUpmsPermissionByUpmsUserId(upmsUser.getUserId());
  55. Set<String> permissions = new HashSet<>();
  56. for (UpmsPermission upmsPermission : upmsPermissions) {
  57. if (StringUtils.isNotBlank(upmsPermission.getPermissionValue())) {
  58. permissions.add(upmsPermission.getPermissionValue());
  59. }
  60. }
  61.  
  62. SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
  63. simpleAuthorizationInfo.setStringPermissions(permissions);
  64. simpleAuthorizationInfo.setRoles(roles);
  65. return simpleAuthorizationInfo;
  66. }
  67.  
  68. /**
  69. * 认证:登录时调用
  70. * @param authenticationToken
  71. * @return
  72. * @throws AuthenticationException
  73. */
  74. @Override
  75. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  76. String username = (String) authenticationToken.getPrincipal();
  77. String password = new String((char[]) authenticationToken.getCredentials());
  78. // client无密认证
  79. String upmsType = PropertiesFileUtil.getInstance("zheng-upms-client").get("zheng.upms.type");
  80. if ("client".equals(upmsType)) {
  81. return new SimpleAuthenticationInfo(username, password, getName());
  82. }
  83.  
  84. // 查询用户信息
  85. UpmsUser upmsUser = upmsApiService.selectUpmsUserByUsername(username);
  86.  
  87. if (null == upmsUser) {
  88. throw new UnknownAccountException();
  89. }
  90. if (!upmsUser.getPassword().equals(MD5Util.md5(password + upmsUser.getSalt()))) {
  91. throw new IncorrectCredentialsException();
  92. }
  93. if (upmsUser.getLocked() == ) {
  94. throw new LockedAccountException();
  95. }
  96.  
  97. return new SimpleAuthenticationInfo(username, password, getName());
  98. }
  99.  
  100. }

会话DAO:

  1. package com.zheng.upms.client.shiro.session;
  2.  
  3. import com.zheng.common.util.RedisUtil;
  4. import com.zheng.upms.client.util.SerializableUtil;
  5. import com.zheng.upms.common.constant.UpmsConstant;
  6. import org.apache.commons.lang.ObjectUtils;
  7. import org.apache.shiro.session.Session;
  8. import org.apache.shiro.session.mgt.ValidatingSession;
  9. import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import redis.clients.jedis.Jedis;
  13.  
  14. import java.io.Serializable;
  15. import java.util.*;
  16.  
  17. /**
  18. * 基于redis的sessionDao,缓存共享session
  19. * Created by shuzheng on 2017/2/23.
  20. */
  21. public class UpmsSessionDao extends CachingSessionDAO {
  22.  
  23. private static final Logger LOGGER = LoggerFactory.getLogger(UpmsSessionDao.class);
  24. // 会话key
  25. private final static String ZHENG_UPMS_SHIRO_SESSION_ID = "zheng-upms-shiro-session-id";
  26. // 全局会话key
  27. private final static String ZHENG_UPMS_SERVER_SESSION_ID = "zheng-upms-server-session-id";
  28. // 全局会话列表key
  29. private final static String ZHENG_UPMS_SERVER_SESSION_IDS = "zheng-upms-server-session-ids";
  30. // code key
  31. private final static String ZHENG_UPMS_SERVER_CODE = "zheng-upms-server-code";
  32. // 局部会话key
  33. private final static String ZHENG_UPMS_CLIENT_SESSION_ID = "zheng-upms-client-session-id";
  34. // 单点同一个code所有局部会话key
  35. private final static String ZHENG_UPMS_CLIENT_SESSION_IDS = "zheng-upms-client-session-ids";
  36.  
  37. @Override
  38. protected Serializable doCreate(Session session) {
  39. Serializable sessionId = generateSessionId(session);
  40. assignSessionId(session, sessionId);
  41. RedisUtil.set(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + sessionId, SerializableUtil.serialize(session), (int) session.getTimeout() / );
  42. LOGGER.debug("doCreate >>>>> sessionId={}", sessionId);
  43. return sessionId;
  44. }
  45.  
  46. @Override
  47. protected Session doReadSession(Serializable sessionId) {
  48. String session = RedisUtil.get(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + sessionId);
  49. LOGGER.debug("doReadSession >>>>> sessionId={}", sessionId);
  50. return SerializableUtil.deserialize(session);
  51. }
  52.  
  53. @Override
  54. protected void doUpdate(Session session) {
  55. // 如果会话过期/停止 没必要再更新了
  56. if(session instanceof ValidatingSession && !((ValidatingSession)session).isValid()) {
  57. return;
  58. }
  59. // 更新session的最后一次访问时间
  60. UpmsSession upmsSession = (UpmsSession) session;
  61. UpmsSession cacheUpmsSession = (UpmsSession) doReadSession(session.getId());
  62. if (null != cacheUpmsSession) {
  63. upmsSession.setStatus(cacheUpmsSession.getStatus());
  64. upmsSession.setAttribute("FORCE_LOGOUT", cacheUpmsSession.getAttribute("FORCE_LOGOUT"));
  65. }
  66. RedisUtil.set(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + session.getId(), SerializableUtil.serialize(session), (int) session.getTimeout() / );
  67. // 更新ZHENG_UPMS_SERVER_SESSION_ID、ZHENG_UPMS_SERVER_CODE过期时间 TODO
  68. LOGGER.debug("doUpdate >>>>> sessionId={}", session.getId());
  69. }
  70.  
  71. @Override
  72. protected void doDelete(Session session) {
  73. String sessionId = session.getId().toString();
  74. String upmsType = ObjectUtils.toString(session.getAttribute(UpmsConstant.UPMS_TYPE));
  75. if ("client".equals(upmsType)) {
  76. // 删除局部会话和同一code注册的局部会话
  77. String code = RedisUtil.get(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + sessionId);
  78. Jedis jedis = RedisUtil.getJedis();
  79. jedis.del(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + sessionId);
  80. jedis.srem(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code, sessionId);
  81. jedis.close();
  82. }
  83. if ("server".equals(upmsType)) {
  84. // 当前全局会话code
  85. String code = RedisUtil.get(ZHENG_UPMS_SERVER_SESSION_ID + "_" + sessionId);
  86. // 清除全局会话
  87. RedisUtil.remove(ZHENG_UPMS_SERVER_SESSION_ID + "_" + sessionId);
  88. // 清除code校验值
  89. RedisUtil.remove(ZHENG_UPMS_SERVER_CODE + "_" + code);
  90. // 清除所有局部会话
  91. Jedis jedis = RedisUtil.getJedis();
  92. Set<String> clientSessionIds = jedis.smembers(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code);
  93. for (String clientSessionId : clientSessionIds) {
  94. jedis.del(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + clientSessionId);
  95. jedis.srem(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code, clientSessionId);
  96. }
  97. LOGGER.debug("当前code={},对应的注册系统个数:{}个", code, jedis.scard(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + code));
  98. jedis.close();
  99. // 维护会话id列表,提供会话分页管理
  100. RedisUtil.lrem(ZHENG_UPMS_SERVER_SESSION_IDS, , sessionId);
  101. }
  102. // 删除session
  103. RedisUtil.remove(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + sessionId);
  104. LOGGER.debug("doUpdate >>>>> sessionId={}", sessionId);
  105. }
  106.  
  107. /**
  108. * 获取会话列表
  109. * @param offset
  110. * @param limit
  111. * @return
  112. */
  113. public Map getActiveSessions(int offset, int limit) {
  114. LOGGER.info("进入getActiveSession获取当前活动的session数据,服务端分页需要返回total 和rows");
  115. Map sessions = new HashMap();
  116. Jedis jedis = RedisUtil.getJedis();
  117. // 获取在线会话总数
  118. long total = jedis.llen(ZHENG_UPMS_SERVER_SESSION_IDS);
  119. // 获取当前页会话详情
  120. List<String> ids = jedis.lrange(ZHENG_UPMS_SERVER_SESSION_IDS, offset, (offset + limit - ));
  121. List<Session> rows = new ArrayList<>();
  122. for (String id : ids) {
  123. String session = RedisUtil.get(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + id);
  124. // 过滤redis过期session
  125. if (null == session) {
  126. RedisUtil.lrem(ZHENG_UPMS_SERVER_SESSION_IDS, , id);
  127. total = total - ;
  128. continue;
  129. }
  130. rows.add(SerializableUtil.deserialize(session));
  131. }
  132. jedis.close();
  133. sessions.put("total", total);
  134. sessions.put("rows", rows);
  135. return sessions;
  136. }
  137.  
  138. /**
  139. * 强制退出
  140. * @param ids
  141. * @return
  142. */
  143. public int forceout(String ids) {
  144. String[] sessionIds = ids.split(",");
  145. for (String sessionId : sessionIds) {
  146. // 会话增加强制退出属性标识,当此会话访问系统时,判断有该标识,则退出登录
  147. String session = RedisUtil.get(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + sessionId);
  148. UpmsSession upmsSession = (UpmsSession) SerializableUtil.deserialize(session);
  149. upmsSession.setStatus(UpmsSession.OnlineStatus.force_logout);
  150. upmsSession.setAttribute("FORCE_LOGOUT", "FORCE_LOGOUT");
  151. RedisUtil.set(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + sessionId, SerializableUtil.serialize(upmsSession), (int) upmsSession.getTimeout() / );
  152. }
  153. return sessionIds.length;
  154. }
  155.  
  156. /**
  157. * 更改在线状态
  158. *
  159. * @param sessionId
  160. * @param onlineStatus
  161. */
  162. public void updateStatus(Serializable sessionId, UpmsSession.OnlineStatus onlineStatus) {
  163. UpmsSession session = (UpmsSession) doReadSession(sessionId);
  164. if (null == session) {
  165. return;
  166. }
  167. session.setStatus(onlineStatus);
  168. RedisUtil.set(ZHENG_UPMS_SHIRO_SESSION_ID + "_" + session.getId(), SerializableUtil.serialize(session), (int) session.getTimeout() / );
  169. }
  170.  
  171. }

会话监听器:

  1. package com.zheng.upms.client.shiro.listener;
  2.  
  3. import org.apache.shiro.session.Session;
  4. import org.apache.shiro.session.SessionListener;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7.  
  8. /**
  9. * Created by shuzheng on 2017/2/12.
  10. */
  11. public class UpmsSessionListener implements SessionListener {
  12.  
  13. private static final Logger LOGGER = LoggerFactory.getLogger(UpmsSessionListener.class);
  14.  
  15. @Override
  16. public void onStart(Session session) {
  17. LOGGER.debug("会话创建:" + session.getId());
  18. }
  19.  
  20. @Override
  21. public void onStop(Session session) {
  22. LOGGER.debug("会话停止:" + session.getId());
  23. }
  24.  
  25. @Override
  26. public void onExpiration(Session session) {
  27. LOGGER.debug("会话过期:" + session.getId());
  28. }
  29.  
  30. }

会话工厂:

  1. package com.zheng.upms.client.shiro.session;
  2.  
  3. import org.apache.shiro.session.Session;
  4. import org.apache.shiro.session.mgt.SessionContext;
  5. import org.apache.shiro.session.mgt.SessionFactory;
  6. import org.apache.shiro.web.session.mgt.WebSessionContext;
  7.  
  8. import javax.servlet.http.HttpServletRequest;
  9.  
  10. /**
  11. * session工厂
  12. * Created by shuzheng on 2017/2/27.
  13. */
  14. public class UpmsSessionFactory implements SessionFactory {
  15.  
  16. @Override
  17. public Session createSession(SessionContext sessionContext) {
  18. UpmsSession session = new UpmsSession();
  19. if (null != sessionContext && sessionContext instanceof WebSessionContext) {
  20. WebSessionContext webSessionContext = (WebSessionContext) sessionContext;
  21. HttpServletRequest request = (HttpServletRequest) webSessionContext.getServletRequest();
  22. if (null != request) {
  23. session.setHost(request.getRemoteAddr());
  24. session.setUserAgent(request.getHeader("User-Agent"));
  25. }
  26. }
  27. return session;
  28. }
  29.  
  30. }

二、日志记录切面

springMVC-servlet.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

通过配置织入@Aspectj切面

  1. <aop:aspectj-autoproxy proxy-target-class="true"/>
  2.  
  3. <!-- 日志记录AOP实现 -->
  4. <bean class="com.zheng.upms.client.interceptor.LogAspect"/>
  5.  
  6. <!-- 日志记录AOP实现 -->
  7. <bean class="com.zheng.common.aspect.RpcLogAspect"/>
  8.  
  9. </beans>

LogAspect实现:

  1. package com.zheng.upms.client.interceptor;
  2.  
  3. import com.alibaba.fastjson.JSON;
  4. import com.zheng.common.util.RequestUtil;
  5. import com.zheng.upms.dao.model.UpmsLog;
  6. import com.zheng.upms.rpc.api.UpmsApiService;
  7. import io.swagger.annotations.ApiOperation;
  8. import org.apache.commons.lang.ObjectUtils;
  9. import org.apache.shiro.authz.annotation.RequiresPermissions;
  10. import org.aspectj.lang.JoinPoint;
  11. import org.aspectj.lang.ProceedingJoinPoint;
  12. import org.aspectj.lang.Signature;
  13. import org.aspectj.lang.annotation.After;
  14. import org.aspectj.lang.annotation.Around;
  15. import org.aspectj.lang.annotation.Aspect;
  16. import org.aspectj.lang.annotation.Before;
  17. import org.aspectj.lang.reflect.MethodSignature;
  18. import org.slf4j.Logger;
  19. import org.slf4j.LoggerFactory;
  20. import org.springframework.beans.factory.annotation.Autowired;
  21. import org.springframework.web.context.request.RequestAttributes;
  22. import org.springframework.web.context.request.RequestContextHolder;
  23. import org.springframework.web.context.request.ServletRequestAttributes;
  24.  
  25. import javax.servlet.http.HttpServletRequest;
  26. import java.lang.reflect.Method;
  27.  
  28. /**
  29. * 日志记录AOP实现
  30. * Created by ZhangShuzheng on 2017/3/14.
  31. */
  32. @Aspect
  33. public class LogAspect {
  34.  
  35. private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
  36.  
  37. // 开始时间
  38. private long startTime = 0L;
  39. // 结束时间
  40. private long endTime = 0L;
  41.  
  42. @Autowired
  43. UpmsApiService upmsApiService;
  44.  
  45. @Before("execution(* *..controller..*.*(..))")
  46. public void doBeforeInServiceLayer(JoinPoint joinPoint) {
  47. LOGGER.debug("doBeforeInServiceLayer");
  48. startTime = System.currentTimeMillis();
  49. }
  50.  
  51. @After("execution(* *..controller..*.*(..))")
  52. public void doAfterInServiceLayer(JoinPoint joinPoint) {
  53. LOGGER.debug("doAfterInServiceLayer");
  54. }
  55.  
  56. @Around("execution(* *..controller..*.*(..))")
  57. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  58. // 获取request
  59. RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
  60. ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
  61. HttpServletRequest request = servletRequestAttributes.getRequest();
  62.  
  63. UpmsLog upmsLog = new UpmsLog();
  64. // 从注解中获取操作名称、获取响应结果
  65. Object result = pjp.proceed();
  66. Signature signature = pjp.getSignature();
  67. MethodSignature methodSignature = (MethodSignature) signature;
  68. Method method = methodSignature.getMethod();
  69. if (method.isAnnotationPresent(ApiOperation.class)) {
  70. ApiOperation log = method.getAnnotation(ApiOperation.class);
  71. upmsLog.setDescription(log.value());
  72. }
  73. if (method.isAnnotationPresent(RequiresPermissions.class)) {
  74. RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
  75. String[] permissions = requiresPermissions.value();
  76. if (permissions.length > ) {
  77. upmsLog.setPermissions(permissions[]);
  78. }
  79. }
  80. endTime = System.currentTimeMillis();
  81. LOGGER.debug("doAround>>>result={},耗时:{}", result, endTime - startTime);
  82.  
  83. upmsLog.setBasePath(RequestUtil.getBasePath(request));
  84. upmsLog.setIp(RequestUtil.getIpAddr(request));
  85. upmsLog.setMethod(request.getMethod());
  86. if ("GET".equalsIgnoreCase(request.getMethod())) {
  87. upmsLog.setParameter(request.getQueryString());
  88. } else {
  89. upmsLog.setParameter(ObjectUtils.toString(request.getParameterMap()));
  90. }
  91. upmsLog.setResult(JSON.toJSONString(result));
  92. upmsLog.setSpendTime((int) (endTime - startTime));
  93. upmsLog.setStartTime(startTime);
  94. upmsLog.setUri(request.getRequestURI());
  95. upmsLog.setUrl(ObjectUtils.toString(request.getRequestURL()));
  96. upmsLog.setUserAgent(request.getHeader("User-Agent"));
  97. upmsLog.setUsername(ObjectUtils.toString(request.getUserPrincipal()));
  98. upmsApiService.insertUpmsLogSelective(upmsLog);
  99. return result;
  100. }
  101.  
  102. }

rpc消费日志记录:

  1. package com.zheng.common.aspect;
  2.  
  3. import com.alibaba.dubbo.rpc.RpcContext;
  4. import org.aspectj.lang.JoinPoint;
  5. import org.aspectj.lang.ProceedingJoinPoint;
  6. import org.aspectj.lang.annotation.After;
  7. import org.aspectj.lang.annotation.Around;
  8. import org.aspectj.lang.annotation.Before;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11.  
  12. /**
  13. * rpc提供者和消费者日志打印
  14. * Created by ZhangShuzheng on 2017/4/19.
  15. */
  16. public class RpcLogAspect {
  17.  
  18. private static final Logger LOGGER = LoggerFactory.getLogger(RpcLogAspect.class);
  19.  
  20. // 开始时间
  21. private long startTime = 0L;
  22. // 结束时间
  23. private long endTime = 0L;
  24.  
  25. @Before("execution(* *..rpc..*.*(..))")
  26. public void doBeforeInServiceLayer(JoinPoint joinPoint) {
  27. LOGGER.debug("doBeforeInServiceLayer");
  28. startTime = System.currentTimeMillis();
  29. }
  30.  
  31. @After("execution(* *..rpc..*.*(..))")
  32. public void doAfterInServiceLayer(JoinPoint joinPoint) {
  33. LOGGER.debug("doAfterInServiceLayer");
  34. }
  35.  
  36. @Around("execution(* *..rpc..*.*(..))")
  37. public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
  38. Object result = pjp.proceed();
  39. // 是否是消费端
  40. boolean consumerSide = RpcContext.getContext().isConsumerSide();
  41. // 获取最后一次提供方或调用方IP
  42. String ip = RpcContext.getContext().getRemoteHost();
  43. // 服务url
  44. String rpcUrl = RpcContext.getContext().getUrl().getParameter("application");
  45. LOGGER.info("consumerSide={}, ip={}, url={}", consumerSide, ip, rpcUrl);
  46. return result;
  47. }
  48.  
  49. }

  

二、session管理页面

  1. <%@ page contentType="text/html; charset=utf-8"%>
  2. <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
  4. <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
  5. <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
  6. <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
  7. <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
  8. <c:set var="basePath" value="${pageContext.request.contextPath}"/>
  9. <!DOCTYPE HTML>
  10. <html lang="zh-cn">
  11. <head>
  12. <meta charset="utf-8">
  13. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  14. <meta name="viewport" content="width=device-width, initial-scale=1">
  15. <title>会话管理</title>
  16. <jsp:include page="/resources/inc/head.jsp" flush="true"/>
  17. </head>
  18. <body>
  19. <div id="main">
  20. <div id="toolbar">
  21. <shiro:hasPermission name="upms:session:forceout"><a class="waves-effect waves-button" href="javascript:;" onclick="forceoutAction()"><i class="zmdi zmdi-run"></i> 强制退出</a></shiro:hasPermission>
  22. </div>
  23. <table id="table"></table>
  24. </div>
  25. <jsp:include page="/resources/inc/footer.jsp" flush="true"/>
  26. <script>
  27. var $table = $('#table');
  28. $(function() {
  29. // bootstrap table初始化
  30. $table.bootstrapTable({
  31. //向服务器请求的url。
  32. url: '${basePath}/manage/session/list',
  33. //表格的高度
  34. height: getHeight(),
  35. //默认false,当设为true,则每行表格的背景会显示灰白相间
  36. striped: true,
  37. //默认false不显示表格右上方搜索框 ,可设为true,在搜索框内只要输入内容即开始搜索
  38. search: false,
  39. //默认为false隐藏刷新按钮,设为true显示
  40. showRefresh: true,
  41. //默认为false隐藏某列下拉菜单,设为true显示
  42. showColumns: true,
  43. //每列的下拉菜单最小数
  44. minimumCountColumns: ,
  45. //默认false不响应,设为true则当点击此行的某处时,会自动选中此行的checkbox(复选框)或radiobox(单选按钮)
  46. clickToSelect: true,
  47. //默认false,设为true显示detail view(细节视图)
  48. detailView: true,
  49. //前提:detailView设为true,启用了显示detail view。
  50. // 用于格式化细节视图
  51. // 返回一个字符串,通过第三个参数element直接添加到细节视图的cell(某一格)中,其中,element为目标cell的jQuery element
  52. detailFormatter: 'detailFormatter',
  53. //默认为false,表格的底部工具栏不会显示分页条(pagination toolbar),可以设为true来显示
  54. pagination: true,
  55. //默认true,分页条无限循环
  56. paginationLoop: false,
  57. //设置在哪进行分页,默认”client”,可选”server”,如果设置 “server”,则必须设置url或者重写ajax方法
  58. sidePagination: 'server',
  59. //设置为 false 将在点击分页按钮时,自动记住排序项。仅在 sidePagination设置为 server时生效。
  60. silentSort: false,
  61. //设置为 true 是程序自动判断显示分页信息和 card 视图。
  62. smartDisplay: false,
  63. //转义HTML字符串,替换 &, <, >, ", \`, 和 ' 字符。
  64. escape: true,
  65. //设置为 true时,按回车触发搜索方法,否则自动触发搜索方法。
  66. searchOnEnterKey: true,
  67. //指定主键列。
  68. idField: 'id',
  69. //设置为 true 在点击分页按钮或搜索按钮时,将记住checkbox的选择项。\
  70. maintainSelected: true,
  71. //一个jQuery 选择器,指明自定义的 toolbar。例如:#toolbar, .toolbar.
  72. toolbar: '#toolbar',
  73. //列配置项,详情请查看 列参数 表格.
  74. columns: [
  75. {field: 'ck', checkbox: true},
  76. {field: 'id', title: '编号', sortable: true, align: 'center'},
  77. {field: 'startTimestamp', title: '创建时间', sortable: true, align: 'center'},
  78. {field: 'lastAccessTime', title: '最后访问时间'},
  79. {field: 'expired', title: '是否过期', align: 'center'},
  80. {field: 'host', title: '访问者IP', align: 'center'},
  81. {field: 'userAgent', title: '用户标识', align: 'center'},
  82. {field: 'status', title: '状态', align: 'center', formatter: 'statusFormatter'}
  83. ]
  84. });
  85. });
  86. // 格式化状态
  87. function statusFormatter(value, row, index) {
  88. if (value == 'on_line') {
  89. return '<span class="label label-success">在线</span>';
  90. }
  91. if (value == 'off_line') {
  92. return '<span class="label label-default">离线</span>';
  93. }
  94. if (value == 'force_logout') {
  95. return '<span class="label label-danger">踢离</span>';
  96. }
  97. }
  98. // 强制退出
  99. var forceoutDialog;
  100. function forceoutAction() {
  101. //getSelections方法返回所选的行,当没有选择任何行的时候返回一个空数组。
  102. var rows = $table.bootstrapTable('getSelections');
  103. if (rows.length == ) {
  104. $.confirm({
  105. title: false,
  106. content: '请至少选择一条记录!',
  107. autoClose: 'cancel|3000',
  108. backgroundDismiss: true,
  109. buttons: {
  110. cancel: {
  111. text: '取消',
  112. btnClass: 'waves-effect waves-button'
  113. }
  114. }
  115. });
  116. } else {
  117. forceoutDialog = $.confirm({
  118. type: 'red',
  119. animationSpeed: ,
  120. title: false,
  121. content: '确认强制退出该会话吗?',
  122. buttons: {
  123. confirm: {
  124. text: '确认',
  125. btnClass: 'waves-effect waves-button',
  126. action: function () {
  127. var ids = new Array();
  128. for (var i in rows) {
  129. ids.push(rows[i].id);
  130. }
  131. $.ajax({
  132. type: 'get',
  133. url: '${basePath}/manage/session/forceout/' + ids.join(","),
  134. success: function(result) {
  135. if (result.code != ) {
  136. if (result.data instanceof Array) {
  137. $.each(result.data, function(index, value) {
  138. $.confirm({
  139. theme: 'dark',
  140. animation: 'rotateX',
  141. closeAnimation: 'rotateX',
  142. title: false,
  143. content: value.errorMsg,
  144. buttons: {
  145. confirm: {
  146. text: '确认',
  147. btnClass: 'waves-effect waves-button waves-light'
  148. }
  149. }
  150. });
  151. });
  152. } else {
  153. $.confirm({
  154. theme: 'dark',
  155. animation: 'rotateX',
  156. closeAnimation: 'rotateX',
  157. title: false,
  158. content: result.data.errorMsg,
  159. buttons: {
  160. confirm: {
  161. text: '确认',
  162. btnClass: 'waves-effect waves-button waves-light'
  163. }
  164. }
  165. });
  166. }
  167. } else {
  168. forceoutDialog.close();
  169. $table.bootstrapTable('refresh');
  170. }
  171. },
  172. error: function(XMLHttpRequest, textStatus, errorThrown) {
  173. $.confirm({
  174. theme: 'dark',
  175. animation: 'rotateX',
  176. closeAnimation: 'rotateX',
  177. title: false,
  178. content: textStatus,
  179. buttons: {
  180. confirm: {
  181. text: '确认',
  182. btnClass: 'waves-effect waves-button waves-light'
  183. }
  184. }
  185. });
  186. }
  187. });
  188. }
  189. },
  190. cancel: {
  191. text: '取消',
  192. btnClass: 'waves-effect waves-button'
  193. }
  194. }
  195. });
  196. }
  197. }
  198. </script>
  199. </body>
  200. </html>

common.js

  1. $(function() {
  2. // Waves初始化
  3. Waves.displayEffect();
  4. // 数据表格动态高度
  5. $(window).resize(function () {
  6. $('#table').bootstrapTable('resetView', {
  7. height: getHeight()
  8. });
  9. });
  10. // 设置input特效
  11. $(document).on('focus', 'input[type="text"]', function() {
  12. $(this).parent().find('label').addClass('active');
  13. }).on('blur', 'input[type="text"]', function() {
  14. if ($(this).val() == '') {
  15. $(this).parent().find('label').removeClass('active');
  16. }
  17. });
  18. // select2初始化
  19. $('select').select2();
  20. });
  21. // 动态高度
  22. function getHeight() {
  23. return $(window).height() - ;
  24. }
  25. // 数据表格展开内容
  26. function detailFormatter(index, row) {
  27. var html = [];
  28. $.each(row, function (key, value) {
  29. html.push('<p><b>' + key + ':</b> ' + value + '</p>');
  30. });
  31. return html.join('');
  32. }
  33. // 初始化input特效
  34. function initMaterialInput() {
  35. $('form input[type="text"]').each(function () {
  36. if ($(this).val() != '') {
  37. $(this).parent().find('label').addClass('active');
  38. }
  39. });
  40. }

【zheng阅读系列】shiro权限管理的更多相关文章

  1. (39.4) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    在读此文章之前您还可能需要先了解: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...

  2. (39.3) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    在学习此小节之前您可能还需要学习: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...

  3. (39.2). Spring Boot Shiro权限管理【从零开始学Spring Boot】

    (本节提供源代码,在最下面可以下载) (4). 集成Shiro 进行用户授权 在看此小节前,您可能需要先看: http://412887952-qq-com.iteye.com/blog/229973 ...

  4. (39.1) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    (本节提供源代码,在最下面可以下载)距上一个章节过了二个星期了,最近时间也是比较紧,一直没有时间可以写博客,今天难得有点时间,就说说Spring Boot如何集成Shiro吧.这个章节会比较复杂,牵涉 ...

  5. Spring Boot Shiro 权限管理

    Spring Boot Shiro 权限管理 标签: springshiro 2016-01-14 23:44 94587人阅读 评论(60) 收藏 举报 .embody{ padding:10px ...

  6. Spring Boot Shiro 权限管理 【转】

    http://blog.csdn.net/catoop/article/details/50520958 主要用于备忘 本来是打算接着写关于数据库方面,集成MyBatis的,刚好赶上朋友问到Shiro ...

  7. shiro权限管理的框架-入门

    shiro权限管理的框架 1.权限管理的概念 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能 ...

  8. (补漏)Springboot2.0 集成shiro权限管理

    原文Springboot2.0 集成shiro权限管理 一.关于停止使用外键. 原本集成shiro建立用户.角色.权限表的时候使用了外键,系统自动创建其中两个关联表,用@JoinTable.看起来省事 ...

  9. SpringMVC+Shiro权限管理(转载)

    源码 http://pan.baidu.com/s/1pJzG4t1 SpringMVC+Shiro权限管理 博文目录 权限的简单描述 实例表结构及内容及POJO Shiro-pom.xml Shir ...

随机推荐

  1. Android四大组件应用系列——实现电话拦截和电话录音

    一.问题描述 使用BordercastReceiver和Service组件实现下述功能: 1.当手机处于来电状态,启动监听服务,对来电进行监听录音. 2.设置电话黑名单,当来电是黑名单电话,则直接挂断 ...

  2. [Mockito] Spring Unit Testing with Mockito

    It is recommened to write unit testing with Mockito in Spring framework, because it is much faster w ...

  3. Redis深入之对象

    Redis对象系统 前面介绍了Redis用到的全部主要数据结构,如简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合等 Redis并没有直接使用这些数据结构来实现键值对数据库.而是基于这些数 ...

  4. akka actors默认邮箱介绍

    1. UnboundedMailbox is the default unbounded MailboxType used by Akka Actors ”无界邮箱“ 是akka actors默认使用 ...

  5. volitile关键字

    1.volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修 ...

  6. Authentication 方案优化探索(JWT, Session, Refresh Token, etc.)

    转载自:http://www.jianshu.com/p/5ac8a0e1e5a8

  7. netstat使用--10个常用的命令

    1.列出所有的端口   netstat -a  列出TCP协议的端口  netstat -at   UDP协议的端口  netstat -au 2.列出处于监听状态的socket  netstat - ...

  8. AaronYang WCF教程目录

    ============================原创,讲究实践===================== 1. 那天有个小孩教我WCF[一][1/3]     基本搭建      阅读    ...

  9. 译:3.消费一个RESTful Web Service

    这节课我们根据官网教程学习如何去消费(调用)一个 RESTful Web Service . 原文链接 https://spring.io/guides/gs/consuming-rest/ 本指南将 ...

  10. ThreadPoolExecutor 线程池浅析

    作为Executor框架中最核心的类,ThreadPoolExecutor代表着鼎鼎大名的线程池,它给了我们足够的理由来弄清楚它. 下面我们就通过源码来一步一步弄清楚它. 内部状态 线程有五种状态:新 ...