shiro基于url拦截-用户授权

2018年02月22日 14:13 | 4713次浏览

一、前言

照例回顾前面一章,注意内容。首先我们登录输入用户名密码-----进入我们的拦截器----匿名地址----存用户到session。这个就是我们rel用户认证的流程,其中关键是查询数据库和拦截器存入session。这样一来我们的用户认证就这么简单是不是,有种豁然开朗的感觉。既然用户认证了,我们肯定是要做点用户授权。

二、基于url拦截-用户授权

首先我们看一下我们授权实现的流程。绿色为我们的用户授权流程

看图说话:我们需要查询用户权利表--------是否是公开页面----------是否有权限------------------有权放行,无权提示

我们还是有dao-service-controller的顺序编写代码

2.1 mapper编写

SysPermissionMapper

package com.ycy.mapper;

import com.ycy.model.SysPermission;
import java.util.List;

/**
 *
 * <p>Title: SysPermissionMapperCustom</p>
 * <p>Description: 权限mapper</p>
 * Created by Administrator on 2015/10/14 0014.
 */
public interface SysPermissionMapper {

    //根据用户id查询菜单
    public List<SysPermission> findMenuListByUserId(String userid)throws Exception;
    //根据用户id查询权限url
    public List<SysPermission> findPermissionListByUserId(String userid)throws Exception;

}

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.ycy.mapper.SysPermissionMapper" >
    <resultMap id="BaseResultMap" type="com.ycy.model.SysPermission" >
      <id column="id" property="id" jdbcType="BIGINT" />
      <result column="name" property="name" jdbcType="VARCHAR" />
      <result column="type" property="type" jdbcType="VARCHAR" />
      <result column="url" property="url" jdbcType="VARCHAR" />
      <result column="percode" property="percode" jdbcType="VARCHAR" />
      <result column="parentid" property="parentid" jdbcType="BIGINT" />
      <result column="parentids" property="parentids" jdbcType="VARCHAR" />
      <result column="sortstring" property="sortstring" jdbcType="VARCHAR" />
      <result column="available" property="available" jdbcType="CHAR" />
    </resultMap>
    <!--基础属性-->
    <sql id="Base_Column_List" >
      id, name, type, url, percode, parentid, parentids, sortstring, available
    </sql>
    <!-- 根据用户id查询url -->
    <select id="findPermissionListByUserId" parameterType="string" resultMap="BaseResultMap">
      SELECT
      <include refid="Base_Column_List" />
      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>
  
    <!-- 根据用户id查询菜单 -->
    <select id="findMenuListByUserId"  parameterType="string" resultMap="BaseResultMap">
      SELECT
      <include refid="Base_Column_List" />
      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>
  
  </mapper>

2.2 service编写

SysService

package com.ycy.service;

import com.ycy.model.ActiveUser;
import com.ycy.model.SysPermission;

import java.util.List;


/**
 *
 * <p>Title: SysService</p>
 * <p>Description: 认证授权服务接口</p>
 */
public interface SysService {

	//根据用户的身份和密码 进行认证,如果认证通过,返回用户身份信息
	public ActiveUser authenticat(String userCode, String password) throws Exception;
}

SysServiceImpl

package com.ycy.service.impl;

import java.util.List;

import com.ycy.Exception.CustomException;
import com.ycy.mapper.SysPermissionMapper;
import com.ycy.mapper.SysUserMapper;
import com.ycy.model.ActiveUser;
import com.ycy.model.SysPermission;
import com.ycy.model.SysUser;
import com.ycy.service.SysService;
import com.ycy.util.MD5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


/**
 * 
 * <p>Title: SysServiceImpl</p>
 * <p>Description:认证和授权的服务接口 </p>
 */
@Service
public class SysServiceImpl implements SysService {
	
	@Autowired
	private SysUserMapper sysUserMapper;
	@Autowired
	private SysPermissionMapper sysPermissionMapper;
	@Override
	public ActiveUser authenticat(String userCode, String password)
			throws Exception {
		/**
	认证过程:
	根据用户身份(账号)查询数据库,如果查询不到用户不存在
	对输入的密码 和数据库密码 进行比对,如果一致,认证通过
		 */
		//根据用户账号查询数据库
		SysUser sysUser = this.findSysUserByUserCode(userCode);
		
		if(sysUser == null){
			//抛出异常
			throw new CustomException("用户账号不存在");
		}
		
		//数据库密码 (md5密码 )
		String password_db = sysUser.getPassword();
		
		//对输入的密码 和数据库密码 进行比对,如果一致,认证通过
		//对页面输入的密码 进行md5加密 
		String password_input_md5 = new MD5().getMD5ofStr(password);
		if(!password_input_md5.equalsIgnoreCase(password_db)){
			//抛出异常
			throw new CustomException("用户名或密码 错误");
		}
		//得到用户id
		String userid = sysUser.getId();

		//根据用户id查询菜单
		List<SysPermission> menus =this.findMenuListByUserId(userid);
		//根据用户id查询权限url
		List<SysPermission> permissions = this.findPermissionListByUserId(userid);


		//认证通过,返回用户身份信息
		ActiveUser activeUser = new ActiveUser();
		activeUser.setUserid(sysUser.getId());
		activeUser.setUsercode(userCode);
		activeUser.setUsername(sysUser.getUsername());//用户名称
		//放入权限范围的菜单和url
		activeUser.setMenus(menus);
		activeUser.setPermissions(permissions);
		return activeUser;
	}

	//根据用户账号查询用户信息
	private SysUser findSysUserByUserCode(String userCode)throws Exception{
		List<SysUser> list = sysUserMapper.getSysUserByUserCode(userCode);
		if(list!=null && list.size()==1){
			return list.get(0);
		}
		return null;
	}
	//根据用户id查询权限范围的菜单
	private List<SysPermission> findMenuListByUserId(String userid)
			throws Exception {

		return sysPermissionMapper.findMenuListByUserId(userid);
	}
	//根据用户id查询权限范围的url
	private List<SysPermission> findPermissionListByUserId(String userid)
			throws Exception {

		return sysPermissionMapper.findPermissionListByUserId(userid);
	}

}

2.3 权限拦截器

1、SysPermissionInterceptor

package com.ycy.interceptor;

/**
 * Created by Administrator on 2015/10/10 0010.
 */

import com.ycy.model.ActiveUser;
import com.ycy.model.SysPermission;
import com.ycy.util.ResourcesUtil;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;

/**
 * 授权拦截器
 */
public class SysPermissionInterceptor implements HandlerInterceptor{

    //在执行handler之前来执行的
    //用于用户认证校验、用户权限校验
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        //得到请求的url
        String url = request.getRequestURI();
        //从配置中取逆名访问url
        /*************************************************匿名地址**********************************************/
        List<String> open_urls = ResourcesUtil.gekeyList("config/anonymousURL");
        //遍历公开 地址,如果是公开 地址则放行
        for(String open_url:open_urls){
            if(url.indexOf(open_url)>=0){
                //如果是公开 地址则放行
                return true;
            }
        }
        /*************************************************公用地址***********************************************/
        //从配置文件中获取公共访问地址
        List<String> common_urls = ResourcesUtil.gekeyList("config/commonURL");
        //遍历公用 地址,如果是公用 地址则放行
        for(String common_url:common_urls){
            if(url.indexOf(common_url)>=0){
                //如果是公开 地址则放行
                return true;
            }
        }
        /*************************************************获取session***********************************************/
        //获取session
        HttpSession session = request.getSession();
        ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
        //从session中取权限范围的url

        List<SysPermission> permissions = activeUser.getPermissions();
        for(SysPermission sysPermission:permissions){
            //权限的url
            String permission_url = sysPermission.getUrl();
            System.out.println(url);
            System.out.println(permission_url);
            if(url.endsWith(".css")||url.endsWith(".js")||url.endsWith(".jsp")){
                return true;
            }else{
                if(url.indexOf(permission_url)>=0){
                    //如果是权限的url 地址则放行
                    return true;
                }
            }

        }
        //执行到这里拦截,跳转到登陆页面,用户进行身份认证
        request.getRequestDispatcher("/pages/jsp/refuse.jsp").forward(request, response);
        //如果返回false表示拦截不继续执行handler,如果返回true表示放行
        return false;
    }
    //在执行handler返回modelAndView之前来执行
    //如果需要向页面提供一些公用 的数据或配置一些视图信息,使用此方法实现 从modelAndView入手
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1...postHandle");

    }
    //执行handler之后执行此方法
    //作系统 统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间点的差就是执行时长
    //实现 系统 统一日志记录
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("HandlerInterceptor1...afterCompletion");
    }
}

2、加入springmvc.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-4.0.xsd ">
   <!--========================================静态资源==============================================-->
    <mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
    <mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
    <mvc:resources mapping="/styles/**" location="/styles/"></mvc:resources>
    <!--========================================拦截器==============================================-->
    <!--拦截器 多个拦截器,顺序执行 -->
    <mvc:interceptors>
        <!--用户认证权限拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.ycy.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
        <!--用户授权权限拦截器-->
       <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.ycy.interceptor.SysPermissionInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    <!-- 使用spring组件扫描 -->
    <context:component-scan base-package="com.ycy"/>
    <!-- 注解驱动 -->
    <mvc:annotation-driven conversion-service="conversionService">
    </mvc:annotation-driven>
    <!--定义统一异常处理-->
    <bean id="CustomExceptionResolver" class="com.ycy.Exception.CustomExceptionResolver"/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/pages/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--转换器 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 转换器 -->
        <property name="converters">
            <list>
                <bean class="com.ycy.controller.converter.CustomDateConverter"/>
            </list>
        </property>
    </bean>
    <!-- 文件上传 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置上传文件的最大尺寸为5MB -->
        <property name="maxUploadSize">
            <value>5242880</value>
        </property>
    </bean>
</beans>

3、配置commonURL公共地址

commonURL.properties

#配置公用的访问地址
first=系统首页
logout=退出

三、权限认证测试

四、url权限系统总结

4.1 用户认证:

用户登录----保存session,认证拦截器判断通过则OK(读匿名地址)

4.2 权限认证:

用户登录----保存session,权限拦截器判断通过则OK(读匿名地址、读公共地址)


4.3 总结

1、两个拦截器顺序是闲用户认证,再权限认证,不要放错顺序。

2、ur一定要配置在数据库里面,否则无法实现,这个是比较麻烦的,包括每一个按钮。

3、页面按钮显示问题,需要用jstl标签每个按钮判断(如果不是跳转到没有权限页面,而且直接不现实按钮)。


一般企业或者一般用户不是特别多管理系统,用着这套URL权限管理系统足矣。所以如果你是做erp管理系统,什么监控平台,什么oa的系统,什么档案管理系统。都是足够的。我们找个系统更多的是讲解权限设计原理,技术点就只有一个,就是拦截器。基于url的权限系统就这么搞定了。其实想想也是那么简单,是不是。

接下来开始讲解shrio你就明白了,都是这个思想



小说《我是全球混乱的源头》

感觉本站内容不错,读后有收获?小额赞助,鼓励网站分享出更好的教程