- 权限判断
1.1 拓展方法,获取每一个登录对象的权限,存入map,然后配置到shiro中
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String username = token.getUsername();
Employee loginUser = employeeService.findByUsername(username);
if(loginUser==null){
return null;
}
//拿到登录用户的密码
String dbPassword = loginUser.getPassword();
//设置加盐
ByteSource salt = ByteSource.Util.bytes("itsource");
SimpleAuthenticationInfo authorizationInfo = new SimpleAuthenticationInfo(loginUser,dbPassword,salt,getName());
return authorizationInfo;
}
1.2 处理欢迎[XX ]登录问题
shiro:user
欢迎[ <shiro:principal property=“username” />]登录,退出
</shiro:user>
1.3 在登录成功后把登录对象存入到session中
1.4 拓展方法根据登录对象id获取其权限信息
@Query("select distinct p.sn from Employee e join e.roles r join r.permissions p where e.id = ?1")
Set<String> findSnByEmp(Long employeeId);
1.5 将获取到登录对象的权限返回给shiro底层管理
public class JpaRealm extends AuthorizingRealm {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IPermissionService permissionService;
//AuthorizationInfo:授权(是否有权限进入操作)
// 我们只需要把相应的权限交给Shiro,它就会自动比对
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//拿到主体信息(指的就是当前登录用户)
Employee loginUser = UserContext.getUser();
//获取权限资源(这里假设已经根据用户名到数据库中获取到了)
Set<String> permissions = permissionService.findSnByEmp(loginUser.getId());
//permissions.add("employee:index");
//permissions.add("role:index");
//permissions.add("employee:*");
//拿到授权对象,并且所有权限交给它
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.setStringPermissions(permissions);
//返回授权对象
return simpleAuthorizationInfo;
}
…
}
1.6 处理ajax请求问题
1如果是ajax请求,那么请求头中有
2. 自定义过滤器
public class AisellPermissionAuthorizationFilter extends PermissionsAuthorizationFilter {
//怎么写
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = this.getSubject(request, response);
if (subject.getPrincipal() == null) {
this.saveRequestAndRedirectToLogin(request, response);
} else {
//如果拦截请求是ajax请求,返回json来处理 否者就返回页面
//X-Requested-With
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse)response;
//获取请求头
String header = req.getHeader("X-Requested-With");
if("XMLHttpRequest".equals(header)){
//返回json {"success":false,"msg":"没有权限"}
resp.setContentType("text/json;charset=UTF-8");
resp.getWriter().print("{\"success\":false,\"msg\":\"没有权限\"}");
}else {
//返回页面
String unauthorizedUrl = this.getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl)) {
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
WebUtils.toHttp(response).sendError(401);
}
}
}
return false;
}
}
- 在applicationContext-shiro.xml 中引用自定义的过滤器
- 菜单配置
- Menu菜单配置
@Entity
@Table(name="menu")
public class Menu extends BaseDomain {
private String name;//菜单名称
private String url; //路径
private String icon; //图标
/**
* JsonIgnore:生成JSON的时候忽略这个属性
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="parent_id")
@JsonIgnore //这里生成json的时候要忽略,否则会造成功能相互调用
private Menu parent;
/**
* 还要配置一个一对多
* 这个字段不要交给JPA管理【到时候自己写代码管理】
* 数据库的menu表中就应该有一个children,而且还是List类型
* Transient:临时属性(JPA不管这个属性,和数据库没有关系)
*/
@Transient
private List<Menu> children = new ArrayList<>();
…
public String getText(){ //EasyUI的树需要一个text属性
return name;
}
}
2 permission 配置
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="menu_id")
private Menu menu;
3 根据用户名,拿到相应的菜单
//根据用户名拿到一个人对应的所有子菜单
@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> findByLoginUser(Long userId);
4 menuService层 【重点】
@Override
public List<Menu> findByLoginUser(Long userId) {
//准备父菜单容器
List<Menu> parentMenus = new ArrayList<>();
//从数据库中拿到子菜单
List<Menu> childrenMenus = menuRepository.findByLoginUser(userId);
//遍历子菜单(如果有父菜单放进入,没有单独创建)
for (Menu childrenMenu : childrenMenus) {
//拿到子菜单对应的父菜单
Menu parent = childrenMenu.getParent();
//判断如果父菜单中是否有这个菜单
if(parentMenus.contains(parent)){
//有的话,咱们就把子菜单放到父菜单中去
int i = parentMenus.indexOf(parent);
Menu parentMenu = parentMenus.get(i);
parentMenu.getChildren().add(childrenMenu);
}else{
//如果没有,再单独把父菜单放进去
parentMenus.add(parent);
parent.getChildren().add(childrenMenu);
}
}
return parentMenus;
}
5 UtilController
将main.jsp中加载菜单的url 改成下面的url
实现不同的用户显示不同的菜单功能
@RequestMapping("/loginUserMenus")
@ResponseBody
public List loginUserMenus(Long id){
Employee loginUser = UserContext.getUser();
return menuService.findByLoginUser(loginUser.getId());
}
6,如果没有相应的权限就不显示相应的按钮
<shiro:hasPermission name="employee:save">
<a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
</shiro:hasPermission>
<shiro:hasPermission name="employee:update">
<a href="#" data-method="edit" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
</shiro:hasPermission>
<shiro:hasPermission name="employee:delete">
<a href="#" data-method="del" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
</shiro:hasPermission>