您好!欢迎来到北极熊

北极熊

热门搜索: 任正非传    神雕侠侣    红楼梦   

SpringBoot+Shiro配置数据库实现后台管理页面根据角色权限动态生成菜单栏

分类:软件开发应用 时间:2022-09-26 22:03 浏览:274
概述
目录前言配置数据库动态生成菜单栏数据库表后台实现shiro配置实现步骤总结参考表数据测试页面效果前言SpringBoot+Shiro做后台管理项目配置权限时,普遍的做法是通过配置shiro标签在html页面里面,来判断当前用户是否拥有该权限,来确认是否展示当前菜单,shiro标签类似如下: Java<!--验证当前用户是否拥有指定权限。  --> <a shiro:ha
内容

目录

前言

SpringBoot+Shiro做后台管理项目配置权限时,普遍的做法是通过配置shiro标签在html页面里面,来判断当前用户是否拥有该权限,来确认是否展示当前菜单,shiro标签类似如下:

 Java

<!--验证当前用户是否拥有指定权限。  --> <a shiro:hasPermission="user:add" href="#" >add用户</a><!-- 拥有权限 --> <!--与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。--> <p shiro:lacksPermission="user:del"> 没有权限 </p> <!--验证当前用户是否拥有以下所有权限。--> <p shiro:hasAllPermissions="user:view, user:add"> 权限与判断 </p>

这种方式缺点是需要手写所有菜单标签,也要在shiro标签内加上对应的权限标识,在菜单列表比较多的时候,index页面会显得很臃肿,而且自己也容易混淆其中的权限标识。

配置数据库动态生成菜单栏

配置后台权限表,在用户登录通过后,进入index页面时,通过用户的角色id查询出该用户拥有的权限,在使用freemarker或者thymeleaf模板引擎动态地渲染出左侧菜单栏。在需要添加菜单栏时,只需要在数据库中添加数据就可以了。并且所有的权限数据都是在数据库中完成的,不需要再单独地写shiro标签了。

实现步骤

数据库表

1.user表

2.user_role表

3.role表

4.permission表

5.role_permission表

6.menu表

后台实现

  1. Controller

     Java

    @GetMapping("/index") public String login(Model model) { 
        //获取当前用户名得到菜单 
        Subject subject = SecurityUtils.getSubject(); 
        if(!subject.isAuthenticated()) { 
            return "/login"; 
        } 
        //根据当前登录账号来获取当前当前账号所拥有权限的菜单列表 
        String username = subject.getPrincipal().toString(); 
        List<Menus> menuTree = menuService.findMenuTreeByUsername(username); 
        model.addAttribute("menuTree",menuTree); 
        return "index"; }
  2. Service

    public interface MenuService extends IService

    {
    List findMenuTreeByUsername(String username);
    }


  3. ServiceImpl

    @Service
    public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    private MenuMapper menuMapper;

     Java

    @Override 
    public List<Menus> findMenuTreeByUsername(String username) { 
        return menuMapper.findMenuTreeByUsername(username); }

    }

  4. Mapper

    public interface MenuMapper extends BaseMapper

    {
    /***
    * 根据用户名获取菜单树
    * @param username
    * @return
    */
    List findMenuTreeByUsername(@Param(“username”)String username);
    }


  5. xml

     Java

    <resultMap type="com.appointment.model.vo.Menus" id="MenuMap"> 
        <id property="menuId" column="id" jdbcType="BIGINT" /> 
        <result property="menuName" column="menu_name" jdbcType="VARCHAR"/> 
        <result property="menuIcon" column="menu_icon" jdbcType="VARCHAR"/> 
        <collection property="subMenus" ofType="com.appointment.model.vo.Menus"> 
            <id property="menuId" column="mid" jdbcType="BIGINT" /> 
            <result property="menuName" column="mname" jdbcType="VARCHAR"/> 
            <result property="menuUrl" column="murl" jdbcType="VARCHAR"/> 
        </collection> </resultMap> 
     <select id="findMenuTreeByUsername" resultMap="MenuMap"> 
        select pm.id,pm.menu_name,pm.menu_icon,m.id mid,m.menu_name mname,m.menu_url murl 
    	from user u 
    	inner join user_role ur on u.id=ur.user_id 
    	inner join role role on ur.role_id=role.id 
    	inner join role_permission rp on role.id=rp.role_id 
    	inner join permission p on rp.permission_id=p.id 
    	inner join menu m on p.menu_id=m.id 
    	inner join menu pm on m.menu_id=pm.id 
    	where u.username=#{username} </select>
  6. VO对象

    @Data
    public class Menus {
    private Long menuId;
    private String menuName;
    private String menuUrl;
    private String menuIcon;
    private List subMenus;
    }

  7. index页面使用freemarker渲染菜单列表

     Java

    		//此处是通过freemarker模板引擎生成,用thymeleaf的话也是可以的 
            <ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu"> 
                menuTree 
                <#list menuTree as menus> 
                <li class="layui-nav-item"> 
                    <a href="javascript:;"><i class="${menus.menuIcon}"></i> 
                        ${menus.menuName} 
                    </a> 
                    <dl  class="layui-nav-child"> 
                        <#list menus.subMenus as s> 
                        <dd data-name="${s.menuName}" > 
                            <a lay-href="${request.contextPath}${s.menuUrl}">${s.menuName}</a> 
                        </dd> 
                        </#list>< 
                    /dl> 
                </li> 
                </#list> 
            </ul>

shiro配置

  1. ShiroConfig添加权限标识
    ShiroConfig文件里面,通过查询在数据库里配置的全选标识,给所有的需要权限的资源添加权限标识,同时,通过这种方式,直接省略了在每个接口上面添加@RequiresPermissions(“user:add”)类似的注解

     Java

    /** 
     * 定义shiroFilter过滤器并注入securityManager 
     * @param manager 
     * @return 
     */ @Bean("shiroFilter")       //必须叫这个。 public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) { 
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); 
        //设置securityManager 
        bean.setSecurityManager(manager); 
        //设置登录页面 
        bean.setLoginUrl("/login"); 
        bean.setSuccessUrl("/index"); 
        bean.setUnauthorizedUrl("/auth.html"); 
        //定义过滤器 
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); 
        //配置记住我或认证通过可以访问的地址 
        filterChainDefinitionMap.put("/index", "anon"); 
        filterChainDefinitionMap.put("/login", "anon"); 
        filterChainDefinitionMap.put("/static/**", "anon"); 
        filterChainDefinitionMap.put("/swagger-ui.html", "anon"); 
        filterChainDefinitionMap.put("/swagger-resources", "anon"); 
        filterChainDefinitionMap.put("/swagger-resources/configuration/security", "anon"); 
        filterChainDefinitionMap.put("/swagger-resources/configuration/ui", "anon"); 
        filterChainDefinitionMap.put("/api/**", "anon"); 
        //通过查询在数据库里面的权限标识,循环给自己设定的字段添加标识权限 
        List<Permission> list = permissionMapper.getAll(); 
        for (Permission permission : list) { 
            filterChainDefinitionMap.put(permission.getResource(), "perms["+permission.getSn()+"]"); 
        } 
        //需要登录访问的资源 , 一般将/**放在最下边 
        filterChainDefinitionMap.put("/**", "anon");   //    , 不需要认证。 
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap); 
        return bean; }
  2. permissionMapper

    public interface PermissionMapper extends BaseMapper {
    List getPermissionsByUserName(@Param(“username”)String username);

     Java

    List<Permission> getAll();

    }

  3. Xml

     Java

    <select id="getAll" resultMap="BaseResultMap"> 
        select * from permission 
    </select>
  4. 创建realm类

     Java

    @Override 
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
        log.info("Shiro开始授权操作"); 
        String username = SecurityUtils.getSubject().getPrincipal().toString(); 
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); 
        Set<String> roles=new HashSet<>(); 
        //得到一个用户的所有角色 
        List<Role> rolesList = roleMapper.getRolesByUserName(username); 
        for (Role role : rolesList) { 
            roles.add(role.getRoleName()); 
        } 
        //得到一个用户的所有权限,给当前用户授权 
        List<Permission> permissionsList = permissionMapper.getPermissionsByUserName(username); 
        for (Permission permission : permissionsList) { 
            authorizationInfo.addStringPermission(permission.getSn()); 
        } 
        authorizationInfo.setRoles(roles); 
        return authorizationInfo; }
  5. Mapper

    public interface RoleMapper extends BaseMapper {
    List getRolesByUserName(@Param(“username”)String username);
    }

  6. xml

     Java

    <select id="getRolesByUserName" resultMap="BaseResultMap"> 
        select 
    	r.id, 
    	r.role_name, 
    	r.remake 
    	from role r 
    	left join user_role ur on ur.role_id=r.id 
    	left join user u on u.id=ur.user_id 
    	where u.username=#{username} </select>
  7. xml

     Java

    <resultMap id="BaseResultMap" type="com.appointment.model.Permission"> 
        <id column="id" property="id" /> 
        <result column="permission_name" property="permissionName" /> 
        <result column="sn" property="sn" /> 
        <result column="resource" property="resource" /> 
        <result column="menu_id" property="menuId" /> </resultMap> <select id="getPermissionsByUserName" resultMap="BaseResultMap"> 
        select 
    	p.id id, 
    	p.permission_name, 
    	p.resource resource, 
    	p.sn sn, 
    	p.menu_id 
    	from permission p 
    	left join role_permission rp on rp.permission_id=p.id 
    	left join role r on r.id=rp.role_id 
    	left join user_role ur on ur.role_id=r.id 
    	left join user u on u.id=ur.user_id 
    	where u.username=#{username} </select>

总结

在使用这种方式动态生成菜单栏的话,刚开始没接触过时会觉得难以理解,实际上只要弄清楚了这些表之间的关系,再整理一下实现逻辑,最后发现这种方式还是挺方便的。

参考表数据

menu

permission表

role_permission

role

role_user

user

测试页面效果


本文参考链接:https://blog.csdn.net/m0_67391870/article/details/126509506


评论
资讯正文页右侧广告
联系我们
电话:18936411277
邮箱:1044412291@qq.com
时间:09:00 - 19:00
公众号:北格软件
底部广告