[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; @Servicepublic 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:/listProductrequestURI:/deleteProductrequestURI:/deleteOrderrequestURI:/deleteOrderrequestURI:/deleteOrderrequestURI:/unauthorizedrequestURI:/deleteProductrequestURI:/listProduct

查看日志也会较为轻松

 

相关文章