基于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
查看日志也会较为轻松
[Shiro] - 基于URL配置动态权限
原文地址:https://www.cnblogs.com/ukzq/p/10247097.html