后台服务
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

320 lines
12 KiB

  1. package com.iformall.config;
  2. import com.iformall.service.MallPermissionService;
  3. import com.iformall.shiro.MyRetryLimitCredentialsMatcher;
  4. import com.iformall.shiro.MyShiroRealm;
  5. import org.apache.shiro.mgt.SecurityManager;
  6. import org.apache.shiro.spring.LifecycleBeanPostProcessor;
  7. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  8. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  9. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  10. import org.apache.shiro.web.servlet.SimpleCookie;
  11. import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
  12. import org.crazycake.shiro.RedisCacheManager;
  13. import org.crazycake.shiro.RedisManager;
  14. import org.crazycake.shiro.RedisSessionDAO;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.beans.factory.annotation.Qualifier;
  17. import org.springframework.beans.factory.annotation.Value;
  18. import org.springframework.context.annotation.Bean;
  19. import org.springframework.context.annotation.Configuration;
  20. import javax.servlet.Filter;
  21. import javax.servlet.ServletRequest;
  22. import javax.servlet.http.HttpServletRequest;
  23. import java.util.LinkedHashMap;
  24. import java.util.Map;
  25. /**
  26. * Created by yangqj on 2017/4/23.
  27. */
  28. @Configuration
  29. public class ShiroConfig {
  30. @Value("${spring.redis.host}")
  31. private String host;
  32. @Value("${spring.redis.port}")
  33. private int port;
  34. @Value("${spring.redis.timeout}")
  35. private int timeout;
  36. @Value("${spring.redis.expire}")
  37. private int expire;
  38. @Value("${spring.redis.password}")
  39. private String password;
  40. @Bean
  41. public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
  42. return new LifecycleBeanPostProcessor();
  43. }
  44. /**
  45. * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
  46. * @return
  47. */
  48. // @Bean
  49. // public ShiroDialect shiroDialect() {
  50. // return new ShiroDialect();
  51. // }
  52. /**
  53. * ShiroFilterFactoryBean 处理拦截资源文件问题。
  54. * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在
  55. * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
  56. * <p>
  57. * Filter Chain定义说明
  58. * 1、一个URL可以配置多个Filter,使用逗号分隔
  59. * 2、当设置多个过滤器时,全部验证通过,才视为通过
  60. * 3、部分过滤器可指定参数,如perms,roles
  61. */
  62. @Bean
  63. public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
  64. System.out.println("ShiroConfiguration.shirFilter()");
  65. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  66. // 必须设置 SecurityManager
  67. shiroFilterFactoryBean.setSecurityManager(securityManager);
  68. Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
  69. filters.put("token", new ShiroLoginFilter());
  70. filters.put("corsFilter", new RestFilter());
  71. //filters.put("authc", new MyFormAuthenticationFilter());
  72. shiroFilterFactoryBean.setFilters(filters);
  73. // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
  74. shiroFilterFactoryBean.setLoginUrl("/#/");
  75. // 登录成功后要跳转的链接
  76. shiroFilterFactoryBean.setSuccessUrl("/usersPage");
  77. //未授权界面;
  78. shiroFilterFactoryBean.setUnauthorizedUrl("/403");
  79. //拦截器.
  80. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
  81. //filterChainDefinitionMap.put("/ue/**", "anon");
  82. //filterChainDefinitionMap.put("/config.json", "anon");
  83. // login
  84. filterChainDefinitionMap.put("/doLogin/**", "anon");
  85. filterChainDefinitionMap.put("/bHidLogin/**", "anon");
  86. filterChainDefinitionMap.put("/sendLoginPhoneCode/**", "anon");
  87. filterChainDefinitionMap.put("/doLoginByPhone/**", "anon");
  88. filterChainDefinitionMap.put("/wechat/login", "anon"); // 微信第三方登录callback
  89. filterChainDefinitionMap.put("/wechat/callback", "anon"); // 微信网页登录回调
  90. filterChainDefinitionMap.put("/wechat/weChatUserLogin", "anon"); // 微信第三方登录
  91. // 验证码
  92. filterChainDefinitionMap.put("/captcha.jpg", "anon");
  93. // 官网
  94. filterChainDefinitionMap.put("/wxMallApply/add", "anon");
  95. // callback
  96. filterChainDefinitionMap.put("/wxPay/notify/**", "anon"); // 支付回调
  97. filterChainDefinitionMap.put("/wxPayBill/notify/**", "anon");
  98. filterChainDefinitionMap.put("/wxMsgCallback/**", "anon");
  99. filterChainDefinitionMap.put("/user/sendvalidationcode", "anon");
  100. filterChainDefinitionMap.put("/user/updatepwd", "anon");
  101. filterChainDefinitionMap.put("/carCallback/**", "anon");
  102. filterChainDefinitionMap.put("/wxMallApply/sendvalidationcode", "anon");
  103. // 补发消息
  104. filterChainDefinitionMap.put("/wxCoupon/updateStokeAndValidDate", "anon");
  105. // static files
  106. filterChainDefinitionMap.put("/css/**", "anon");
  107. filterChainDefinitionMap.put("/js/**", "anon");
  108. filterChainDefinitionMap.put("/img/**", "anon");
  109. filterChainDefinitionMap.put("/font-awesome/**", "anon");
  110. //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
  111. //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
  112. //自定义加载权限资源关系
  113. // Map<String,Object> map = new HashMap<>();
  114. // List<SysPermission> resourcesList = resourcesService.list(map);
  115. // for(SysPermission resources:resourcesList){
  116. //
  117. // if (StringUtil.isNotEmpty(resources.getUrl())) {
  118. // String permission = "perms[" + resources.getUrl()+ "]";
  119. // filterChainDefinitionMap.put(resources.getUrl(),permission);
  120. // }
  121. // }
  122. // swagger-ui
  123. filterChainDefinitionMap.put("/swagger-ui.html", "anon");
  124. filterChainDefinitionMap.put("/doc.html", "anon");
  125. filterChainDefinitionMap.put("/v2/**", "anon");
  126. filterChainDefinitionMap.put("/swagger-resources/**", "anon");
  127. filterChainDefinitionMap.put("/webjars/**", "anon");
  128. filterChainDefinitionMap.put("/version", "anon");
  129. //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
  130. filterChainDefinitionMap.put("/logout", "authc");
  131. filterChainDefinitionMap.put("/**", "corsFilter,token,authc");
  132. // filterChainDefinitionMap.put("/**", "anon");
  133. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  134. return shiroFilterFactoryBean;
  135. }
  136. public static boolean isAjax(ServletRequest request) {
  137. String header = ((HttpServletRequest) request).getHeader("X-Requested-With");
  138. if ("XMLHttpRequest".equalsIgnoreCase(header)) {
  139. System.out.println("当前请求为Ajax请求");
  140. return Boolean.TRUE;
  141. }
  142. System.out.println("当前请求非Ajax请求");
  143. return Boolean.FALSE;
  144. }
  145. @Bean
  146. public SecurityManager securityManager() {
  147. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  148. //设置realm.
  149. securityManager.setRealm(myShiroRealm());
  150. // 自定义缓存实现 使用redis
  151. //securityManager.setCacheManager(cacheManager());
  152. // 自定义session管理 使用redis
  153. securityManager.setSessionManager(sessionManager());
  154. return securityManager;
  155. }
  156. @Bean
  157. public MyShiroRealm myShiroRealm() {
  158. MyShiroRealm myShiroRealm = new MyShiroRealm();
  159. myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
  160. return myShiroRealm;
  161. }
  162. /**
  163. * 密码匹配凭证管理器 凭证匹配器
  164. * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
  165. * 所以我们需要修改下doGetAuthenticationInfo中的代码;
  166. * )
  167. *
  168. * @return
  169. */
  170. public MyRetryLimitCredentialsMatcher hashedCredentialsMatcher() {
  171. MyRetryLimitCredentialsMatcher hashedCredentialsMatcher = new MyRetryLimitCredentialsMatcher();
  172. hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
  173. hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
  174. return hashedCredentialsMatcher;
  175. }
  176. /**
  177. * 开启shiro aop注解支持.
  178. * 使用代理方式;所以需要开启代码支持;
  179. *
  180. * @param securityManager
  181. * @return
  182. */
  183. @Bean
  184. public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
  185. AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  186. authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  187. return authorizationAttributeSourceAdvisor;
  188. }
  189. /**
  190. * 配置shiro redisManager
  191. * 使用的是shiro-redis开源插件
  192. *
  193. * @return
  194. */
  195. public RedisManager redisManager() {
  196. RedisManager redisManager = new RedisManager();
  197. redisManager.setHost(host);
  198. redisManager.setPort(port);
  199. //redisManager.setExpire(expire);// 配置缓存过期时间
  200. redisManager.setTimeout(timeout);
  201. redisManager.setPassword(password);
  202. return redisManager;
  203. }
  204. /**
  205. * cacheManager 缓存 redis实现
  206. * 使用的是shiro-redis开源插件
  207. *
  208. * @return
  209. */
  210. public RedisCacheManager cacheManager() {
  211. RedisCacheManager redisCacheManager = new RedisCacheManager();
  212. redisCacheManager.setRedisManager(redisManager());
  213. return redisCacheManager;
  214. }
  215. /**
  216. * RedisSessionDAO shiro sessionDao层的实现 通过redis
  217. * 使用的是shiro-redis开源插件
  218. */
  219. @Bean
  220. public RedisSessionDAO redisSessionDAO() {
  221. RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
  222. redisSessionDAO.setRedisManager(redisManager());
  223. return redisSessionDAO;
  224. }
  225. /**
  226. * shiro session的管理
  227. */
  228. @Bean
  229. public DefaultWebSessionManager sessionManager() {
  230. DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
  231. //设置session过期时间为1小时(单位:毫秒),默认为30分钟
  232. sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
  233. sessionManager.setSessionValidationSchedulerEnabled(true);
  234. sessionManager.setSessionIdUrlRewritingEnabled(false);
  235. sessionManager.setSessionDAO(redisSessionDAO());
  236. sessionManager.setSessionIdCookie(simpleCookie());
  237. return sessionManager;
  238. }
  239. @Bean
  240. public SimpleCookie simpleCookie() {
  241. SimpleCookie simpleCookie = new SimpleCookie("SSIDS");
  242. simpleCookie.setDomain("");
  243. return simpleCookie;
  244. }
  245. // @Bean
  246. // public SimpleCookie rememberMeCookie(){
  247. // //System.out.println("ShiroConfiguration.rememberMeCookie()");
  248. // //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
  249. // SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
  250. // //<!-- 记住我cookie生效时间30天 ,单位秒;-->
  251. // simpleCookie.setMaxAge(60*30);
  252. // return simpleCookie;
  253. // }
  254. // @Bean
  255. // public CookieRememberMeManager rememberMeManager(){
  256. // //System.out.println("ShiroConfiguration.rememberMeManager()");
  257. // CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
  258. // cookieRememberMeManager.setCookie(rememberMeCookie());
  259. // //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
  260. // cookieRememberMeManager.setCipherKey(Base64.decodeBytes("2AvVhdsgUs0FSA3SDFAdag=="));
  261. // return cookieRememberMeManager;
  262. // }
  263. // @Bean(name = "securityManager")
  264. // public DefaultWebSecurityManager defaultWebSecurityManager(MyShiroRealm realm){
  265. // DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  266. // //设置realm
  267. // securityManager.setRealm(realm);
  268. // //用户授权/认证信息Cache, 采用EhCache缓存
  269. // securityManager.setCacheManager(cacheManager());
  270. // //注入记住我管理器
  271. // securityManager.setRememberMeManager(rememberMeManager());
  272. // return securityManager;
  273. // }
  274. }