我是靠谱客的博主 激情蜜粉,最近开发中收集的这篇文章主要介绍智能商贸系统07-Shiro权限与菜单1、权限管理2、ajax请求权限拦截3、shrio标签做权限拦截4、菜单管理(层级结构)5、菜单管理(层级+权限结构),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
1、权限管理
之前写的权限是写死的,没有根据用户实际生效,如下图:现在做一个真实的权限,主要思路是:
从主体中获取到登录的用户,然后通过自定义jpql,拿到权限
1.1、FilterChainDefinitionMapFactory,自定义拦截器
public class FilterChainDefinitionMapFactory {
@Autowired
private IPermissionService permissionService;
/*
*
* /login = anon
/s/permission.jsp = perms[user:index]
/** = authc
* */
public Map<String, String> createMap() {
Map<String, String> map = new LinkedHashMap<>();
//一定注意顺序
//不拦截的
map.put("/login","anon");
//把所有的静态资源(js,css,图片,...)放行
map.put("*.js","anon");
map.put("*.css","anon");
map.put("/css/**","anon");
map.put("/js/**","anon");
map.put("/easyui/**","anon");
map.put("/images/**","anon");
//添加权限拦截数据,从数据库中获取
List<Permission> permissions = permissionService.findAll();
permissions.forEach(permission -> {
map.put(permission.getUrl(),"perms["+permission.getSn()+"]");
});
//拦截所有
map.put("/**","authc");
return map;
}
}
1.2、PermissionRepository,自定义jpql,连接5张表
public interface PermissionRepository extends BaseRepository<Permission, Long> {
/**
* 根据用户获取权限
* 返回的是Set<String>,与AisellRealm对应
* jpql关连法则:
* 1,关连前面的类的别名,
* 2.不需要消除笛卡尔积
*/
@Query("select p.sn from Employee e join e.roles r join r.permissions p where e.id = ?1")
Set<String> findSnByUser(Long userId);
}
1.3、AisellRealm
public class AisellRealm extends AuthorizingRealm {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IPermissionService permissionService;
//授权功能
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//创建一个授权对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//获取与设置角色,为了演示,写的假的
// Set<String> roles = findRoles();
// authorizationInfo.setRoles(roles);
//拿到与设置权限
Set<String> perms =permissionService.findSnByUser();
authorizationInfo.setStringPermissions(perms);
return authorizationInfo;
}
2、ajax请求权限拦截
普通请求中比ajax请求的请求头中少了一个X-Requested-With:XMLHttpRequest,而在shiro权限中,ajax跳转返回json格式没有格式化,需要自定义。
2.1、自定义权限
写一个类,继承 PermissionsAuthorizationFilter
public class AisellPermissionAuthorizationFiltrer extends PermissionsAuthorizationFilter {
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = this.getSubject(request, response);
if (subject.getPrincipal() == null) {
this.saveRequestAndRedirectToLogin(request, response);
} else {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String xhr = req.getHeader("X-Requested-With");
//如果是ajax响应,走这里
if ("XMLHttpRequest".equals(xhr)) {
//这里设置响应格式为json格式
resp.setContentType("application/json; charset=utf-8");
resp.getWriter().print("{"success":false,"msg":"你没有权限"}");
} else {
//没有权限,就走这个页面,在xml中配置了
String unauthorizedUrl = this.getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl)) {
//如果有路径,就跳到没有权限的位置
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
//如果xml中没有配置路径,就报401的错误
WebUtils.toHttp(response).sendError(401);
}
}
}
return false;
}
}
2.2、applicationContext-shiro.xml配置拦截器
<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap" />
<property name="filters">
<map >
<entry key="aisellPerms" value-ref="aisellFiler"/>
</map>
</property>
2.3、权限使用FilterChainDefinitionMapFactory
注意,这里的aisellPerms一定要与xml配置文件的名字一致
public class FilterChainDefinitionMapFactory {
@Autowired
private IPermissionService permissionService;
/*
*
* /login = anon
/s/permission.jsp = perms[user:index]
/** = authc
* */
public Map<String, String> createMap() {
Map<String, String> map = new LinkedHashMap<>();
//一定注意顺序
//不拦截的
map.put("/login","anon");
//把所有的静态资源(js,css,图片,...)放行
map.put("*.js","anon");
map.put("*.css","anon");
map.put("/css/**","anon");
map.put("/js/**","anon");
map.put("/easyui/**","anon");
map.put("/images/**","anon");
//添加权限拦截数据,从数据库中获取
List<Permission> permissions = permissionService.findAll();
permissions.forEach(permission -> {
map.put(permission.getUrl(),"aisellPerms["+permission.getSn()+"]");
});
//拦截所有
map.put("/**","authc");
return map;
}
}
3、shrio标签做权限拦截
3.1、引入标签
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
3.2、拿到主体的标签
<shiro:principal property="username" />
3.3、权限判断的标签
<shiro:hasPermission name="employee:delete">
<a href="javascript:;" data-method="delete" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true">删除</a>
</shiro:hasPermission>
4、菜单管理(层级结构)
4.1、菜单对象
前面已经写好了Menu的CRUD,这里把关系配置好
//parent_id
//配置一对多
@OneToMany
@JoinColumn(name = "parent_id")
private List<Menu> children = new ArrayList<>();
4.2、MenuRepository
public interface MenuRepository extends BaseRepository<Menu,Long>{
//查询父级菜子级菜单会自动加载
@Query("select o from Menu o where o.url is null ")
List<Menu> findParentMenu();
}
4.3、IMenuService
public interface IMenuService extends IBaseService<Menu,Long> {
List<Menu> findParentMenu();
}
4.4、MenuController
//查询菜单,在主页面显示
@RequestMapping("/findParent")
@ResponseBody
public List<Menu> findParentMenu() {
return menuService.findParentMenu();
}
4.5、main.jsp主页展示
$('#menuid').tree({
method: 'post',
url: '/menu/findParent',
//点击菜单中间显示选项卡
.....
注意:菜单展示的时候需要兼容EasyUI中的text格式,新增一个getText()方法。
5、菜单管理(层级+权限结构)
思路:
- 用户->角色->权限->菜单
- 用户拥有的权限就是对应的菜单
- 通过自定义jpql查询到主体中当前用户的所有子菜单,再通过子菜单得到对应的父菜单
- 新建容器将父菜单和子菜单通通包起来
5.1、domain
Menu
需要将上面写的一对多关系注释掉。
/*
* 多对一,儿子菜单,可以找到父亲菜单
*JsonIgnore:生成JSON的时候忽略这个属性
* */
@ManyToOne
@JoinColumn(name = "parent_id")
@JsonIgnore
private Menu parent;
/*@OneToMany
@JoinColumn(name = "parent_id")*/
/*
* 临时属性
* 这里不能配一对多
* 在一对多的情况下,菜单会通过父级菜单把所有子级菜单展示
* 达不到权限的目的。
*
* */
@Transient
private List<Menu> children = new ArrayList<>();
Permission
@ManyToOne
@JoinColumn(name = "menu_id")
private Menu menu;
5.2、MenuRepository
public interface MenuRepository extends BaseRepository<Menu,Long>{
//查询父级菜子级菜单会自动加载
@Query("select o from Menu o where o.url is null ")
List<Menu> findParentMenu();
//根据用户名拿到一个人对应的所有子菜单
@Query("select distinct m from Employee e join e.roles r join r.permissions p join p.menu m where e.id=?1")
List<Menu> findMenusByUser(Long userId);
}
5.3、MenuServiceImpl
@Service
public class MenuServiceImpl extends BaseServiceImpl<Menu, Long> implements IMenuService {
@Autowired
private MenuRepository menuRepository;
@Override
public List<Menu> findParentMenu() {
//创建一个父菜单容器
List<Menu> parentMenus = new ArrayList<>();
//拿到当前用用户的菜单
Employee user = UserContext.getUser();
List<Menu> menus = menuRepository.findMenusByUser(user.getId());
//遍历子菜单
menus.forEach(menu -> {
Menu menuParent = menu.getParent();
//判断是否已经有了
if(!parentMenus.contains(menuParent)){
parentMenus.add(menuParent);
}
menuParent.getChildren().add(menu);
});
return parentMenus;
}
}
5.4、UserContext
抽取的方法
public class UserContext {
/*
* 拿到当前用户
* */
public static Employee getUser(){
//当前用户
Subject subject = SecurityUtils.getSubject();
//拿到主体(当前登录用户,这里我们写的就是employee,所以强转)
Employee loginUser = (Employee) subject.getPrincipal();
return loginUser;
}
}
最后
以上就是激情蜜粉为你收集整理的智能商贸系统07-Shiro权限与菜单1、权限管理2、ajax请求权限拦截3、shrio标签做权限拦截4、菜单管理(层级结构)5、菜单管理(层级+权限结构)的全部内容,希望文章能够帮你解决智能商贸系统07-Shiro权限与菜单1、权限管理2、ajax请求权限拦截3、shrio标签做权限拦截4、菜单管理(层级结构)5、菜单管理(层级+权限结构)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复