权限判断和菜单读取

本文介绍了如何在系统中实现权限判断和菜单读取。首先,通过登录成功将用户信息存入Session。接着,从数据库获取用户权限,并在PermissionRepository中增加相应方法。在PermissionServiceImpl中处理这些权限。然后,利用JpaRealm进行权限判断,区分普通请求和AJAX请求。此外,还创建了自定义过滤器并在shiro配置中定义过滤链。最后,详细讲述了菜单的加载过程,包括Menu菜单的定义、Permission的扩展以及MenuService的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

获取到所有权限进行判断

public class FilterChainDefinitionMapBuilder {

    @Autowired
    private IPermissionService permissionService;

    public Map<String,String> createFilterChainDefinitionMap(){
       …
        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,"perms["+sn+"]");
        }
        filterChainDefinitionMap.put("/**","authc");

        return  filterChainDefinitionMap;

    }
}

拿到登录用户

//完成登录的认证
@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;
}

新建一个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;
    }
}

.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();
    }

根据用户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);
}

JpaRealm:进入权限判断

   @Override
    //授权验证  AuthorizationInfo:授权(是否有权限进入操作)
    // 我们只需要把相应的权限交给Shiro,它就会自动比对
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //当前用户的权限弄出来 --给shiro 让shiro 进行比较  做权限的操作
        //得到主体/用户
        Employee employee =(Employee)principalCollection.getPrimaryPrincipal();
        //根据用户 从数据库去拿到对应权限 加入到shiro里面
        Set<String> permissions = permissionService.findPermissionsByLoginUser(employee.getId());
        //查询数据库 jpql语句
        SimpleAuthorizationInfo simpleAuthorizationInfo  = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);

        //返回到shiro里面 就会进行权限的判断
        return simpleAuthorizationInfo;
    }

权限判断
一般请求和AJAX请求区分
Ajax请求多个一个请求头X-Requested-With XMLHttpRequest
自定义过滤器

package cn.itsource.aisell.shiro;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

		...
       <!--配置自定义权限过滤器-->
        <property name="filters" >
            <map>
                <entry key="aisellPerm" value-ref="aisellPermissionAuthorizationFilter"></entry>
            </map>
        </property>

    </bean>
    <bean id="aisellPermissionAuthorizationFilter" class="cn.itsource.aisell.shiro.AisellPermissionAuthorizationFilter"></bean>

FilterChainDefinitionMapBuilder

    @Autowired
    private IPermissionService permissionService;
    //得到Map
    public Map buildFilterChaiDefinitionMap(){
        /*按照 顺序放行 不能下载配置文件中,因为写死了,现在要动态获取后台数据库的
          /s/login.jsp=anon
          /login=anon
          /s/permission.jsp = perms[user:*]
          /**=authc
        */
        Map map = new LinkedHashMap();
        map.put("/login","anon");
        map.put("*.js","anon");
        map.put("*.css","anon");
        map.put("/css/**","anon");
        map.put("/js/**","anon");
        map.put("/easyui/**","anon");
        map.put("/images/**","anon");
        map.put("/s/login.jsp","anon");

        map.put("/s/permission.jsp","perms[user:*]");
        //1.拿到所有权限
        List<Permission> permissions = permissionService.findAll();
        //遍历所有 拿到权限和资源
        for (Permission permission : permissions) {
            //放到map里面
            String url = permission.getUrl();
            String sn = permission.getSn();
            map.put(url, "aisellPerm["+sn+":*]");
        }
        map.put("/**","authc");
        return map;
    }

菜单读取

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

Permission 添加一个

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

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

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、付费专栏及课程。

余额充值