智能商贸-day7-权限与菜单

1.1. 权限判断

1.1.1. 获取到所有权限进行判断

FilterChainDefinitionMapBuilder:

public class FilterChainDefinitionMapBuilder {

    @Autowired
    private IPermissionService permissionService;

    public Map createFilterChainDefinitionMap(){
       …
        filterChainDefinitionMap.put("/logout","logout"); //不登录也可以访问
        //从数据库拿到数据,放到咱们的Map中
        //1.拿到所有权限
        List permissions = permissionService.findAll();
        //2.遍历权限,拿到权限与资源
        for (Permission permission : permissions) {
            String url = permission.getUrl();//资源
            String sn = permission.getSn();//权限
            //把路径与资源放到拦截中去
            filterChainDefinitionMap.put(url,"perms["+sn+"]");
        }
        filterChainDefinitionMap.put("/**","authc");

        return  filterChainDefinitionMap;

    }
}

1.1.2. 完成权限的判断

其它完成权限,就是通过当前登录用户拿到所有权限,然后去判断当前用户是否有咱们当前访问的这路径的权限!

  1. 怎么拿到登录用户
    先把主体修改成Employee用户:
    主体改成当前登录用户:
//完成登录的认证
@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. UserContext:设置与拿到当前登录用户
public class UserContext {
    private static final String USER_IN_SESSION = "loginUser";
    /**
     * 把当前登录用户放入Session
     * @param loginUser
     */
    public static void setUser(Employee loginUser) {
        Subject subject = SecurityUtils.getSubject();
        subject.getSession().setAttribute(USER_IN_SESSION, loginUser);
    }
    /**
     * 从Session中获取User
     */
    public static Employee getUser() {
        Subject subject = SecurityUtils.getSubject();
        Employee curentUser = (Employee) subject.getSession().getAttribute(USER_IN_SESSION);
        return curentUser;
    }
}
  1. LoginController:登录成功后把用户放到Session中
@RequestMapping(value="/login",method = RequestMethod.POST)
@ResponseBody
public JsonResult login(String username, String password){
    //1.拿到访问的主体(当前登录用户)
    Subject subject = SecurityUtils.getSubject();
    //2.判断这个用户是否已经登录(通过验证)
    if(!subject.isAuthenticated()){
        ….
    }
    //登录成功后,把当前登录用户放到session中
    //1.拿到当前登录用户(这个主体就是当前登录用户)
    Employee loginUser = (Employee) subject.getPrincipal();
    //2.当前登录用户放到session中
    UserContext.setUser(loginUser);
    return new JsonResult();
}
  1. 根据用户id拿到权限
    PermissionRepository
//根据当前登录用户拿到对应的权限
@Query("select distinct p.sn from Employee e join e.roles r join r.permissions p where e.id = ?1")
Set findSnByEmp(Long employeeId);

IPermissionService 
Set findSnByEmp(Long employeeId);

PermissionServiceImpl
@Override
public Set findSnByEmp(Long employeeId) {
    return permissionRepository.findSnByEmp(employeeId);
}
  1. JpaRealm:进入权限判断
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 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.2. 权限判断Ajax请求

1.2.1. 判断需知

咱们所有的请求可以分为两大类,一个是跳转页面,xxx/index 还有一类是Ajax请求期望返回的是{“success”:false,”message”:”没有权限”}

区分处理是否是Ajax请求,普通跳转页面的请求 ,就跳转没有权限的页面,如果是ajax请求返回{“success”:false,”message”:”没有权限”}

?怎么Ajax 判断请求头里面是否有X-Requested-With
跳转页面请求头

Ajax请求多个一个请求头X-Requested-With XMLHttpRequest

1.2.2. 自定义权限拦截器

区分处理–shiro默认的权限过滤器不支持,需要自定义过滤器才行

上面的配置会交给

自定义权限的功能:可以参考我们给大家准备Shiro的资料

//ItsourceYxbPermissionsAuthorizationFilter:自定义权限过滤器
public class ItsourceYxbPermissionsAuthorizationFilter 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 {
            //登录成功后没有权限的操作
            //1.转成http的请求与响应操作
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            //2.根据请求确定是什么请求
            String xRequestedWith = httpRequest.getHeader("X-Requested-With");
            if (xRequestedWith != null &&"XMLHttpRequest".equals(xRequestedWith)) {
                //3.在这里就代表是ajax请求
                //表示ajax请求 {"success":false,"message":"没有权限"}
                httpResponse.setContentType("text/json; charset=UTF-8");
                httpResponse.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



    
    
    
    
    
    
    
    
    
    
    
        
            
        
    









FilterChainDefinitionMapBuilder

public Map createFilterChainDefinitionMap(){

    Map filterChainDefinitionMap = new LinkedHashMap();
    //注:对于一些不登录也可以放行的设置(大家可以根据实际情况添加)
    filterChainDefinitionMap.put("/login","anon");
    filterChainDefinitionMap.put("*.js","anon");
    filterChainDefinitionMap.put("*.css","anon");
    filterChainDefinitionMap.put("/css/**","anon");
    filterChainDefinitionMap.put("/js/**","anon");
    filterChainDefinitionMap.put("/easyui/**","anon");
    filterChainDefinitionMap.put("/images/**","anon");

    filterChainDefinitionMap.put("/logout","logout"); //不登录也可以访问
    //这个值之后从数据库中查询到【用户-角色-权限-资源】
    //从数据库拿到数据,放到咱们的Map中
    //1.拿到所有权限
    List permissions = permissionService.findAll();
    //2.遍历权限,拿到权限 资源
    for (Permission permission : permissions) {
        String url = permission.getUrl();//资源
        String sn = permission.getSn();//权限
        //把路径与资源放到拦截中去
        filterChainDefinitionMap.put(url,"yxbPerms["+sn+"]");
    }
    filterChainDefinitionMap.put("/**","authc");
    return  filterChainDefinitionMap;

}

1.3. 菜单读取

用户->角色->权限->菜单

1.3.1. Domain设计

  1. 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 children = new ArrayList<>();

    …
   public String getText(){ //EasyUI的树需要一个text属性
      return name;
    }
}
  1. Permission
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="menu_id")
private Menu menu;

1.3.2. 功能完成

  1. MenuRepository
//根据用户名拿到一个人对应的所有子菜单
@Query("select distinct m from Employee e join e.roles r join r.permissions p join p.menu m where e.id = ?1")
List findByLoginUser(Long userId);
  1. MenuService
@Override
public List findByLoginUser(Long userId) {
    //准备父菜单容器
    List parentMenus = new ArrayList<>();
    //从数据库中拿到子菜单
    List 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;
}
  1. UtilController
@RequestMapping("/loginUserMenus")
@ResponseBody
public List loginUserMenus(Long id){
    Employee loginUser = UserContext.getUser();
    return menuService.findByLoginUser(loginUser.getId());
}

1.4. 页面按钮权限控制

1.4.1. 功能实现


    添加


    修改


    删除

你可能感兴趣的:(智能商贸-day7-权限与菜单)