[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

查看日志也會較為輕松

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM