¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.framework.handler; |
| | | |
| | | import cn.hutool.core.annotation.AnnotationUtil; |
| | | import cn.hutool.core.collection.ConcurrentHashSet; |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.core.util.ClassUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.ruoyi.common.annotation.DataColumn; |
| | | import com.ruoyi.common.annotation.DataPermission; |
| | | import com.ruoyi.common.core.domain.entity.SysRole; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.common.core.service.UserService; |
| | | import com.ruoyi.common.enums.DataScopeType; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.helper.DataPermissionHelper; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.spring.SpringUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import net.sf.jsqlparser.JSQLParserException; |
| | | import net.sf.jsqlparser.expression.Expression; |
| | | import net.sf.jsqlparser.expression.Parenthesis; |
| | | import net.sf.jsqlparser.expression.operators.conditional.AndExpression; |
| | | import net.sf.jsqlparser.parser.CCJSqlParserUtil; |
| | | import org.springframework.context.expression.BeanFactoryResolver; |
| | | import org.springframework.expression.BeanResolver; |
| | | import org.springframework.expression.ExpressionParser; |
| | | import org.springframework.expression.ParserContext; |
| | | import org.springframework.expression.common.TemplateParserContext; |
| | | import org.springframework.expression.spel.standard.SpelExpressionParser; |
| | | import org.springframework.expression.spel.support.StandardEvaluationContext; |
| | | |
| | | import java.lang.reflect.Method; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * æ°æ®æéè¿æ»¤ |
| | | * |
| | | * @author Lion Li |
| | | * @version 3.5.0 |
| | | */ |
| | | @Slf4j |
| | | public class PlusDataPermissionHandler { |
| | | |
| | | /** |
| | | * æ¹æ³æç±»(åç§°) ä¸ æ³¨è§£çæ å°å
³ç³»ç¼å |
| | | */ |
| | | private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * æ ææ³¨è§£æ¹æ³ç¼åç¨äºå¿«éè¿å |
| | | */ |
| | | private final Set<String> inavlidCacheSet = new ConcurrentHashSet<>(); |
| | | |
| | | /** |
| | | * spel è§£æå¨ |
| | | */ |
| | | private final ExpressionParser parser = new SpelExpressionParser(); |
| | | private final ParserContext parserContext = new TemplateParserContext(); |
| | | /** |
| | | * beanè§£æå¨ ç¨äºå¤ç spel 表达å¼ä¸å¯¹ bean çè°ç¨ |
| | | */ |
| | | private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); |
| | | |
| | | |
| | | public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { |
| | | DataColumn[] dataColumns = findAnnotation(mappedStatementId); |
| | | if (ArrayUtil.isEmpty(dataColumns)) { |
| | | inavlidCacheSet.add(mappedStatementId); |
| | | return where; |
| | | } |
| | | SysUser currentUser = DataPermissionHelper.getVariable("user"); |
| | | if (ObjectUtil.isNull(currentUser)) { |
| | | currentUser = SpringUtils.getBean(UserService.class).selectUserById(SecurityUtils.getUserId()); |
| | | DataPermissionHelper.setVariable("user", currentUser); |
| | | } |
| | | // 妿æ¯è¶
级管çåï¼åä¸è¿æ»¤æ°æ® |
| | | if (ObjectUtil.isNull(currentUser) || currentUser.isAdmin()) { |
| | | return where; |
| | | } |
| | | String dataFilterSql = buildDataFilter(dataColumns, isSelect); |
| | | if (StringUtils.isBlank(dataFilterSql)) { |
| | | return where; |
| | | } |
| | | try { |
| | | Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); |
| | | // æ°æ®æé使ç¨åç¬çæ¬å· 鲿¢ä¸å
¶ä»æ¡ä»¶å²çª |
| | | Parenthesis parenthesis = new Parenthesis(expression); |
| | | if (ObjectUtil.isNotNull(where)) { |
| | | return new AndExpression(where, parenthesis); |
| | | } else { |
| | | return parenthesis; |
| | | } |
| | | } catch (JSQLParserException e) { |
| | | throw new ServiceException("æ°æ®æéè§£æå¼å¸¸ => " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æé æ°æ®è¿æ»¤sql |
| | | */ |
| | | private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) { |
| | | StringBuilder sqlString = new StringBuilder(); |
| | | // æ´æ°æå é¤éæ»¡è¶³æææ¡ä»¶ |
| | | String joinStr = isSelect ? " OR " : " AND "; |
| | | SysUser user = DataPermissionHelper.getVariable("user"); |
| | | StandardEvaluationContext context = new StandardEvaluationContext(); |
| | | context.setBeanResolver(beanResolver); |
| | | DataPermissionHelper.getContext().forEach(context::setVariable); |
| | | for (SysRole role : user.getRoles()) { |
| | | user.setRoleId(role.getRoleId()); |
| | | // è·åè§è²æéæ³å |
| | | DataScopeType type = DataScopeType.findCode(role.getDataScope()); |
| | | if (ObjectUtil.isNull(type)) { |
| | | throw new ServiceException("è§è²æ°æ®èå´å¼å¸¸ => " + role.getDataScope()); |
| | | } |
| | | // å
¨é¨æ°æ®æéç´æ¥è¿å |
| | | if (type == DataScopeType.ALL) { |
| | | return ""; |
| | | } |
| | | boolean isSuccess = false; |
| | | for (DataColumn dataColumn : dataColumns) { |
| | | // ä¸å
å« key åé åä¸å¤ç |
| | | if (!StringUtils.contains(type.getSqlTemplate(), "#" + dataColumn.key())) { |
| | | continue; |
| | | } |
| | | // 设置注解åé key 为表达å¼åé value 为åéå¼ |
| | | context.setVariable(dataColumn.key(), dataColumn.value()); |
| | | |
| | | // è§£æsql模æ¿å¹¶å¡«å
|
| | | String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class); |
| | | sqlString.append(joinStr).append(sql); |
| | | isSuccess = true; |
| | | } |
| | | // æªå¤çæååå¡«å
å
åºæ¹æ¡ |
| | | if (!isSuccess) { |
| | | sqlString.append(joinStr).append(type.getElseSql()); |
| | | } |
| | | } |
| | | |
| | | if (StringUtils.isNotBlank(sqlString.toString())) { |
| | | return sqlString.substring(joinStr.length()); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private DataColumn[] findAnnotation(String mappedStatementId) { |
| | | StringBuilder sb = new StringBuilder(mappedStatementId); |
| | | int index = sb.lastIndexOf("."); |
| | | String clazzName = sb.substring(0, index); |
| | | String methodName = sb.substring(index + 1, sb.length()); |
| | | Class<?> clazz = ClassUtil.loadClass(clazzName); |
| | | List<Method> methods = Arrays.stream(ClassUtil.getDeclaredMethods(clazz)) |
| | | .filter(method -> method.getName().equals(methodName)).collect(Collectors.toList()); |
| | | DataPermission dataPermission; |
| | | // è·åæ¹æ³æ³¨è§£ |
| | | for (Method method : methods) { |
| | | dataPermission = dataPermissionCacheMap.get(method.getName()); |
| | | if (ObjectUtil.isNotNull(dataPermission)) { |
| | | return dataPermission.value(); |
| | | } |
| | | if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) { |
| | | dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class); |
| | | dataPermissionCacheMap.put(method.getName(), dataPermission); |
| | | return dataPermission.value(); |
| | | } |
| | | } |
| | | dataPermission = dataPermissionCacheMap.get(clazz.getName()); |
| | | if (ObjectUtil.isNotNull(dataPermission)) { |
| | | return dataPermission.value(); |
| | | } |
| | | // è·å类注解 |
| | | if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { |
| | | dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); |
| | | dataPermissionCacheMap.put(clazz.getName(), dataPermission); |
| | | return dataPermission.value(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * æ¯å¦ä¸ºæ ææ¹æ³ æ æ°æ®æé |
| | | */ |
| | | public boolean isInvalid(String mappedStatementId) { |
| | | return inavlidCacheSet.contains(mappedStatementId); |
| | | } |
| | | } |