使用Springboot+shiro+layui打造漂亮简洁的权限控制系统

Springboot集成shiro

pom.xml


<dependency>
    <groupId>org.apache.shirogroupId>
    <artifactId>shiro-springartifactId>
    <version>1.6.0version>
dependency>

<dependency>
    <groupId>com.github.theborakompanionigroupId>
    <artifactId>thymeleaf-extras-shiroartifactId>
    <version>2.0.0version>
dependency>

新建shiro配置

/**
 * 权限配置文件
 * @ClassName: ShiroConfiguration
 * @author YoungJ
 * @date 2020年8月25日
 *
 */
@Configuration
public class ShiroConfig {
     

	/**
	 * 这是shiro的大管家,相当于mybatis里的SqlSessionFactoryBean
	 * @param securityManager
	 * @return
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
     
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		//登录
		shiroFilterFactoryBean.setLoginUrl("/user/login");
		//首页
		shiroFilterFactoryBean.setSuccessUrl("/");
		//错误页面,认证不通过跳转
		shiroFilterFactoryBean.setUnauthorizedUrl("/error/403");
		//页面权限控制
		shiroFilterFactoryBean.setFilterChainDefinitionMap(ShiroFilterMapFactory.shiroFilterMap());

		//自定义认证过滤器
		/*Map filterMap = Maps.newHashMap();
		//权限认证过滤器
		filterMap.put("authc", new PermissionFilter());

		shiroFilterFactoryBean.setFilters(filterMap);*/

		shiroFilterFactoryBean.setSecurityManager(securityManager);
		return shiroFilterFactoryBean;
	}
	
	/**
	 * web应用管理配置
	 * @param shiroRealm
	 * @param cacheManager
	 * @param manager
	 * @return
	 */
	@Bean
	public DefaultWebSecurityManager securityManager(Realm shiroRealm,CacheManager cacheManager,RememberMeManager manager) {
     
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setCacheManager(cacheManager);
		securityManager.setRememberMeManager(manager);//记住Cookie
		securityManager.setRealm(shiroRealm);
		securityManager.setSessionManager(sessionManager());
		return securityManager;
	}
	/**
	 * session过期控制
	 * @return
	 * @author fuce
	 * @Date 2019年11月2日 下午12:49:49
	 */
	@Bean
	public  DefaultWebSessionManager sessionManager() {
     
		DefaultWebSessionManager defaultWebSessionManager=new DefaultWebSessionManager();
		// 设置session过期时间3600s
		Long timeout=60L*1000*60;//毫秒级别
		defaultWebSessionManager.setGlobalSessionTimeout(timeout);
		return defaultWebSessionManager;
	}
	/**
	 * 加密算法
	 * @return
	 */
	@Bean
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
     
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		hashedCredentialsMatcher.setHashAlgorithmName("MD5");//采用MD5 进行加密
		hashedCredentialsMatcher.setHashIterations(1);//加密次数
		return hashedCredentialsMatcher;
	}
	
	/**
	 * 记住我的配置
	 * @return
	 */
	@Bean
	public RememberMeManager rememberMeManager() {
     
		Cookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);//通过js脚本将无法读取到cookie信息
        cookie.setMaxAge(60 * 60 * 24);//cookie保存一天
		CookieRememberMeManager manager=new CookieRememberMeManager();
		manager.setCookie(cookie);
		return manager;
	}
	/**
	 * 缓存配置
	 * @return
	 */
	@Bean
	public CacheManager cacheManager() {
     
		MemoryConstrainedCacheManager cacheManager=new MemoryConstrainedCacheManager();//使用内存缓存
		return cacheManager;
	}
	
	/**
	 * 配置realm,用于认证和授权
	 * @param hashedCredentialsMatcher
	 * @return
	 */
	@Bean
	public AuthorizingRealm shiroRealm(HashedCredentialsMatcher hashedCredentialsMatcher) {
     
		MyShiroRealm shiroRealm = new MyShiroRealm();
		//校验密码用到的算法
		shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher);
		return shiroRealm;
	}
	
	/**
	 * 启用shiro方言,这样能在页面上使用shiro标签
	 * @return
	 */
	@Bean
    public ShiroDialect shiroDialect() {
     
        return new ShiroDialect();
    }
	
	/**
     * 启用shiro注解
     *加入注解的使用,不加入这个注解不生效
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) {
     
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    

}

ShiroFilterMapFactory.java

package com.szcl.verify.shiro.config;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @ClassName: ShiroFilterMapFactory
 * @author YoungJ
 * @date 2020年8月26日
 *
 */
public class ShiroFilterMapFactory {
     
	public static Map<String, String> shiroFilterMap() {
     
		// 设置路径映射,注意这里要用LinkedHashMap 保证有序
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		//对所有用户认证
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/admin/login", "anon");
		filterChainDefinitionMap.put("/admin/logout", "logout");
		//放验证码
		filterChainDefinitionMap.put("/captcha/**", "anon");
		// 释放 druid 监控画面
		filterChainDefinitionMap.put("/druid/**", "anon");
		//释放websocket请求
		filterChainDefinitionMap.put("/websocket", "anon");
		//前端
		filterChainDefinitionMap.put("/", "anon");
		filterChainDefinitionMap.put("/index", "anon");
		
		filterChainDefinitionMap.put("/quartz/**", "anon");
		
		//开放APicontroller
		filterChainDefinitionMap.put("/ApiController/**", "anon");
		
		//对所有页面进行认证
		filterChainDefinitionMap.put("/**","authc");
		return filterChainDefinitionMap;
	}
}

MyShiroRealm.java

/**
 * 身份校验核心类
 *
 * @author YoungJ
 * @date 2020年8月25日
 */
@Service
public class MyShiroRealm extends AuthorizingRealm {
     

    @Autowired
    private UserMapper tsysUserDao;

    @Autowired
    private PermissionMapper permissionDao;

    @Autowired
    private RoleMapper roleDao;


    /**
     * 认证登陆
     */
    @SuppressWarnings("unused")
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
     

        if (token.getPrincipal() == null) {
     
            return null;
        }
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        // 通过username从数据库中查找 User对象
        // 实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        User userInfo = tsysUserDao.queryUserName(username);
        if (userInfo == null) {
     
            return null;
        } else {
     
            //错误次数控制
            checkLoginErrorTimes(username);
            //单一登录控制
            checkSingleSingOn(userInfo);
            return new SimpleAuthenticationInfo(
                    userInfo,
                    userInfo.getPassword(),
                    getName()
            );
        }

    }

    /**
     * 错误次数控制
     * @param userName
     */
    private void checkLoginErrorTimes(String userName) {
     

    }

    /**
     * 单一登录控制
     * @param user
     */
    private void checkSingleSingOn(User user) {
     
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
        //获取当前已登录的用户session列表
        SessionDAO sessionDAO = sessionManager.getSessionDAO();
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        for (Session session : sessions) {
     
            //清除该用户以前登录时保存的session

            Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            SimplePrincipalCollection coll = (SimplePrincipalCollection) obj;
            if(coll !=null){
     
                User userLogin =  (User)coll.getPrimaryPrincipal();
                if(user.getUsername().equals(userLogin.getUsername())){
     
                    sessionDAO.delete(session);
                }
            }
        }
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
     
        if (principals == null) {
     
            throw new AuthorizationException("principals should not be null");
        }
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User userinfo = (User) principals.getPrimaryPrincipal();
        Long id = userinfo.getId();
        List<Role> tsysRoles = roleDao.queryUserRole(id);
        for (Role userrole : tsysRoles) {
     
            Long rolid = userrole.getId();
            authorizationInfo.addRole(userrole.getName());
            List<Permission> permissions = permissionDao.queryRoleId(rolid);
            for (Permission p : permissions) {
     
                if (StringUtils.isNotEmpty(p.getPerms())) {
     
                    authorizationInfo.addStringPermission(p.getPerms());
                }

            }
        }
        return authorizationInfo;
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo() {
     
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}

ShiroUtils.java

/**
 * shiro 工具类
 *
 * @author YoungJ
 */
public class ShiroUtils {
     

    private ShiroUtils() {
     
    }

    /**
     * 获取shiro subject
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午10:00:55
     */
    public static Subject getSubjct() {
     
        return SecurityUtils.getSubject();
    }

    /**
     * 获取登录session
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午10:00:41
     */
    public static Session getSession() {
     
        return SecurityUtils.getSubject().getSession();
    }

    /**
     * 退出登录
     *
     * @author YoungJ
     * @Date 2019年11月21日 上午10:00:24
     */
    public static void logout() {
     
        getSubjct().logout();
    }

    /**
     * 获取登录用户model
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午10:00:10
     */
    public static User getUser() {
     
        User user = null;
        Object obj = getSubjct().getPrincipal();
        if (!StringUtils.isEmpty(obj)) {
     
            user = new User();
            BeanUtils.copyBeanProp(user, obj);
        }
        return user;
    }

    /**
     * set用户
     *
     * @param user
     * @author YoungJ
     * @Date 2019年11月21日 上午9:59:52
     */
    public static void setUser(User user) {
     
        Subject subject = getSubjct();
        PrincipalCollection principalCollection = subject.getPrincipals();
        String realmName = principalCollection.getRealmNames().iterator().next();
        PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(user, realmName);
        // 重新加载Principal
        subject.runAs(newPrincipalCollection);
    }

    /**
     * 清除授权信息
     *
     * @author YoungJ
     * @Date 2019年11月21日 上午9:59:37
     */
    public static void clearCachedAuthorizationInfo() {
     
        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        MyShiroRealm realm = (MyShiroRealm) rsm.getRealms().iterator().next();
        realm.clearCachedAuthorizationInfo();
    }

    /**
     * 获取登录用户id
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午9:58:55
     */
    public static Long getUserId() {
     
        User tsysUser = getUser();
        if (tsysUser == null || tsysUser.getId() == null) {
     
            throw new RuntimeException("用户不存在!");
        }
        return tsysUser.getId();
    }

    /**
     * 获取登录用户name
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午9:58:48
     */
    public static String getLoginName() {
     
        User tsysUser = getUser();
        if (tsysUser == null) {
     
            throw new RuntimeException("用户不存在!");
        }
        return tsysUser.getUsername();
    }

    /**
     * 获取登录用户ip
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午9:58:26
     */
    public static String getIp() {
     
        return getSubjct().getSession().getHost();
    }

    /**
     * 获取登录用户sessionid
     *
     * @return
     * @author YoungJ
     * @Date 2019年11月21日 上午9:58:37
     */
    public static String getSessionId() {
     
        return String.valueOf(getSubjct().getSession().getId());
    }

    /**
     * 缓存获取当前用户权限
     */
    public static Set<String> getPermissions() {
     
        Set<String> userPermissions =
                (Set<String>) SecurityUtils.getSubject().getSession().getAttribute(Constants.SHIRO_PERMISSIONKEY);
        return userPermissions;
    }

    /**
     * 设置权限缓存
     */
    public static void setPermissions(Set<String> userPermissions) {
     
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute(Constants.SHIRO_PERMISSIONKEY, userPermissions);
    }

    /**
     * 设置缓存
     */
    public static void setCacheParam(String key, Object value) {
     
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute(key, value);
    }

    /**
     * 获取缓存
     */
    public static Object getCacheParam(String key) {
     
        Session session = SecurityUtils.getSubject().getSession();
        return session.getAttribute(key);
    }
}

新建表

用户表

CREATE TABLE `t_sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户账号',
  `password` varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户密码',
  `nickname` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '昵称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='用户表';

角色表

CREATE TABLE `t_sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(20) DEFAULT NULL COMMENT '角色名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';

用户角色中间表

CREATE TABLE `t_sys_role_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `sys_user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `sys_role_id` bigint(20) DEFAULT NULL COMMENT '角色id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色中间表';

权限表

CREATE TABLE `t_sys_permission` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(20) DEFAULT NULL COMMENT '权限名称',
  `descripion` varchar(50) DEFAULT NULL COMMENT '权限描述',
  `url` varchar(255) DEFAULT NULL COMMENT '授权链接',
  `is_blank` int(1) DEFAULT '0' COMMENT '是否跳转 0 不跳转 1跳转',
  `pid` bigint(20) DEFAULT NULL COMMENT '父节点id',
  `perms` varchar(255) DEFAULT NULL COMMENT '权限标识',
  `type` int(1) DEFAULT NULL COMMENT '类型   0:目录   1:菜单   2:按钮',
  `icon` varchar(255) DEFAULT NULL COMMENT '菜单图标',
  `order_num` int(11) DEFAULT NULL COMMENT '排序',
  `visible` int(1) DEFAULT NULL COMMENT '是否可见',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='权限表';

角色权限中间表

CREATE TABLE `t_sys_permission_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(20) DEFAULT NULL COMMENT '角色id',
  `permission_id` bigint(20) DEFAULT NULL COMMENT '权限id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色权限中间表';

权限控制

LoginController.java

@Controller
public class LoginController {
     

    private static Logger log = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private IPermissionService permissionService;

    @GetMapping("/index")
    public String index(HttpServletRequest request) {
     
        Long userId = null;
        try {
     
            userId = ShiroUtils.getUserId();
        } catch (Exception e) {
     
            return "login";
        }
        if (userId == null) {
     
            return "login";
        }
        //获取菜单栏
        MenuTree tree= permissionService.getTreePerm(userId);
//        log.info(GsonConvertUtil.toJson(tree));
        request.getSession().setAttribute("tree", tree);
        request.getSession().setAttribute("sessionUserName", ShiroUtils.getUser().getNickname());
        return "home";
    }

    @GetMapping("/user/login")
    public String login(ModelMap model) {
     
        try {
     
            if ((null != SecurityUtils.getSubject() && SecurityUtils.getSubject().isAuthenticated()) || SecurityUtils.getSubject().isRemembered()) {
     
                return "redirect:index";
            } else {
     
                return "login";
            }
        } catch (Exception e) {
     
            log.error(e.getMessage(), e);
        }
        return "login";
    }



    @PostMapping(value = "/user/login")
    @ResponseBody
    public BaseDTO<String> login(@RequestParam("username") String username,
                                 @RequestParam("password") String password,
                                 @RequestParam(value = "isRemeberMe", required = false) Boolean isRemeberMe,
                                 Model model) {
     
        try {
     
            if ((null != SecurityUtils.getSubject() && SecurityUtils.getSubject().isAuthenticated()) || SecurityUtils.getSubject().isRemembered()) {
     
                return DtoConvertUtil.toDTO(null, "登录成功", Constants.CODE_SUCCESS, true);
            } else {
     
                System.out.println("--进行登录验证..验证开始");
                Subject currentUser = SecurityUtils.getSubject();
                UsernamePasswordToken token =new UsernamePasswordToken(username, password);
                if (isRemeberMe != null && isRemeberMe) {
     
                    token.setRememberMe(true);
                }
                currentUser.login(token);
                // 设置登录过期时间30分钟
                SecurityUtils.getSubject().getSession().setTimeout(30 * 60 * 1000);
//                model.addAttribute("RollVerification", V2Config.getRollVerification());
//                System.out.println("V2Config.getRollVerification()>>>"+V2Config.getRollVerification());
                return DtoConvertUtil.toDTO(null, "登录成功", Constants.CODE_SUCCESS, true);
            }
        }catch (UnknownAccountException e) {
     
            log.error("[登录异常] >> 账户不存在 account : {}", username);
            model.addAttribute("msg", "账号不存在");
            return DtoConvertUtil.toDTO(null, "账号不存在", Constants.CODE_PARAMA_ERR, false);
        } catch (IncorrectCredentialsException e) {
     
            log.error("[登录异常] >> 密码错误 account : {}", username);
            model.addAttribute("msg", "密码错误");
            return DtoConvertUtil.toDTO(null, "密码错误", Constants.CODE_PARAMA_ERR, false);
        } catch (LockedAccountException e) {
     
            log.error("[登录异常] >> 账户已锁定 account : {}", username);
            model.addAttribute("msg", "账户已锁定");
            return DtoConvertUtil.toDTO(null, "账户已锁定", Constants.CODE_PARAMA_ERR, false);
        } catch (DisabledAccountException e) {
     
            log.error("[登录异常] >> 账户已停用 account : {}", username);
            model.addAttribute("msg", "账户已停用");
            return DtoConvertUtil.toDTO(null, "账户已停用", Constants.CODE_PARAMA_ERR, false);
        } catch (Exception e) {
     
            log.error("[登录异常] >> 未知异常 account : {}", username);
            model.addAttribute("msg", "未知异常");
            return DtoConvertUtil.toDTO(null, "未知异常", Constants.CODE_PARAMA_ERR, false);
        }
    }

    @GetMapping("/loginout")
    public String loginOut(HttpServletRequest request, HttpServletResponse response){
     
        //在这里执行退出系统前需要清空的数据
        ShiroUtils.logout();
        return "redirect:/user/login";
    }
}

controller请求权限判断

/**
 * 修改保存用户
 */
//@Log(title = "修改保存用户", action = "1")
@ApiOperation(value = "修改保存用户", notes = "修改保存用户")
@RequiresPermissions("system:user:edit")
@PostMapping("/user/edit")
@ResponseBody
public BaseDTO<String> editSave(User user, @RequestParam(value = "roles") List<Long> roles) {
     
    if (roles == null || roles.isEmpty()) {
     
        return DtoConvertUtil.toDTO(null, "请选择角色", Constants.CODE_NO_PERMISSION, false);
    }
    userService.updateUserRoles(user, roles);
    return DtoConvertUtil.toDTO(null, "保存成功", Constants.CODE_SUCCESS, true);
}

页面权限判断

<html class="x-admin-sm" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<shiro:hasPermission name="system:user:edit">
    
shiro:hasPermission>

展示效果

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第1张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第2张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第3张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第4张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第5张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第6张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第7张图片

使用Springboot+shiro+layui打造漂亮简洁的权限控制系统_第8张图片

你可能感兴趣的:(springboot,shiro,spring,boot,shiro,layui)