zoukankan      html  css  js  c++  java
  • 基于URL权限拦截的实现

    一、实现原理

    1.实现原理
      本示例采用SpringMVC的拦截器来实现一个基于URL的权限拦截。
    2.权限管理流程

    二、数据库搭建

    1.用户表(sys_user)
    (1)表结构

    (2)表字段说明
     id:主键
     usercode:登录用户名
     username:姓名
     passsword:密码
     salt:盐
     locked:是否锁定
    (3)表数据

    INSERT INTO `sys_user` VALUES ('lisi', 'lisi', '李四', '96e79218965eb72c92a549dd5a330112', 'uiwueylm', '0');
    INSERT INTO `sys_user` VALUES ('zhangsan', 'zhangsan', '张三', '96e79218965eb72c92a549dd5a330112', 'eteokues', '0');
    

    2.角色表(sys_role)
    (1)表结构

    (2)表字段说明
     id:主键
     name:角色名称
     avaliable:是否启用
    (3)表数据

    INSERT INTO `sys_role` VALUES ('ebc8a441-c6f9-11e4-b137-0adc305c3f28', '商品管理员', '1');
    INSERT INTO `sys_role` VALUES ('ebc9d647-c6f9-11e4-b137-0adc305c3f28', '用户管理员', '1');
    

    3.权限表(sys_premission)
    (1)表结构

    (2)表字段说明
     id:主键
     name:资源名称
     type:资源类型
     url:访问url地址
     percode:权限代码字符串
     parentid:父结点id
     parentids:父结点id列表串
     sortstring:排序号
     available:是否启用
    (3)表数据

    INSERT INTO `sys_permission` VALUES ('1', '权限', '', '', null, '0', '0/', '0', '1');
    INSERT INTO `sys_permission` VALUES ('11', '商品管理', 'menu', 'queryItems.action', null, '1', '0/1/', '1.', '1');
    INSERT INTO `sys_permission` VALUES ('12', '商品新增', 'permission', '/item/add.action', 'item:create', '11', '0/1/11/', '', '1');
    INSERT INTO `sys_permission` VALUES ('13', '商品修改', 'permission', '/updateitems.action', 'item:update', '11', '0/1/11/', '', '1');
    INSERT INTO `sys_permission` VALUES ('14', '商品删除', 'permission', '', 'item:delete', '11', '0/1/11/', '', '1');
    INSERT INTO `sys_permission` VALUES ('15', '商品查询', 'permission', '/queryItems.action', 'item:query', '11', '0/1/11/', null, '1');
    INSERT INTO `sys_permission` VALUES ('21', '用户管理', 'menu', '/user/query.action', 'user:query', '1', '0/1/', '2.', '1');
    INSERT INTO `sys_permission` VALUES ('22', '用户新增', 'permission', '', 'user:create', '21', '0/1/21/', '', '1');
    INSERT INTO `sys_permission` VALUES ('23', '用户修改', 'permission', '', 'user:update', '21', '0/1/21/', '', '1');
    INSERT INTO `sys_permission` VALUES ('24', '用户删除', 'permission', '', 'user:delete', '21', '0/1/21/', '', '1');
    

    4.用户角色表(sys_user_role)
    (1)表结构

    (2)表字段说明
     id:主键
     sys_user_id:用户id
     sys_role_id:角色id
    (3)表数据

    INSERT INTO `sys_user_role` VALUES ('ebc8a441-c6f9-11e4-b137-0adc305c3f28', 'zhangsan', 'ebc8a441-c6f9-11e4-b137-0adc305c');
    INSERT INTO `sys_user_role` VALUES ('ebc9d647-c6f9-11e4-b137-0adc305c3f28', 'lisi', 'ebc9d647-c6f9-11e4-b137-0adc305c');
    

    5.角色权限表(sys_role_premission)
    (1)表结构

    (2)表字段说明
     id:主键
     sys_permission_id:权限id
     sys_role_id:角色id
    (3)表数据

    INSERT INTO `sys_role_permission` VALUES ('ebc8a441-c6f9-11e4-b137-0adc305c3f21', 'ebc8a441-c6f9-11e4-b137-0adc305c', '12');
    INSERT INTO `sys_role_permission` VALUES ('ebc8a441-c6f9-11e4-b137-0adc305c3f22', 'ebc8a441-c6f9-11e4-b137-0adc305c', '11');
    INSERT INTO `sys_role_permission` VALUES ('ebc8a441-c6f9-11e4-b137-0adc305c3f24', 'ebc9d647-c6f9-11e4-b137-0adc305c', '21');
    INSERT INTO `sys_role_permission` VALUES ('ebc8a441-c6f9-11e4-b137-0adc305c3f25', 'ebc8a441-c6f9-11e4-b137-0adc305c', '15');
    INSERT INTO `sys_role_permission` VALUES ('ebc9d647-c6f9-11e4-b137-0adc305c3f23', 'ebc9d647-c6f9-11e4-b137-0adc305c', '22');
    INSERT INTO `sys_role_permission` VALUES ('ebc9d647-c6f9-11e4-b137-0adc305c3f26', 'ebc8a441-c6f9-11e4-b137-0adc305c', '13');
    

    6.商品表(items)
    (1)表结构

    (2)表字段说明
     id:主键
     name:商品名称
     price:商品价格
     detil:商品描述
     pic:商品图片url
     createtime:创建时间
    (3)表数据

    INSERT INTO `items` VALUES ('1', '台式机', '3000.0', '该电脑质量非常好!!!!', null, '2015-02-03 13:22:53');
    INSERT INTO `items` VALUES ('2', '笔记本', '6000.0', '笔记本性能好,质量好!!!!!', null, '2015-02-09 13:22:57');
    INSERT INTO `items` VALUES ('3', '背包', '200.0', '名牌背包,容量大质量好!!!!', null, '2015-02-06 13:23:02');
    

    三、程序实现

    (一)认证

    1.系统登录流程
      系统 登陆相当 于用户身份认证,用户成功,要在session中记录用户的身份信息.
      操作流程:
        1. 用户进行登陆页面
        2. 输入用户名和密码进行登陆
        3. 进行用户名和密码校验
        4. 如果校验通过,在session记录用户身份信息
    2.创建专门类用于记录用户身份信息

     public class ActiveUser {
        //用户id
        private String userid;
        //用户账号
        private String usercode;
        //用户名称
        private String username;
    	//getter and setter....
    }
    

    3.mybatis的mapper和mapper接口
    (1)ActiveUserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.jack.mapper.ActiveUserMapper">
    
        <select id="authenticat" parameterType="String" resultType="activeUser" >
           SELECT * FROM sys_user WHERE usercode = #{id}
        </select>
    </mapper>
    

    (2)ActiveUserMapper.java

    public interface ActiveUserMapper {
    
        public ActiveUser authenticat(String usercode) throws Exception;
    }
    

    4.service(进行用户名和密码校验)

    public interface UserService {
        //根据用户名和密码进行身份验证,如果通过,则返回身份信息
        public ActiveUser authenticat(String usercode, String password) throws Exception;
    }
    

    5.验证的实现类

     public ActiveUser authenticat(String usercode, String password) throws Exception {
    
            //查询该用户
           User user =  userMapper.authenticat(usercode);
    
           if(user == null){
                throw  new ItemsException("该账号不存在");
           }
           //得到用户的id
            String userid = user.getId();
           //获取该用户的密码
          String user_password =  user.getPassword();
          MD5 md5 = new MD5();
          String passwprd1 = md5.getMD5ofStr(password);
           //将密码和输入的密码进行比较
            if(!user_password.equals(passwprd1)){
                throw  new ItemsException("用户名或密码错误");
            }
            //认证通过,返回认证信息
            ActiveUser activeUser = new ActiveUser();
            activeUser.setUsercode(user.getUsercode());
            activeUser.setUsername(user.getUsername());
            activeUser.setUserid(user.getId());
            return activeUser;
        }
    

    6.controller

       /**
         * TODO:登录controller
         * @param session 系统session
         * @param randomcode 验证码
         * @param usercode 用户账号
         * @param password //用户密码
         * @return 重定向
         * @throws Exception
         */
        @RequestMapping("/login")
        public String login (HttpSession session,String randomcode,String usercode,String password)throws Exception{
            //从session中获取验证码信息
            String validateCode = (String) session.getAttribute("validateCode");
            //对比验证码信息
           /* if(!validateCode.equals(randomcode)){
                //验证码不一致,抛出异常
                throw  new ItemsException("验证码错误");
            }*/
            //检验账号密码是否正确
            ActiveUser activeUser = userService.authenticat(usercode,password);
            //将身份信息保存到session
            session.setAttribute("activeUser",activeUser);
            return "redirect:/first.action";
        }
    

    7.创建保存匿名访问地址的properties文件

    #可以匿名访问的url地址
    login.action = 登录 
    

    8.编写登录的拦截器LoginIntersector

    public class LoginIntersector implements HandlerInterceptor{
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
    
            //得到请求的URL
            String url = httpServletRequest.getRequestURI();
            //判断是否是公开地址
            //1.从配置文件中获取全部公开地址
           List<String> anonymousUrl =  ResourcesUtil.gekeyList("./config/anonymousURL");
           //对比URL
            for (String an_url: anonymousUrl) {
                if(url.indexOf(an_url) >= 0){
                    //如果是公开地址,放行
                    return true;
                }
            }
            //获取session
            HttpSession session = httpServletRequest.getSession();
           //获取身份信息
            ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
            //判断身份信息在session中是否存在
            if(activeUser != null){
                //存在放行
                return true;
            }
            //跳转到登录页面
            httpServletRequest.getRequestDispatcher("/page/login.jsp").forward(httpServletRequest,httpServletResponse);
            return false;
        }
    	 @Override
       	 public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    

    9.配置登录的拦截器

     <!--配置全局的拦截器-->
        <mvc:interceptors>
            <!--多个拦截器顺序执行-->
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.jack.intersector.LoginIntersector" />
            </mvc:interceptor>
        </mvc:interceptors>
    

    (二)、授权

    1.流程
    在用户认证时,认证通过,根据用户id从数据库获取用户权限范围的菜单,将菜单的集合存储在session中。
    2.修改用于记录用户身份信息的类

    public class ActiveUser {
    //用户id
    private String userid;
    //用户账号
    private String usercode;
    //用户名称
    private String username;
    //用户权限列表
    private List<SysPermission> menus;
    //用户菜单列表
    private List<SysPermission> permissions;
    

    3.mapper和mapper接口
    (1) SyspermissionMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.jack.mapper.SyspermissionMapper">
    
        <select id="findMenuListByUserId" parameterType="String" resultType="sysPermission">
                 SELECT
                        *
                    FROM
                        sys_permission
                    WHERE
                        type = 'menu'
                        AND
                        id IN (
                            SELECT
                                sys_permission_id
                            FROM
                                sys_role_permission
                            WHERE
                                sys_role_id IN (
                                    SELECT
                                        sys_role_id
                                    FROM
                                        sys_user_role
                                    WHERE
                                        sys_user_id =#{id}
                                )
                        )
        </select>
    
    
        <select id="findPermissionListByUserId" parameterType="String" resultType="sysPermission">
            SELECT
             *
               FROM
                 sys_permission
                 WHERE
                  type = 'permission'
                  AND
                 id IN (
                    SELECT
                        sys_permission_id
                         FROM
                            sys_role_permission
                            WHERE
            sys_role_id IN (
            SELECT
            sys_role_id
            FROM
            sys_user_role
            WHERE
            sys_user_id =#{id}
            )
            )
        </select>
    </mapper>
    

    (2)SyspermissionMapper.java

    public interface SyspermissionMapper {
    
        //获取用户的权限列表
        public List<SysPermission> findPermissionListByUserId(String userid) throws Exception;
        //获取用户的菜单列表
        public List<SysPermission> findMenuListByUserId(String userid) throws Exception;
    }
    

    (4)修改service接口实现类

      public ActiveUser authenticat(String usercode, String password) throws Exception {
    
            //查询该用户
           User user =  userMapper.authenticat(usercode);
    
           if(user == null){
                throw  new ItemsException("该账号不存在");
           }
           //等到用户的id
            String userid = user.getId();
           //得到用户的菜单列表
            List<SysPermission> menus = syspermissionMapper.findMenuListByUserId(userid);
           //得到用户的权限列表
            List<SysPermission> permissions = syspermissionMapper.findPermissionListByUserId(userid);
           //获取该用户的密码
          String user_password =  user.getPassword();
          MD5 md5 = new MD5();
          String passwprd1 = md5.getMD5ofStr(password);
           //将密码和输入的密码进行比较
            if(!user_password.equals(passwprd1)){
                throw  new ItemsException("用户名或密码错误");
            }
            //认证通过,返回认证信息
            ActiveUser activeUser = new ActiveUser();
            activeUser.setUsercode(user.getUsercode());
            activeUser.setUsername(user.getUsername());
            activeUser.setUserid(user.getId());
            activeUser.setMenus(menus);
            activeUser.setPermissions(permissions);
            return activeUser;
        }
    

    (5)页面菜单的动态显示

       <c:if test="${activeUser.menus!=null }">
                <ul>
                    <c:forEach items="${activeUser.menus }" var="menu">
                        <li><div>
                            <a title="${menu.name }" ref="1_1" href="#"
                               rel="${baseurl }${menu.url }" icon="icon-log"><span
                                    class="icon icon-log">&nbsp;</span><span class="nav"><a href=javascript:addTab('${menu.name }','${baseurl }${menu.url }')>${menu.name }</a></span></a>
                        </div></li>
                    </c:forEach>
                </ul>
            </c:if>
    

    (6)权限拦截器PermissionIntersector

    public class PermissionIntersector implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
    
            //得到用户的访问地址
           String url1 =  httpServletRequest.getRequestURI();
           String url = url1.substring(url1.lastIndexOf("/"));
           //判断是否是公开地址
           List<String> an_urls = ResourcesUtil.gekeyList("./config/anonymousURL");
            for (String an_url:an_urls) {
                if(url.indexOf(an_url) >=0){
                    return true;
                }
            }
            //判读是否是共用地址
            List<String> co_urls = ResourcesUtil.gekeyList("./config/commonURL");
            for (String co_url: co_urls) {
                if(url.indexOf(co_url) >= 0){
                    return true;
                }
            }
    
            //获取session
            HttpSession session = httpServletRequest.getSession();
            //获得权限列表
            ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
            //获取权限列表
            List<SysPermission> permissions = activeUser.getPermissions();
            for (SysPermission permission:permissions
                 ) {
                String p_url = permission.getUrl();
                if(url.indexOf(p_url) >= 0){
                    return true;
                }
            }
            httpServletRequest.getRequestDispatcher("page/refuse.jsp").forward(httpServletRequest,httpServletResponse);
           return false;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }  
    

    (7)配置权限拦截器

     <!--配置全局的拦截器-->
        <mvc:interceptors>
            <!--多个拦截器顺序执行-->
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.jack.intersector.LoginIntersector" />
            </mvc:interceptor>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.jack.intersector.PermissionIntersector" />
            </mvc:interceptor>
        </mvc:interceptors>
    

    四、总结

    使用基于url拦截的权限管理方式,实现起来比较简单,不依赖框架,使用web提供filter就可以实现。
    问题:
    需要将所有的url全部配置起来,有些繁琐,不易维护,url(资源)和权限表示方式不规范。

  • 相关阅读:
    【PASOTTIPASOTTI 伞】PASOTTI黑色聚酯纤维伞 Style 478
    乐雨 德国happyrain 超大男士高尔夫伞 直柄伞 双人伞 双层伞面防风雨伞 黑色【图片 价格 品牌 报价】-京东
    Larmes琅幕仕家居马头长款短柄自动雨伞 晴雨两用太阳伞防紫外线遮阳男士商务伞 雨伞雨具 骏马长款-金色配饰【图片 价格 品牌 报价】-京东
    Planner – 项目管理软件
    Project Server 2010安装部署手册(1.5版)
    Serena Software :: pod-update
    ]project-open[ 中国 功能一览
    几块钱或许能治好你的白发(2)
    爱心日式便当 给爸爸妈妈的爱心便当
    给老公做的爱心便当,持续更新!-西餐-19楼私房菜-杭州19楼
  • 原文地址:https://www.cnblogs.com/jack1995/p/7445972.html
Copyright © 2011-2022 走看看