Servlet实现RBAC权限管理(二)
  TEZNKK3IfmPf 2023年11月15日 34 0

勿以恶小而为之,勿以善小而不为--------------------------刘备

劝诸君,多行善事积福报,莫作恶

上一章简单介绍了 RBAC权限(一) ,如果没有看过,请观看上一章

在观看这一章节之前,需要先知道 老蝴蝶刚写的文章: Servlet开发搭建

本章节所使用的表,仍然是 RBAC 权限讲解的那五张表, 框架使用的是 Servlet开发搭建的框架。

一. 准备阶段

一.一 数据库准备阶段

(关于数据库的数据,会放置一个 rbac.sql 文件上来的,读者可以执行,故不复制 insert 插入语句了)

user 表数据 (密码被MD5 加密过了,明文为 1234)

Servlet实现RBAC权限管理(二)

role 表数据:

Servlet实现RBAC权限管理(二)

user_role 表数据

Servlet实现RBAC权限管理(二)

admin 是管理员, yuejl 是经理, yuezl 是普通职员

privilege 表数据:

Servlet实现RBAC权限管理(二)

role_privilege 表数据:

Servlet实现RBAC权限管理(二)

用户有哪些权限,有点晕啊, 老蝴蝶这儿查询一下。

admin 所拥有的权限:

select * from privilege a where a.id in ( select rp.pid from user_role ur left join role_privilege rp 
          on ur.rid=rp.rid  where ur.uid=1 );

Servlet实现RBAC权限管理(二)

岳建立所拥有的权限:

Servlet实现RBAC权限管理(二)

岳泽霖所拥有的权限:

Servlet实现RBAC权限管理(二)

另外,还有一个部门表, dept, 用来演示具体的按钮权限数据。

Servlet实现RBAC权限管理(二)

一.二 前端页面准备阶段

(前端页面代码较多,这儿就不复制了,只讲解一下,各个页面的作用和相应的截图)

Servlet实现RBAC权限管理(二)

jdbc.properties ,是数据库配置文件

driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/rbac?characterEncoding=UTF-8
username=root
password=abc123

dept.js,是 部门功能的js脚本

pages/dept.jsp 页面,是部门的页面,实现相应信息

Servlet实现RBAC权限管理(二)

pages/detailInfo.jsp ,是查看个人信息的页面,不实现相应的信息

Servlet实现RBAC权限管理(二)

pages/login.jsp,登录的页面,实现相应的信息

Servlet实现RBAC权限管理(二)

pages/main.jsp ,主页展示的页面, 实现相应的信息

Servlet实现RBAC权限管理(二)

pages/noPrivilege.jsp, 无权限时展示的页面, 实现相应的信息

Servlet实现RBAC权限管理(二)

pages/updateInfo.jsp, 是修改个人信息的界面,不实现相应的信息

Servlet实现RBAC权限管理(二)

pages/user.jsp , 是员工的页面,不实现相应的信息。

Servlet实现RBAC权限管理(二)

以部门表,进行详细的权限举例分析。

二. 权限认证

目录结构如下所示:

Servlet实现RBAC权限管理(二)

二.一 认证和授权

在登录的方法里面,进行验证,如果查询出有这个员工的信息,就去查询这个员工的权限数据。

这个方法 写在 UserServlet 的 login 方法里面。

二.一.一 登录方法进行认证和查询权限

public void login(HttpServletRequest req,HttpServletResponse resp){
    //将请求信息,封装到对象里面。
    User userInfo=super.reqParamToBean(req,User.class);
    userService=new UserServiceImpl();

    //从数据库中查询密码
    User user=userService.login(userInfo);

    if(user!=null){
      //说明登录成功,放置到session里面
      HttpSession session=req.getSession();
      session.setAttribute("loginUser",user);

      //查询一下,该员工的 按钮权限信息。
      privilegeService=new PrivilegeServiceImpl();

      List<Privilege> privilegeList= privilegeService.getPrivilegeByUId(user.getId(),2);

      List<String> priCodeList=new ArrayList<String>();
      for(Privilege pri:privilegeList){
        if(pri.getPercode()!=null){
          //放置标识
          priCodeList.add(pri.getPercode());
        }

      }
      JsonConfig jsonConfig = new JsonConfig();
      JSONArray objData=JSONArray.fromObject(priCodeList,jsonConfig);
      JSONObject objMap=new JSONObject();
      objMap.put("data",objData);
      //转换成 json 字符串对象
      session.setAttribute("privilegeList",objMap.toString());

      //登录成功
      super.boolean2Json(resp, true);

    }else{
      //代码为001,表示用户名或者密码错误
       super.map2Json(resp,"001");
    }

}

如果登录成功,那么就跳转到 main.jsp 的页面。

(该代码存放在 login.jsp 的页面)

Servlet实现RBAC权限管理(二)

二.一.二 权限菜单展示

main.jsp 的左侧菜单,是动态地读取出来的,然后渲染到页面上。

二.一.二.一 菜单 div

<!-- 存放左侧的菜单事件 -->
<div class="leftmenu" id="leftmenu">
    <div id="leftmenu_0" class="leftmenu-item">

    </div>

</div>

二.一.二.二 根据登录者id 动态查询权限,渲染到页面 leftmenu 上

/*获取所有的权限信息*/
      function getAllPrivilege(){
            //取出当前登录的用户信息
             var userId='';
             console.log("id:"+userId);

             $.post("Privilege?method=getPrivilegeByUId",{userId:userId},function(data){
               //查询出权限
               var allPrivilegeList=data.data;

               createMenuByData($("#leftmenu_0"),allPrivilegeList);
             })
            }
      //执行获取权限的方法
            getAllPrivilege();
            //渲染到页面里面
            function createMenuByData(target,allPrivilegeList){

              target.empty();

              var firstMenus=[];

              var secondMenus=[];

              $.each(allPrivilegeList,function(idx,item){
                //有父
                if(item.pid){
                  secondMenus.push(item);
                }else{
                  firstMenus.push(item);
                }
              })

              $.each(firstMenus,function(idx,item){

                var $dl=$("<dl id='"+item.id+"'><dt>"+item.name+"</dt></dl>");
                var $dd=$("<dd id='"+item.id+"'></dd>");
                var $ul=$('<ul id="'+item.id+'" class="clearfix"></ul>');
                $dd.append($ul);
                $dl.append($dd);
                $.each(secondMenus,function(idx1,item1){
                  if(item1.pid==item.id){
                    var $li=$('<li id="'+item1.id+'"><a href="https://www.ctyun.cn/portal/link.html?target=javascript%3Avoid%280%29%3B" 
      data-link="'+item1.url+'">'+item1.name+'</a></li>');
                    $ul.append($li);  
                  }
                })
                target.append($dl);

              })
            }

二.一.二.三 根据用户编号,查询该用户的权限

PrivilegeServiceImpl 实现类里面的 getPrivilegeByUId() 方法。

Servlet实现RBAC权限管理(二)

二.一.二.四 展示 按钮的权限

上面一部分,可以根据登录者的id 动态地展示 菜单权限,下面根据登录者的id 动态地展示页面上按钮的权限。

用 部门表 dept 进行举例。

  1. 设置标识,后面根据标识来控制按钮的显示与隐藏
<script>
      //获取权限 
      var privilegeList='<%=session.getAttribute("privilegeList")%>'; 
      //console.log("值是:"+privilegeList+","+typeof(privilegeList));
      var objPrivilegeList=JSON.parse(privilegeList);
      $.each(objPrivilegeList.data,function(idx,item){
        //将标识存放在 sessionStorage 里面,进行暂时的保存。 
        sessionStorage.setItem(item,true);
      })
</script>
<script type="text/javascript" src="/static/js/dept.js"></script>
  1. dept.js 里面,从sessionStorage 里面取出标识,进行显隐

Servlet实现RBAC权限管理(二)

二.一.三 退出登录按钮

二.一.三.一 前端页面实现

<div class="right">
        <span>
            <a href="https://www.ctyun.cn/portal/link.html?target=javascript%3Avoid%280%29%3B" onclick="window.location.href='https://www.ctyun.cn/portal/link.html?target=User%3Fmethod%3Dlogout'">退出</a>
        </span>
    </div>

二.一.三.二 退出后台实现

//退出登录
  public String logout(HttpServletRequest req,HttpServletResponse resp){

    HttpSession session=req.getSession();
    //注销
    session.invalidate();

    return "login";
  }

二.二 不同用户地验证测试

二.二.一 admin 管理员验证

输入网址: http://localhost:8080/Servlet_RBAC/User?jsp=toLogin

填入 用户名为 admin, 密码是 1234

Servlet实现RBAC权限管理(二)

点击登录:

Servlet实现RBAC权限管理(二)

菜单显示是正常的, 没有添加和修改的权限,按钮显示是正常的。

二.二.二 yuejl 经理验证

输入网址: http://localhost:8080/Servlet_RBAC/User?jsp=toLogin

填入 用户名为 yuejl, 密码是 1234

Servlet实现RBAC权限管理(二)

点击登录:

Servlet实现RBAC权限管理(二)

菜单显示是正常的, 没有部门的权限,所以部门那没有显示数据。

二.二.三 yuezl 普通职员验证

输入网址: http://localhost:8080/Servlet_RBAC/User?jsp=toLogin

填入 用户名为 yuezl, 密码是 1234

Servlet实现RBAC权限管理(二)

点击登录:

Servlet实现RBAC权限管理(二)

菜单显示是正常的

菜单的权限和按钮的权限,控制是正常的。

但这个时候,也是有问题的, 如果我们知道后端的访问地址,如用户 yuezl 没有部门的权限,但知道 部门查询的地址是:

http://localhost:8080/Servlet_RBAC/Dept?method=list

Servlet实现RBAC权限管理(二)

知道部门 添加的地址是: http://localhost:8080/Servlet_RBAC/Dept?method=add

Servlet实现RBAC权限管理(二)

Servlet实现RBAC权限管理(二)

这样是不安全的, 我们需要在每一次访问时,都需要对 url 路径进行一下判断。

需要用到登录和授权过滤器。

二.三 登录和授权过滤器 LoginInterceptor

package com.yjl.web.interceptor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.yjl.pojo.Privilege;
import com.yjl.pojo.User;
import com.yjl.service.PrivilegeService;
import com.yjl.service.impl.PrivilegeServiceImpl;

//过滤所有的请求
@WebFilter("/*")
public class LoginInterceptor implements Filter{

  //不需要登录验证的url
  private static List<String> noLoginValidateUrl;
  //不需要权限验证的url
  private static List<String> noPriValidateUrl;

  //跳转到的登录页面
  private static String LOGIN_URL;
  //没有权限的界面
  private static String NO_PRIVILEGE_URL;

  static{
    noLoginValidateUrl=new ArrayList<String>();

    //静态资源
    noLoginValidateUrl.add("/static/");
    //登录页面
    noLoginValidateUrl.add("/User?jsp=toLogin");
    //登录方法
    noLoginValidateUrl.add("/User?method=login");


    noPriValidateUrl=new ArrayList<String>();

    noPriValidateUrl.add("/Main?jsp=toMain");
    //查询权限


    noPriValidateUrl.add("/Privilege?method=getPrivilegeByUId");
    //退出
    noPriValidateUrl.add("/User?method=logout");

    LOGIN_URL="/WEB-INF/pages/login.jsp";

    NO_PRIVILEGE_URL="/WEB-INF/pages/noPrivilege.jsp";
  }

  @Override
  public void destroy() {
    // TODO 自动生成的方法存根

  }

  @Override
  public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
      throws IOException, ServletException {
    if(arg0 instanceof HttpServletRequest){
      //请求。
      HttpServletRequest req=(HttpServletRequest)arg0;

      //获取Session
      HttpSession session=req.getSession();

      //请求路径
      String uri=req.getRequestURI();
      //请求参数
      String reqParam=req.getQueryString();

      //真正的请求路径
      String realPath="";

      if(reqParam==null||"".equals(reqParam)){
        realPath=uri;
      }else{
        realPath=uri+"?"+reqParam;
      }

      System.out.println("地址是:"+realPath);

      //验证是否在 不需要验证登录的url里面
      if(isContain(realPath,1)){
        arg2.doFilter(arg0, arg1);
        return ;
      }
      //如果为空,表示没有登录
      if(session.getAttribute("loginUser")==null){
        req.getRequestDispatcher(LOGIN_URL).forward(req,(HttpServletResponse)arg1);
      }else{

        //不需要验证权限
        if(isContain(realPath,2)){
          arg2.doFilter(arg0, arg1);
          return ;
        }
        //如果不为空,表示登录了。
        PrivilegeService privilegeService=new PrivilegeServiceImpl();
        //重新获取全部权限 , 需要缓存, 这儿不用缓存。
        User user=(User)session.getAttribute("loginUser");
        List<Privilege> privilegeList=privilegeService.getPrivilegeByUId(user.getId(),null);
        boolean isHavePri=false;
        for(Privilege pri:privilegeList){
          if(pri.getUrl()!=null){
            if(realPath.contains(pri.getUrl())){
              isHavePri=true;
              break;
            }
          }
        }
        if(isHavePri){
          //放行
          arg2.doFilter(arg0, arg1);
        }else{
          req.getRequestDispatcher(NO_PRIVILEGE_URL).forward(req,(HttpServletResponse)arg1);
        }

      }

    }
  }

  private boolean isContain(String realPath,int type){  
    List<String> urls;
    if(type==1){
      urls=noLoginValidateUrl;
    }else{
      urls=noPriValidateUrl;
    }

    boolean flag=false;

    for(String url:urls){
      //包括,返回-1
      if(realPath.indexOf(url)!=-1){
        flag=true;
        break;
      }
    }
    return flag;

  }


  @Override
  public void init(FilterConfig arg0) throws ServletException {
    // TODO 自动生成的方法存根

  }
}

重启服务器,以 yuezl 的身份登录后,

查询部门的方法:

http://localhost:8080/Servlet_RBAC/Dept?method=list

Servlet实现RBAC权限管理(二)

以 admin 的身份登录后, 执行部门查询的方法

可以查询出数据

Servlet实现RBAC权限管理(二)

但执行部门添加的方法时

Servlet实现RBAC权限管理(二)

权限验证,实现成功,详细的代码设计可以看链接。

谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月15日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   2023年11月15日   49   0   0 servletJSp
  TEZNKK3IfmPf   2023年11月15日   35   0   0 servlet
  TEZNKK3IfmPf   2023年11月14日   35   0   0 servletjavajvm
TEZNKK3IfmPf