[Shiro] - 基于URL配置动态权限

Posted ukzq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Shiro] - 基于URL配置动态权限相关的知识,希望对你有一定的参考价值。

基于shiro进阶

更改了数据库表

之前的PageController是通过@RequiresPermissions和@RequiresRoles进行是否有权限/是否有角色的判定调用@RequestMapping路径

在PermissionService中加入了两个方法:needInterceptor, listPermissionURLs

needInterceptor表示是否要进行拦截,判断依据是如果访问的某个url,在权限系统里存在,就要进行拦截.

如果不存在就放行了. 这一种策略,也可以切换成另一个,即:

访问的地址如果不存在于权限系统中,就提示没有拦截.这两种做法没有对错之分,取决于业务上希望如何制定权限策略。

listPermissionURLs(User user)用来获取某个用户所拥有的权限地址集合

package com.how2java.service.impl;
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.how2java.mapper.PermissionMapper;
import com.how2java.mapper.RolePermissionMapper;
import com.how2java.pojo.Permission;
import com.how2java.pojo.PermissionExample;
import com.how2java.pojo.Role;
import com.how2java.pojo.RolePermission;
import com.how2java.pojo.RolePermissionExample;
import com.how2java.service.PermissionService;
import com.how2java.service.RoleService;
import com.how2java.service.UserService;
 
@Service
public class PermissionServiceImpl implements PermissionService {
 
    @Autowired
    PermissionMapper permissionMapper;
    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;
    @Autowired
    RolePermissionMapper rolePermissionMapper;
 
    @Override
    public Set<String> listPermissions(String userName) {
        Set<String> result = new HashSet<>();
        List<Role> roles = roleService.listRoles(userName);
 
        List<RolePermission> rolePermissions = new ArrayList<>();
 
        for (Role role : roles) {
            RolePermissionExample example = new RolePermissionExample();
            example.createCriteria().andRidEqualTo(role.getId());
            List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
            rolePermissions.addAll(rps);
        }
 
        for (RolePermission rolePermission : rolePermissions) {
            Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
            result.add(p.getName());
        }
 
        return result;
    }
 
    @Override
    public void add(Permission u) {
        permissionMapper.insert(u);
    }
 
    @Override
    public void delete(Long id) {
        permissionMapper.deleteByPrimaryKey(id);
    }
 
    @Override
    public void update(Permission u) {
        permissionMapper.updateByPrimaryKeySelective(u);
    }
 
    @Override
    public Permission get(Long id) {
        return permissionMapper.selectByPrimaryKey(id);
    }
 
    @Override
    public List<Permission> list() {
        PermissionExample example = new PermissionExample();
        example.setOrderByClause("id desc");
        return permissionMapper.selectByExample(example);
 
    }
 
    @Override
    public List<Permission> list(Role role) {
        List<Permission> result = new ArrayList<>();
        RolePermissionExample example = new RolePermissionExample();
        example.createCriteria().andRidEqualTo(role.getId());
        List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
        for (RolePermission rolePermission : rps) {
            result.add(permissionMapper.selectByPrimaryKey(rolePermission.getPid()));
        }
 
        return result;
    }
 
    @Override
    public boolean needInterceptor(String requestURI) {
        List<Permission> ps = list();
        for (Permission p : ps) {
            if (p.getUrl().equals(requestURI))
                return true;
        }
        return false;
    }
 
    @Override
    public Set<String> listPermissionURLs(String userName) {
        Set<String> result = new HashSet<>();
        List<Role> roles = roleService.listRoles(userName);
 
        List<RolePermission> rolePermissions = new ArrayList<>();
 
        for (Role role : roles) {
            RolePermissionExample example = new RolePermissionExample();
            example.createCriteria().andRidEqualTo(role.getId());
            List<RolePermission> rps = rolePermissionMapper.selectByExample(example);
            rolePermissions.addAll(rps);
        }
 
        for (RolePermission rolePermission : rolePermissions) {
            Permission p = permissionMapper.selectByPrimaryKey(rolePermission.getPid());
            result.add(p.getUrl());
        }
 
        return result;
    }
 
}

注意其中的for循环,是否可以进行更优化的写法

 

URLPathMatchingFilter, PathMatchingFilter是shiro内置过滤器.URL...继承了Path...

基本思路:

1. 如果没登录就跳转到登录

2. 如果当前访问路径没有在权限系统里维护,则允许访问

3. 当前用户所拥有的权限如何不包含当前的访问地址,则跳转到/unauthorized, 否则就允许访问

package com.how2java.filter;
 
import java.util.Set;
 
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
 
import com.how2java.service.PermissionService;
 
public class URLPathMatchingFilter extends PathMatchingFilter {
    @Autowired
    PermissionService permissionService;
 
    @Override
    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        String requestURI = getPathWithinApplication(request);
 
        System.out.println("requestURI:" + requestURI);
 
        Subject subject = SecurityUtils.getSubject();
        // 如果没有登录,就跳转到登录页面
        if (!subject.isAuthenticated()) {
            WebUtils.issueRedirect(request, response, "/login");
            return false;
        }
 
        // 看看这个路径权限里有没有维护,如果没有维护,一律放行(也可以改为一律不放行)
        boolean needInterceptor = permissionService.needInterceptor(requestURI);
        if (!needInterceptor) {
            return true;
        } else {
            boolean hasPermission = false;
            String userName = subject.getPrincipal().toString();
            Set<String> permissionUrls = permissionService.listPermissionURLs(userName);
            for (String url : permissionUrls) {
                // 这就表示当前用户有这个权限
                if (url.equals(requestURI)) {
                    hasPermission = true;
                    break;
                }
            }
 
            if (hasPermission)
                return true;
            else {
                UnauthorizedException ex = new UnauthorizedException("当前用户没有访问路径 " + requestURI + " 的权限");
 
                subject.getSession().setAttribute("ex", ex);
 
                WebUtils.issueRedirect(request, response, "/unauthorized");
                return false;
            }
 
        }
 
    }
}

以及applicationContext-shiro.xml做了改动

将urlPathMatchingFilter加入shiro使用这个过滤器

这样一样就配置全部的url路径了,而对应的角色没有和url对应起来.

为什么不把角色也对应起来,从代码开发角色来说是可以的,无非是role表添加一个url字段,但是从权限管理本身,当一个url即对应权限表的数据,又对应角色表的数据,

反而容易产生混淆.

这种呢,url地址,仅仅和权限表关联,从逻辑上明晰简单,更易维护.

requestURI:/
requestURI:/listProduct
requestURI:/deleteProduct
requestURI:/deleteOrder
requestURI:/deleteOrder
requestURI:/deleteOrder
requestURI:/unauthorized
requestURI:/deleteProduct
requestURI:/listProduct

查看日志也会较为轻松

 

以上是关于[Shiro] - 基于URL配置动态权限的主要内容,如果未能解决你的问题,请参考以下文章

shiro动态控制url资源

一套基于SpringBoot+Vue+Shiro 前后端分离 开发的代码生成器

第十九章 动态URL权限控制——《跟我学Shiro》

springMvc+shiro做权限管理,页面上的静态资源,样式图片等没有出现,用几种方式过滤试过,还是不行

shiro教程-基于url权限管理

了解权限控制框架shiro 之实际应用.