在数据库中拥有菜单表与用户权限表的情况下,页面上登录账号进去只能看到用户权限表中所存在的菜单,但由于不想每个接口都写权限审查,所以写了一个基于拦截器的权限判断来审查,防止用户在不经过页面操作而是直接通过url跳转到不在自己权限内的菜单中。
数据表:user表(若分角色组的需要另外一个角色表,这里是按账号区分的,所以直接把权限字段rights写在user表中)
menu表(菜单表,我这里设计的字段有menu_id,menu_name,menu_url,parent_id,menu_order,menu_icon, menu_type,menu_state)
拦截器代码:
<!-- 权限访问拦截 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**/*.do"/>
<bean class="com.mxr.interceptor.JurisdictionInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
拦截所有.do的url访问路径。
com.mxr.interceptor.JurisdictionInterceptor类:
public class JurisdictionInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(JurisdictionInterceptor.class);
@Resource(name = "chaMenuService")
private ChaMenuService menuService;
@Resource(name = "chaUserService")
private ChaUserService chaUserService;
/*
*拦截所有.do的访问接口,判断该账号是否拥有权限,若不拥有则无法访问
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取访问的url
String url=request.getRequestURI();
//Const.SHIRO_PREFIX_UN为项目中的“username”
String username=SecurityUtils.getSubject().getPrincipals().asList().get(1).toString().replace(Const.SHIRO_PREFIX_UN, "");
//通过username(唯一)到用户表中获取userId
int userId=chaUserService.getByUsername(username).getUserId();
//通过userId获取权限rights在菜单树中所对应的各个url
List<ChaMenu> chaMenuList = menuService.listTreeMenuByRole(userId);
int flag=0;
//遍历菜单树,若访问的url存在于菜单树url中则flag=1
for(int i=0;i<chaMenuList.size();i++){
for(int j=0;j<chaMenuList.get(i).getSubMenu().size();j++) {
String menuUrl=chaMenuList.get(i).getSubMenu().get(j).getMenuUrl();
if(menuUrl.equals(url)){
flag=1;
}
}
}
if(flag==1){
return true;
}
//设置编码格式
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
PrintWriter pw = response.getWriter();
pw.write("拦截器拦截,无权限操作");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if(ex != null)
logger.error("异常", ex);
}
}
获取用户id下的权限菜单(有缓存)
@Override
public List<ChaMenu> listTreeMenuByRole(int userId) throws Exception {
ChaUser role = chaUserService.getByUserId(userId);
if (role == null)
return new ArrayList<>();
String menuRights = role.getRights();
List<ChaMenu> allMenuList = listAll();
List<ChaMenu> menuList = listTreeMenu(allMenuList, 0, menuRights, true);
return menuList;
}
/**
* 获取所有菜单记录(外部调有缓存,内部则无)
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public List<ChaMenu> listAll() throws Exception {
return (List<ChaMenu>) dao.findForList(MAPPER.concat("listAll"), null);
}
@Override
public List<ChaMenu> listTreeMenu(List<ChaMenu> allMenuList, Integer parentMenuId, String rights, boolean isExcept) {
if(allMenuList == null || allMenuList.size() == 0)
return new ArrayList<>();
List<ChaMenu> list = new ArrayList<>();
for(ChaMenu menu: allMenuList) {
if(menu.getMenuState() == Status.ENABLED.getId())
continue;
if(menu.getParentId() != parentMenuId)
continue;
rights = rights == null ? "" : rights;
boolean hasRights = rights.equals(Const.ALL_RIGHTS) || RightsHelper.testRights(rights, menu.getMenuId());
menu.setHasMenu(hasRights);
if(isExcept && !menu.isHasMenu())
continue;
menu.setSubMenu(listTreeMenu(allMenuList, menu.getMenuId(), rights, isExcept));
if(menu.getSubMenu() != null && menu.getSubMenu().size() > 0)
menu.setTarget("treeFrame");
list.add(menu);
}
return list;
}
/**
* 测试是否具有指定编码的权限
* @param sum
* @param targetRights
* @return
*/
public static boolean testRights(String sum,int targetRights){
if(Tools.isEmpty(sum))
return false;
return testRights(new BigInteger(sum),targetRights);
}