SpringBoot + Redis + Shiro 实现权限管理
文章主要是针对shiro进行权限配置,只针对角色进行了权限过滤。
GitHub:https://github.com/stevencxb/blog
数据库脚本
-- ---------------------------- -- Table structure for sys_menu -- ---------------------------- DROP TABLE IF EXISTS `sys_menu`; CREATE TABLE `sys_menu` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `pid` bigint(20) NULL DEFAULT 0 COMMENT '父id', `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称', `type` int(11) NULL DEFAULT NULL COMMENT '类型(1:模块;2:菜单)', `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路径', `sort` int(11) NULL DEFAULT NULL COMMENT '排序', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统菜单' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色id', `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称', `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for sys_role_menu -- ---------------------------- DROP TABLE IF EXISTS `sys_role_menu`; CREATE TABLE `sys_role_menu` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `role_id` bigint(20) NOT NULL, `menu_id` bigint(20) NOT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `role_id`(`role_id`, `menu_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 171 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色-菜单' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户id', `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名', `user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名', `nick_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称', `birthday` date NULL DEFAULT NULL COMMENT '出生日期', `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', `pwd` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码', `sex` tinyint(2) NULL DEFAULT NULL COMMENT '性别(1:男;2:女)', `intro` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '个人简介', `head_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像地址', `status` tinyint(2) NOT NULL DEFAULT 1 COMMENT '状态(1:正常:2:冻结)', `last_login_time` datetime(0) NULL DEFAULT NULL COMMENT '最后登录时间', `create_time` datetime(0) NOT NULL COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `username`(`user_name`) USING BTREE, UNIQUE INDEX `phone`(`phone`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', `user_id` bigint(20) NOT NULL COMMENT '用户id', `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色id', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户-角色' ROW_FORMAT = Dynamic;
maven配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>2.4.2.1-RELEASE</version> </dependency> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
ShiroConfig
package com.cxb.blog.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import com.cxb.blog.service.ISysMenuService; import com.cxb.blog.utils.ShiroUtil; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisManager; import org.crazycake.shiro.RedisSessionDAO; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; /** * @Title: ShiroConfig * @Description: ShiroConfig * @Author <a href="mailto:chenxb1993@126.com">陈晓博</a> * @Date 2019-05-14 14:01 * @Version V1.0 */ @Slf4j @Configuration public class ShiroConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.port}") private String port; @Value("${spring.redis.timeout}") private String timeout; @Value("${spring.redis.database}") private String database; @Autowired private ISysMenuService sysMenuService; @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射 shiroFilterFactoryBean.setLoginUrl("/login"); // 设置无权限时跳转的 url; shiroFilterFactoryBean.setUnauthorizedUrl("/403"); Map<String, Filter> filtersMap = new LinkedHashMap<>(); filtersMap.put("roleOrFilter",new RolesOrFilterAuthorizationFilter());//可以配置RoleOrFilter的Bean filtersMap.put("kickout",kickoutSessionControlFilter()); shiroFilterFactoryBean.setFilters(filtersMap); // 设置拦截器 Map<String, String> filterChainDefinitionMap = ShiroUtil.getFilterChainDefinitionMap(sysMenuService); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); log.info("Shiro拦截器工厂类注入成功"); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(shiroRealm()); // 自定义缓存实现 使用redis securityManager.setCacheManager(cacheManager()); // 自定义session管理 使用redis securityManager.setSessionManager(sessionManager()); return securityManager; } /** * 身份认证realm; (这个需要自己写,账号密码校验;权限等) * * @return */ @Bean public RealmConfig shiroRealm() { RealmConfig realmConfig = new RealmConfig(); return realmConfig; } /** * cacheManager 缓存 redis实现 * 使用的是shiro-redis开源插件 * * @return */ public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * 配置shiro redisManager * 使用的是shiro-redis开源插件 * * @return */ public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host); redisManager.setPort(Integer.parseInt(port)); redisManager.setExpire(1800);// 配置缓存过期时间 redisManager.setTimeout(Integer.parseInt(timeout)); redisManager.setPassword(password); return redisManager; } /** * Session Manager * 使用的是shiro-redis开源插件 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; } /** * RedisSessionDAO shiro sessionDao层的实现 通过redis * 使用的是shiro-redis开源插件 */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } /** * 限制同一账号登录同时登录人数控制 * * @return */ @Bean public KickoutSessionControlFilter kickoutSessionControlFilter() { KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter(); kickoutSessionControlFilter.setCacheManager(cacheManager()); kickoutSessionControlFilter.setSessionManager(sessionManager()); kickoutSessionControlFilter.setKickoutAfter(false); kickoutSessionControlFilter.setMaxSession(1); kickoutSessionControlFilter.setKickoutUrl("/kickout"); return kickoutSessionControlFilter; } /*** * 授权所用配置 * * @return */ @Bean public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } /*** * 使授权注解起作用不如不想配置可以在pom文件中加入 * <dependency> *<groupId>org.springframework.boot</groupId> *<artifactId>spring-boot-starter-aop</artifactId> *</dependency> * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * Shiro生命周期处理器 * */ @Bean public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean * * @return */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }
RealmConfig
package com.cxb.blog.config; import com.cxb.blog.dao.SysMenuDao; import com.cxb.blog.domain.DO.SysMenuDO; import com.cxb.blog.domain.DO.SysUserDO; import com.cxb.blog.enums.SysUserStatus; import com.cxb.blog.exception.SysUserStatusException; import com.cxb.blog.service.ISysUserRoleService; import com.cxb.blog.service.ISysUserService; import com.cxb.blog.utils.RegexUtil; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @Title: RealmConfig * @Description: shiro realm * @Author <a href="mailto:chenxb1993@126.com">陈晓博</a> * @Date 2019-05-14 14:01 * @Version V1.0 */ @Slf4j public class RealmConfig extends AuthorizingRealm { //如果项目中用到了事物,@Autowired注解会使事物失效,可以自己用get方法获取值 @Autowired private ISysUserService sysUserService; @Autowired private ISysUserRoleService sysUserRoleService; @Autowired private SysMenuDao sysMenuDao; /** * 认证信息.(身份验证) : Authentication 是用来验证用户身份 * */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authctoken) throws AuthenticationException { log.info("---------------- 执行 Shiro 凭证认证 ----------------------"); UsernamePasswordToken token = (UsernamePasswordToken) authctoken; String name = token.getUsername(); String password = String.valueOf(token.getPassword()); // 从数据库获取对应用户名密码的用户 SysUserDO userDO; if (RegexUtil.checkMobile(name)) { userDO = sysUserService.getByPhone(name); }else { userDO = sysUserService.getByUserName(name); } if (userDO == null) { throw new UnknownAccountException("账号或密码不正确"); } // 密码错误 if (!password.equals(userDO.getPwd())) { throw new IncorrectCredentialsException("账号或密码不正确"); } if (userDO.getStatus() != SysUserStatus.NORMAL.getStatus()){ throw new SysUserStatusException("用户状态异常"); } Subject subject = SecurityUtils.getSubject(); subject.getSession().setAttribute("userName", name); subject.getSession().setAttribute("id", userDO.getId()); log.info("---------------- Shiro 凭证认证成功 ----------------------"); SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( name, //用户 password, //密码 getName() //realm name ); return authenticationInfo; } /** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { log.info("---------------- 执行 Shiro 权限获取 ---------------------"); String principal = (String)principals.getPrimaryPrincipal(); SysUserDO sysUserDO = sysUserService.getByUserName(principal); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); Set<String> roles = sysUserRoleService.getRoleIdByUserId(sysUserDO.getId()); authorizationInfo.addRoles(roles); // // List<SysMenuDO> list = sysMenuDao.getSysMenuByUserId(sysUserDO.getId()); // Set<String> set=new HashSet<>(); // for (SysMenuDO sysMenuDO : list){ // set.add(sysMenuDO.getUrl()+"/**"); // } // authorizationInfo.addStringPermissions(set); log.info("---------------- Shiro 权限获取成功 ----------------------"); return authorizationInfo; } }
RolesOrFilterAuthorizationFilter
package com.cxb.blog.config; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.CollectionUtils; import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; import java.util.Set; /** * @Title: RolesOrFilterAuthorizationFilter * @Description: 角色过滤 * @Author <a href="mailto:chenxb1993@126.com">陈晓博</a> * @Date 2019-05-23 15:01 * @Version V1.0 */ public class RolesOrFilterAuthorizationFilter extends RolesAuthorizationFilter{ public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { Subject subject = this.getSubject(request, response); String[] rolesArray = (String[])((String[])mappedValue); if (rolesArray != null && rolesArray.length != 0) { Set<String> roles = CollectionUtils.asSet(rolesArray); for (String role : roles){ if (subject.hasRole(role)){ return true; } } return false; } else { return true; } } }
5.KickoutSessionControlFilter
package com.cxb.blog.config; import com.alibaba.fastjson.JSON; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.session.Session; import org.apache.shiro.session.mgt.DefaultSessionKey; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.AccessControlFilter; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; import java.util.Deque; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; /** * @Title: KickoutSessionControlFilter * @Description: 被踢出控制 * @Author <a href="mailto:chenxb1993@126.com">陈晓博</a> * @Date 2019-05-14 14:03 * @Version V1.0 */ public class KickoutSessionControlFilter extends AccessControlFilter { private String kickoutUrl; //踢出后到的地址 private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户 private int maxSession = 1; //同一个帐号最大会话数 默认1 private SessionManager sessionManager; private Cache<String, Deque<Serializable>> cache; public void setKickoutUrl(String kickoutUrl) { this.kickoutUrl = kickoutUrl; } public void setKickoutAfter(boolean kickoutAfter) { this.kickoutAfter = kickoutAfter; } public void setMaxSession(int maxSession) { this.maxSession = maxSession; } public void setSessionManager(SessionManager sessionManager) { this.sessionManager = sessionManager; } //设置Cache的key的前缀 public void setCacheManager(CacheManager cacheManager) { this.cache = cacheManager.getCache("shiro_redis_cache"); } @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { return false; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { Subject subject = getSubject(request, response); if(!subject.isAuthenticated() && !subject.isRemembered()) { //如果没有登录,直接进行之后的流程 return true; } Session session = subject.getSession(); String userName = (String) subject.getPrincipal(); Serializable sessionId = session.getId(); //读取缓存 没有就存入 Deque<Serializable> deque = cache.get(userName); //如果此用户没有session队列,也就是还没有登录过,缓存中没有 //就new一个空队列,不然deque对象为空,会报空指针 if(deque==null){ deque = new LinkedList<Serializable>(); } //如果队列里没有此sessionId,且用户没有被踢出;放入队列 if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) { //将sessionId存入队列 deque.push(sessionId); //将用户的sessionId队列缓存 cache.put(userName, deque); } //如果队列里的sessionId数超出最大会话数,开始踢人 while(deque.size() > maxSession) { Serializable kickoutSessionId = null; if(kickoutAfter) { //如果踢出后者 kickoutSessionId = deque.removeFirst(); //踢出后再更新下缓存队列 cache.put(userName, deque); } else { //否则踢出前者 kickoutSessionId = deque.removeLast(); //踢出后再更新下缓存队列 cache.put(userName, deque); } try { //获取被踢出的sessionId的session对象 Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId)); if(kickoutSession != null) { //设置会话的kickout属性表示踢出了 kickoutSession.setAttribute("kickout", true); } } catch (Exception e) {//ignore exception } } //如果被踢出了,直接退出,重定向到踢出后的地址 if (session.getAttribute("kickout") != null) { //会话被踢出了 try { //退出登录 subject.logout(); } catch (Exception e) { //ignore } saveRequest(request); Map<String, String> resultMap = new HashMap<String, String>(); //判断是不是Ajax请求 if ("XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request).getHeader("X-Requested-With"))) { resultMap.put("user_status", "300"); resultMap.put("message", "您已经在其他地方登录,请重新登录!"); //输出json串 out(response, resultMap); }else{ //重定向 WebUtils.issueRedirect(request, response, kickoutUrl); } return false; } return true; } private void out(ServletResponse hresponse, Map<String, String> resultMap) throws IOException { try { hresponse.setCharacterEncoding("UTF-8"); PrintWriter out = hresponse.getWriter(); out.println(JSON.toJSONString(resultMap)); out.flush(); out.close(); } catch (Exception e) { System.err.println("KickoutSessionFilter.class 输出JSON异常,可以忽略。"); } } }
ShiroFilerChainManager
package com.cxb.blog.config; import com.cxb.blog.service.ISysMenuService; import com.cxb.blog.utils.ShiroUtil; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; import org.apache.shiro.web.servlet.AbstractShiroFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; /** * @Title: ShiroFilerChainManager * @Description: ShiroFilerChainManager * @Author <a href="mailto:chenxb1993@126.com">陈晓博</a> * @Date 2019-05-23 15:30 * @Version V1.0 */ @Slf4j @Component("shiroFilerChainManager") @Transactional(readOnly=true) public class ShiroFilerChainManager { @Autowired private ShiroFilterFactoryBean shiroFilterFactoryBean; @Autowired private ISysMenuService sysMenuService; /** * 重载过滤链 */ public void reloadFilterChains() { AbstractShiroFilter shiroFilter = null; try { shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject(); } catch (Exception e) { log.error("getShiroFilter from shiroFilterFactoryBean error!", e); throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!"); } PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver(); DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager(); // 清空老的权限控制 manager.getFilterChains().clear(); shiroFilterFactoryBean.getFilterChainDefinitionMap().clear(); shiroFilterFactoryBean.setFilterChainDefinitionMap(ShiroUtil.getFilterChainDefinitionMap(sysMenuService)); System.out.println("Shiro拦截器工厂类注入成功"); } }
ShiroUtil
package com.cxb.blog.utils; import com.cxb.blog.domain.VO.SysMenuFilterVO; import com.cxb.blog.service.ISysMenuService; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * @Title: ShiroUtil * @Description: shiro工具类 * @Author <a href="mailto:chenxb1993@126.com">陈晓博</a> * @Date 2019-05-23 15:37 * @Version V1.0 */ public class ShiroUtil { public static Map<String, String> getFilterChainDefinitionMap(ISysMenuService sysMenuService){ Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); List<SysMenuFilterVO> list = sysMenuService.selectAll(); // //游客,开发权限 // filterChainDefinitionMap.put("/guest/**", "anon"); // //用户,需要角色权限 “user” // filterChainDefinitionMap.put("/user/**", "roles[user]"); // //管理员,需要角色权限 “admin” // filterChainDefinitionMap.put("/admin/**", "roles[admin]"); // //开放登陆接口 // filterChainDefinitionMap.put("/login", "anon"); // //其余接口一律拦截 //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 for(SysMenuFilterVO filter : list){ filterChainDefinitionMap.put(filter.getUrl()+"/**","roleOrFilter["+(filter.getRoles()==null?"":filter.getRoles())+"]"); } filterChainDefinitionMap.put("/**", "kickout,anon"); return filterChainDefinitionMap; } }