Package com.ketayao.ketacustom.spring

Source Code of com.ketayao.ketacustom.spring.DataControlInterceptor

/**
*
*/
package com.ketayao.ketacustom.spring;

import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.support.RequestContextUtils;

import com.ketayao.ketacustom.SecurityConstants;
import com.ketayao.ketacustom.entity.main.DataControl;
import com.ketayao.ketacustom.entity.main.Module;
import com.ketayao.ketacustom.entity.main.User;
import com.ketayao.ketacustom.spring.DataControlXML.Condition;
import com.ketayao.ketacustom.util.persistence.DynamicSpecifications;
import com.ketayao.ketacustom.util.persistence.SearchFilter;
import com.ketayao.ketacustom.util.persistence.SearchFilter.Operator;
import com.ketayao.utils.Exceptions;
import com.ketayao.utils.SecurityUtils;

import freemarker.template.SimpleHash;

/**
* @author KETAYAO
*
*/
public class DataControlInterceptor extends HandlerInterceptorAdapter {
  private final static Logger logger = LoggerFactory.getLogger(DataControlInterceptor.class);
 
  protected static final String PART_DIVIDER_TOKEN = ":";
  protected static final String PERMISSION_DIVIDER_TOKEN = ",";
  protected static final String HOLDER_DIVIDER_TOKEN = "#";
 
  protected static final String SHOW_METHOD_PREFIX = "list";
  protected static final String MANY_METHOD_SUFFIX = "Many";
 
  protected static final String SINGLE_KEY = "id";
  protected static final String MANY_KEY = "ids";
 
  @PersistenceContext
  private EntityManager em;
 
  private static Unmarshaller unmarshaller;
 
  static {
    try {
      unmarshaller = JAXBContext.newInstance(DataControlXML.class).createUnmarshaller();
    } catch (JAXBException e) {
      logger.error("DataControlXML JAXB初始化错误:" + Exceptions.getStackTraceAsString(e));
    }
  }
 
  private static FreeMarkerParse freeMarkerParse = new FreeMarkerParse();
 
  /**
   * @param request
   * @param response
   * @param handler
   * @return
   * @throws Exception
   * @see org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet.http.HttpServletRequest,
   *      javax.servlet.http.HttpServletResponse, java.lang.Object)
   */
  @Override
  public boolean preHandle(HttpServletRequest request,
      HttpServletResponse response, Object handler) throws Exception {
    DynamicSpecifications.putRequest(request);
    if (!(handler instanceof HandlerMethod)) {
      return true;
    }
   
    final HandlerMethod handlerMethod = (HandlerMethod)handler;
    Method method = handlerMethod.getMethod();
   
    final RequiresPermissions rps = method.getAnnotation(RequiresPermissions.class);
    if (rps == null) {
      return true;
    }
    Logical logical = rps.logical();
    String[] pv = rps.value();
   
    // 假如验证逻辑为OR,并且有些权限不需要做数据权限检查的,直接返回true。
    if (logical.equals(Logical.OR)) {
      for (String p : pv) {
        if (p.split(PART_DIVIDER_TOKEN).length < 3) {
          return true;
        }
      }
    }

    boolean firstPermitted = false;
    for (String p : pv) {
      String[] v = p.split(PART_DIVIDER_TOKEN);
     
      if (v.length == 3) {
        // 进行初次验证,确保shiro中用户的权限被初始化。
        if (!firstPermitted) {
          Subject subject = SecurityUtils.getSubject();
          if (!subject.isPermitted(p)){
            throw new UnauthorizedException("数据权限验证失败!");
          }
          firstPermitted = true;
        }
     
        try {
          // 把内部动态查询参数常量,logical放入request
          request.setAttribute(SecurityConstants.NEST_DYNAMIC_SEARCH_LOGICAL, logical);
          boolean checkResult = (check(request, response, method, v[0], v[2]) == true) ? true : false;
          if (!checkResult) {
            throw new UnauthorizedException("数据权限验证失败!");
          }
         
          if (checkResult == true && logical.equals(Logical.OR)) {
            return true;
          }
        } catch (Exception e) {
          logger.error(Exceptions.getStackTraceAsString(e));
          throw new UnauthorizedException("数据权限验证失败!");
        }
      }
    }
   
    return true;
  }
 
  /* (non-Javadoc)
   * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
   */
  @Override
  public void afterCompletion(HttpServletRequest request,
      HttpServletResponse response, Object handler, Exception ex)
      throws Exception {
    DynamicSpecifications.removeRequest();
  }
 
  public boolean check(HttpServletRequest request, HttpServletResponse response, Method method,
      String moduleString, String dataControlString) {
    String[] m = moduleString.split(PERMISSION_DIVIDER_TOKEN);
    for (String sn : m) {
      String[] d = dataControlString.split(PERMISSION_DIVIDER_TOKEN);
      for (String name : d) {
       
        DataControl dataControl = SecurityUtils.getShiroUser().getHasDataControls().get(name);
        if (dataControl == null) {
          continue;
        }
       
        // EQ_user.id=#userId, EQ_user.id_OR=2, id=#id
        String control = dataControl.getControl();
        Map<String, Object> controlMap = new HashMap<String, Object>();
        try {
          DataControlXML xml = (DataControlXML)unmarshaller.unmarshal(new StringReader(control));
          for (Condition c : xml.getItems()) {
            controlMap.put(c.getName(), c.getContent());
          }
        } catch (Exception e) {
          throw new IllegalArgumentException("数据权限条件格式错误:" + control, e);
        }
       
        Set<Entry<String, Object>> set = controlMap.entrySet();
        for (Entry<String, Object> entry : set) {
          String value = (String)entry.getValue();
          try {
            entry.setValue(parseValue(request, response, control));
          } catch (Exception e) {
            throw new IllegalArgumentException("数据权限参数解析错误:" + value, e);
          }
        }
       
        Map<String, SearchFilter> searchFilters = SearchFilter.parse(controlMap);
        Set<SearchFilter> filterSet = new HashSet<SearchFilter>(searchFilters.values());
        try {
          Module module = SecurityUtils.getShiroUser().getHasModules().get(sn);
         
          boolean handleResult = true;
          if (method.getName().startsWith(SHOW_METHOD_PREFIX)) {
            handleResult = (handleList(request, filterSet, method, dataControl, module) == true) ? true : false;
          } else {
            handleResult = (handleOther(request, filterSet, method, dataControl, module) == true) ? true : false;
          }
         
          if (!handleResult) {
            return false;
          }
        } catch (Exception e) {
          throw new IllegalArgumentException("数据权限方法处理错误:" + method.getName(), e);
        }
      }

    }
   
    return true;
  }
 
  /**
   * 处理分页显示的方法
   */
  @SuppressWarnings("unchecked")
  protected boolean handleList(HttpServletRequest request, Set<SearchFilter> filterSet,
      Method method, DataControl dataControl, Module module) {
    Logical logical = (Logical)request.getAttribute(SecurityConstants.NEST_DYNAMIC_SEARCH_LOGICAL);
    if (logical.equals(Logical.AND)) {
      Set<SearchFilter> pre = (Set<SearchFilter>)request.getAttribute(SecurityConstants.NEST_DYNAMIC_SEARCH);
      if (pre == null) {
        pre = new HashSet<SearchFilter>();
        request.setAttribute(SecurityConstants.NEST_DYNAMIC_SEARCH, pre);
      }
       
      pre.addAll(filterSet);
    } else {
      request.setAttribute(SecurityConstants.NEST_DYNAMIC_SEARCH, filterSet);
    }
   
    return true;
  }
 
  /**
   * 处理其他方法
   * @throws Exception
   * @throws 
   * @throws InstantiationException
   */
  @SuppressWarnings({ "rawtypes", "unchecked" })
  protected boolean handleOther(HttpServletRequest request, Set<SearchFilter> filterSet,
      Method method, DataControl dataControl, Module module) throws Exception {
   
    String[] ids = null;
    if (method.getName().endsWith(MANY_METHOD_SUFFIX)) { // 多对象操作方法
      ids = request.getParameterValues(MANY_KEY);
      if (ids != null) {
        filterSet.add(new SearchFilter("id", Operator.IN, ids));
      }
    } else {
      String id = request.getParameter("id");
      if (id != null) {
        filterSet.add(new SearchFilter("id", Operator.EQ, id));
      } else {
        // 截取类似/update/{id}的id
        String uri = request.getRequestURI();
        String tmp = StringUtils.substringAfterLast(uri, "/");
        Long longId = NumberUtils.toLong(tmp);
        if (longId != 0L) {
          filterSet.add(new SearchFilter("id", Operator.EQ, longId));
        }
      }
    }
   
    Object clazz = Class.forName(module.getClassName()).newInstance();
    //Object clazz = null;
    Specification spec = DynamicSpecifications.bySearchFilter(request, clazz.getClass(), filterSet);
   
    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery criteriaQuery = builder.createQuery(clazz.getClass());
    Root root = criteriaQuery.from(clazz.getClass());
   
    Predicate predicate = spec.toPredicate(root, criteriaQuery, builder);
    criteriaQuery.where(predicate);
   
    List<Object> objects = em.createQuery(criteriaQuery).getResultList();
    if (ids != null) {
      if (objects.size() == ids.length) {
        return true;
      }
    } else {
      if (objects.size() > 0) {
        return true;
      }
    }
   
    return false;
  }
 
  protected String parseValue(HttpServletRequest request, String value) throws Exception {
    if (value.startsWith(HOLDER_DIVIDER_TOKEN)) {
      value = value.substring(1);
     
      // 替换登录用户的属性值
      if (value.startsWith("user.")) {
        value = value.substring(5);
       
        User user = SecurityUtils.getLoginUser();
        return PropertyUtils.getProperty(user, value).toString();
      }
     
      return request.getParameter(value);
    }
   
    return value;
  }
 
  protected String parseValue(HttpServletRequest request, HttpServletResponse response,
      String control) {
    Map<String, Object> model = new HashMap<String, Object>();
    model.put("user", SecurityUtils.getLoginUser());
    model.putAll(SecurityUtils.getShiroUser().getAttributes());
   
    WebApplicationContext context = RequestContextUtils.getWebApplicationContext(request);
    SimpleHash simpleHash = freeMarkerParse.buildTemplateModel(model, context.getServletContext(), request, response);
   
    return freeMarkerParse.renderString(control, simpleHash);
  }
}
TOP

Related Classes of com.ketayao.ketacustom.spring.DataControlInterceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.