wisdomsell-day7-权限与菜单

判断权限

//1.拿到所有权限

List<Permission> permissions = permissionService.findAll();
//2.遍历权限,拿到权限与资源
for (Permission permission : permissions) {
    String url = permission.getUrl();//资源
    String sn = permission.getSn();//权限
    //把路径与资源放到拦截中去
    maps.put(url,"wglPer["+sn+"]");
}

2.获取登录用户 在这里插入图片描述

注意:
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
 <h1>
        <div style="text-align: right;padding-right:20px;">欢迎您,<**shiro:principal property="username"**/> <a href="/logout">登出</a>
    </h1>
    public class UserContext {

    public static final String LOGINUSER ="loginUser";

    public static void putUser(){
        Subject subject = SecurityUtils.getSubject();
        //获取到session
        Session session = subject.getSession();
        //获取到相应的主体
        Employee employee = (Employee) subject.getPrincipal();
        //将当前登录用户放到session中
        session.setAttribute(LOGINUSER,employee);
    }

    public static Employee getUser(){
        Subject subject = SecurityUtils.getSubject();
        //获取到session
        Session session = subject.getSession();
        return (Employee) session.getAttribute(LOGINUSER);
    }
}

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public JsonResult login(String username, String password) {
        //1.拿到subject(当前用户)
        Subject subject = SecurityUtils.getSubject();
        //2.如果没有登录,放它登录
        if (!subject.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            try {
                subject.login(token);
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                return  new JsonResult(false,"用户名出错");
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                return  new JsonResult(false,"用户名或者密码错误");
            } catch (AuthenticationException e) {
                System.out.println("未知错误");
                return  new JsonResult(false,"未知错误");
            }
        }
        UserContext.putUser();
        //成功到主页面
        return new JsonResult();
    }

根据用户id拿到权限

PermissionRepository
//根据当前登录用户拿到对应的权限
@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);

IPermissionService 
Set<String> findSnByEmp(Long employeeId);

PermissionServiceImpl
@Override
public Set<String> findSnByEmp(Long employeeId) {
    return permissionRepository.findSnByEmp(employeeId);
}

进入权限判断

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;
    }

自定义权限拦截器

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

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
<!-- 5.shiro的真实过滤器(注:这个名称必需和web.xml的代表过滤器【DelegatingFilterProxy】名称一样) -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- 登录的url,如果没有登录,你访问的路径会跳到这个页面 -->
    <property name="loginUrl" value="/login"/>
    <!-- 登录成功的url,如果登录成功,会跳转到这个页面 -->
    <property name="successUrl" value="/main"/>
    <!-- 没有权限时跳转到这个位置 -->
    <property name="unauthorizedUrl" value="/s/unauthorized.jsp"/>
    <!-- 这个配置我们可以直接给一个map(动态的可以从代码中获取) -->
    <property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>
    <!-- 引用自定义的权限过滤器 -->
    <property name="filters">
        <map>
            <entry key="yxbPerms" value-ref="yxbPermissionsAuthorizationFilter"></entry>
        </map>
    </property>
</bean>

<!-- 配置自定义权限过滤器 -->
<bean id="yxbPermissionsAuthorizationFilter" class="cn.itsource.yxb.shiro.filter.ItsourceYxbPermissionsAuthorizationFilter"></bean>

<!-- 这个bean是帮助咱们获取相应的值:它会到一个工厂bean中通过对应的方法拿到相应的值 -->
<bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="createFilterChainDefinitionMap"></bean>
<!-- 配置可以创建 -->
<bean id="filterChainDefinitionMapBuilder" class="cn.itsource.yxb.shiro.filter.FilterChainDefinitionMapBuilder"></bean>

FilterChainDefinitionMapBuilder
public Map<String,String> createFilterChainDefinitionMap(){

    Map<String, String> 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<Permission> 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;

}

树状菜单显示

@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;
    }
}

3.1.2.Permission
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="menu_id")
private Menu menu;

3.2.功能完成
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<Menu> findByLoginUser(Long userId);


3.2.2.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;
}


3.2.3.UtilController
@RequestMapping("/loginUserMenus")
@ResponseBody
public List loginUserMenus(Long id){
    Employee loginUser = UserContext.getUser();
    return menuService.findByLoginUser(loginUser.getId());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值