我是靠谱客的博主 激情蜜粉,最近开发中收集的这篇文章主要介绍智能商贸系统07-Shiro权限与菜单1、权限管理2、ajax请求权限拦截3、shrio标签做权限拦截4、菜单管理(层级结构)5、菜单管理(层级+权限结构),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1、权限管理

之前写的权限是写死的,没有根据用户实际生效,如下图:现在做一个真实的权限,主要思路是:
从主体中获取到登录的用户,然后通过自定义jpql,拿到权限
在这里插入图片描述

1.1、FilterChainDefinitionMapFactory,自定义拦截器

public class FilterChainDefinitionMapFactory {
    @Autowired
    private IPermissionService permissionService;
    /*
    *
    *  /login = anon
      /s/permission.jsp = perms[user:index]
     /** = authc
    * */
    public Map<String, String> createMap() {
        Map<String, String> map = new LinkedHashMap<>();
        //一定注意顺序
        //不拦截的
        map.put("/login","anon");
        //把所有的静态资源(js,css,图片,...)放行
        map.put("*.js","anon");
        map.put("*.css","anon");
        map.put("/css/**","anon");
        map.put("/js/**","anon");
        map.put("/easyui/**","anon");
        map.put("/images/**","anon");
        //添加权限拦截数据,从数据库中获取
        List<Permission> permissions = permissionService.findAll();
        permissions.forEach(permission -> {
            map.put(permission.getUrl(),"perms["+permission.getSn()+"]");
        });
        //拦截所有
        map.put("/**","authc");
        return map;
    }
}

1.2、PermissionRepository,自定义jpql,连接5张表

	public interface PermissionRepository extends BaseRepository<Permission, Long> {
    /**
     * 根据用户获取权限
     * 返回的是Set<String>,与AisellRealm对应
     * jpql关连法则:
     *      1,关连前面的类的别名,
     *      2.不需要消除笛卡尔积
     */
    @Query("select p.sn from Employee e join e.roles r join r.permissions p where e.id = ?1")
    Set<String> findSnByUser(Long userId);
}

1.3、AisellRealm

public class AisellRealm extends AuthorizingRealm {
    @Autowired
    private IEmployeeService employeeService;
    @Autowired
    private IPermissionService permissionService;

    //授权功能
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //创建一个授权对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //获取与设置角色,为了演示,写的假的
//        Set<String> roles = findRoles();
//        authorizationInfo.setRoles(roles);
        //拿到与设置权限
        Set<String> perms =permissionService.findSnByUser();
        authorizationInfo.setStringPermissions(perms);
        return authorizationInfo;
    }

2、ajax请求权限拦截

普通请求中比ajax请求的请求头中少了一个X-Requested-With:XMLHttpRequest,而在shiro权限中,ajax跳转返回json格式没有格式化,需要自定义。
在这里插入图片描述
在这里插入图片描述

2.1、自定义权限

写一个类,继承 PermissionsAuthorizationFilter

public class AisellPermissionAuthorizationFiltrer extends PermissionsAuthorizationFilter {
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        Subject subject = this.getSubject(request, response);
        if (subject.getPrincipal() == null) {
            this.saveRequestAndRedirectToLogin(request, response);
        } else {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            String xhr = req.getHeader("X-Requested-With");
            //如果是ajax响应,走这里
            if ("XMLHttpRequest".equals(xhr)) {
                //这里设置响应格式为json格式
                resp.setContentType("application/json; charset=utf-8");
                resp.getWriter().print("{"success":false,"msg":"你没有权限"}");
            } else {
                //没有权限,就走这个页面,在xml中配置了
                String unauthorizedUrl = this.getUnauthorizedUrl();
                if (StringUtils.hasText(unauthorizedUrl)) {
                    //如果有路径,就跳到没有权限的位置
                    WebUtils.issueRedirect(request, response, unauthorizedUrl);
                } else {
                    //如果xml中没有配置路径,就报401的错误
                    WebUtils.toHttp(response).sendError(401);
                }
            }
        }
        return false;
    }
}

2.2、applicationContext-shiro.xml配置拦截器

<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap" />
        <property name="filters">
            <map >
                <entry key="aisellPerms" value-ref="aisellFiler"/>
            </map>
        </property>

2.3、权限使用FilterChainDefinitionMapFactory

注意,这里的aisellPerms一定要与xml配置文件的名字一致

public class FilterChainDefinitionMapFactory {
    @Autowired
    private IPermissionService permissionService;
    /*
    *
    *  /login = anon
      /s/permission.jsp = perms[user:index]
     /** = authc
    * */
    public Map<String, String> createMap() {
        Map<String, String> map = new LinkedHashMap<>();
        //一定注意顺序
        //不拦截的
        map.put("/login","anon");
        //把所有的静态资源(js,css,图片,...)放行
        map.put("*.js","anon");
        map.put("*.css","anon");
        map.put("/css/**","anon");
        map.put("/js/**","anon");
        map.put("/easyui/**","anon");
        map.put("/images/**","anon");
        //添加权限拦截数据,从数据库中获取
        List<Permission> permissions = permissionService.findAll();
        permissions.forEach(permission -> {
            map.put(permission.getUrl(),"aisellPerms["+permission.getSn()+"]");
        });
        //拦截所有
        map.put("/**","authc");
        return map;
    }
}

3、shrio标签做权限拦截

3.1、引入标签

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

3.2、拿到主体的标签

<shiro:principal property="username" />  

3.3、权限判断的标签

<shiro:hasPermission name="employee:delete">
        <a href="javascript:;" data-method="delete" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true">删除</a>
</shiro:hasPermission>

4、菜单管理(层级结构)

4.1、菜单对象

前面已经写好了Menu的CRUD,这里把关系配置好

//parent_id
    //配置一对多
    @OneToMany
    @JoinColumn(name = "parent_id")
    private List<Menu> children = new ArrayList<>();

4.2、MenuRepository

public interface MenuRepository extends BaseRepository<Menu,Long>{

    //查询父级菜子级菜单会自动加载
    @Query("select o from Menu o where o.url is null ")
    List<Menu> findParentMenu();
}

4.3、IMenuService

public interface IMenuService extends IBaseService<Menu,Long> {

    List<Menu> findParentMenu();
}

4.4、MenuController

  //查询菜单,在主页面显示
    @RequestMapping("/findParent")
    @ResponseBody
    public List<Menu> findParentMenu() {
        return menuService.findParentMenu();
    }

4.5、main.jsp主页展示

$('#menuid').tree({
        method: 'post',
        url: '/menu/findParent',
        //点击菜单中间显示选项卡
        .....

注意:菜单展示的时候需要兼容EasyUI中的text格式,新增一个getText()方法。

5、菜单管理(层级+权限结构)

思路:

  • 用户->角色->权限->菜单
  • 用户拥有的权限就是对应的菜单
  • 通过自定义jpql查询到主体中当前用户的所有子菜单,再通过子菜单得到对应的父菜单
  • 新建容器将父菜单和子菜单通通包起来

5.1、domain

Menu
需要将上面写的一对多关系注释掉。

/*
    * 多对一,儿子菜单,可以找到父亲菜单
    *JsonIgnore:生成JSON的时候忽略这个属性
    * */
    @ManyToOne
    @JoinColumn(name = "parent_id")
    @JsonIgnore
    private Menu parent;

    /*@OneToMany
    @JoinColumn(name = "parent_id")*/
    /*
    * 临时属性
    *       这里不能配一对多
    *       在一对多的情况下,菜单会通过父级菜单把所有子级菜单展示
    *       达不到权限的目的。
    *
    * */
    @Transient
    private List<Menu> children = new ArrayList<>();

Permission

 @ManyToOne
    @JoinColumn(name = "menu_id")
    private Menu menu;

5.2、MenuRepository

public interface MenuRepository extends BaseRepository<Menu,Long>{

    //查询父级菜子级菜单会自动加载
    @Query("select o from Menu o where o.url is null ")
    List<Menu> findParentMenu();
    //根据用户名拿到一个人对应的所有子菜单
    @Query("select distinct m from Employee e join e.roles r join r.permissions p join p.menu m where e.id=?1")
    List<Menu> findMenusByUser(Long userId);
}

5.3、MenuServiceImpl

@Service
public class MenuServiceImpl extends BaseServiceImpl<Menu, Long> implements IMenuService {
    @Autowired
    private MenuRepository menuRepository;

    @Override
    public List<Menu> findParentMenu() {
        //创建一个父菜单容器
        List<Menu> parentMenus = new ArrayList<>();
        //拿到当前用用户的菜单
        Employee user = UserContext.getUser();
        List<Menu> menus = menuRepository.findMenusByUser(user.getId());
        //遍历子菜单
        menus.forEach(menu -> {
            Menu menuParent = menu.getParent();
            //判断是否已经有了
            if(!parentMenus.contains(menuParent)){
                parentMenus.add(menuParent);
            }
            menuParent.getChildren().add(menu);
        });
        return parentMenus;
    }
}

5.4、UserContext

抽取的方法

public class UserContext {
    /*
    * 拿到当前用户
    * */
    public static Employee getUser(){
        //当前用户
        Subject subject = SecurityUtils.getSubject();
        //拿到主体(当前登录用户,这里我们写的就是employee,所以强转)
        Employee loginUser = (Employee) subject.getPrincipal();
        return loginUser;
    }
}

最后

以上就是激情蜜粉为你收集整理的智能商贸系统07-Shiro权限与菜单1、权限管理2、ajax请求权限拦截3、shrio标签做权限拦截4、菜单管理(层级结构)5、菜单管理(层级+权限结构)的全部内容,希望文章能够帮你解决智能商贸系统07-Shiro权限与菜单1、权限管理2、ajax请求权限拦截3、shrio标签做权限拦截4、菜单管理(层级结构)5、菜单管理(层级+权限结构)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(32)

评论列表共有 0 条评论

立即
投稿
返回
顶部