瀏覽代碼

:sparkles: 添加新特性。数据权限,统一异常包装处理

冷冷 7 年之前
父節點
當前提交
fe9283ddc2

+ 46 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/datascope/DataScope.java

@@ -0,0 +1,46 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.datascope;
+
+import lombok.Data;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author lengleng
+ * @date 2018/8/30
+ * 数据权限查询参数
+ */
+@Data
+public class DataScope extends HashMap {
+	/**
+	 * 限制范围的字段名称
+	 */
+	private String scopeName = "deptId";
+
+	/**
+	 * 具体的数据范围
+	 */
+	private List<Integer> deptIds;
+
+	/**
+	 * 是否只查询本部门
+	 */
+	private Boolean isOnly = false;
+}

+ 124 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/datascope/DataScopeInterceptor.java

@@ -0,0 +1,124 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.datascope;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.plugins.SqlParserHandler;
+import com.baomidou.mybatisplus.toolkit.PluginUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
+
+import java.sql.Connection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * @author lengleng
+ * @date 2018/8/30
+ * <p>
+ * mybatis 数据权限拦截器
+ */
+@Slf4j
+@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
+public class DataScopeInterceptor extends SqlParserHandler implements Interceptor {
+
+	@Override
+	public Object intercept(Invocation invocation) throws Throwable {
+		StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
+		MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
+		this.sqlParser(metaObject);
+		// 先判断是不是SELECT操作
+		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
+		if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
+			return invocation.proceed();
+		}
+
+		BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
+		String originalSql = boundSql.getSql();
+		Object parameterObject = boundSql.getParameterObject();
+
+		//查找参数中包含DataScope类型的参数
+		DataScope dataScope = findDataScopeObject(parameterObject);
+
+		if (dataScope == null) {
+			return invocation.proceed();
+		} else {
+			String scopeName = dataScope.getScopeName();
+			List<Integer> deptIds = dataScope.getDeptIds();
+			if (StrUtil.isNotBlank(scopeName) && CollectionUtil.isNotEmpty(deptIds)) {
+				String join = CollectionUtil.join(deptIds, ",");
+				originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")";
+				metaObject.setValue("delegate.boundSql.sql", originalSql);
+			}
+			return invocation.proceed();
+		}
+	}
+
+	/**
+	 * 生成拦截对象的代理
+	 *
+	 * @param target 目标对象
+	 * @return 代理对象
+	 */
+	@Override
+	public Object plugin(Object target) {
+		if (target instanceof StatementHandler) {
+			return Plugin.wrap(target, this);
+		}
+		return target;
+	}
+
+	/**
+	 * mybatis配置的属性
+	 *
+	 * @param properties mybatis配置的属性
+	 */
+	@Override
+	public void setProperties(Properties properties) {
+
+	}
+
+	/**
+	 * 查找参数是否包括DataScope对象
+	 *
+	 * @param parameterObj 参数列表
+	 * @return DataScope
+	 */
+	private DataScope findDataScopeObject(Object parameterObj) {
+		if (parameterObj instanceof DataScope) {
+			return (DataScope) parameterObj;
+		} else if (parameterObj instanceof Map) {
+			for (Object val : ((Map<?, ?>) parameterObj).values()) {
+				if (val instanceof DataScope) {
+					return (DataScope) val;
+				}
+			}
+		}
+		return null;
+	}
+
+}

+ 49 - 0
pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/exception/GlobalExceptionHandler.java

@@ -0,0 +1,49 @@
+/*
+ *    Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package com.pig4cloud.pigx.common.core.exception;
+
+import com.pig4cloud.pigx.common.core.util.R;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * @author lengleng
+ * @date 2018/8/30
+ * 全局的的异常处理器
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+	/**
+	 * 全局异常.
+	 *
+	 * @param e the e
+	 * @return R
+	 */
+	@ExceptionHandler(Exception.class)
+	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+	@ResponseBody
+	public R exception(Exception e) {
+		log.info("全局异常信息 ex={}", e.getMessage(), e);
+		return new R<>(e);
+	}
+}

+ 1 - 0
pigx-common/pigx-common-core/src/main/resources/META-INF/spring.factories

@@ -2,4 +2,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
   com.pig4cloud.pigx.common.core.config.JacksonConfig,\
   com.pig4cloud.pigx.common.core.config.RedisConfig,\
   com.pig4cloud.pigx.common.core.config.RestTemplateConfig,\
+  com.pig4cloud.pigx.common.core.exception.GlobalExceptionHandler,\
   com.pig4cloud.pigx.common.core.util.SpringContextHolder

+ 1 - 1
pigx-common/pigx-common-log/src/main/java/com/pig4cloud/pigx/common/log/aspect/SysLogAspect.java

@@ -38,7 +38,7 @@ import org.aspectj.lang.annotation.Aspect;
 public class SysLogAspect {
 
 	@Around("@annotation(sysLog)")
-	public Object aroundWxApi(ProceedingJoinPoint point, SysLog sysLog) throws Throwable {
+	public Object around(ProceedingJoinPoint point, SysLog sysLog) throws Throwable {
 		String strClassName = point.getTarget().getClass().getName();
 		String strMethodName = point.getSignature().getName();
 		log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);

+ 2 - 2
pigx-config/src/main/resources/config/pigx-codegen-dev.yml

@@ -2,8 +2,8 @@
 security:
   oauth2:
     client:
-      client-id: ENC(xD1AY92cohwLfefsXett5Q==)
-      client-secret: ENC(xD1AY92cohwLfefsXett5Q==)
+      client-id: ENC(gPFcUOmJm8WqM3k3eSqS0Q==)
+      client-secret: ENC(gPFcUOmJm8WqM3k3eSqS0Q==)
       scope: server
 
 # 数据源配置

+ 2 - 2
pigx-config/src/main/resources/config/pigx-daemon-dev.yml

@@ -2,8 +2,8 @@
 security:
   oauth2:
     client:
-      client-id: ENC(Y91StLXT8tX5TwpcTSR2kg==)
-      client-secret: ENC(Y91StLXT8tX5TwpcTSR2kg==)
+      client-id: ENC(tz2NM4GcmnE7sNJTYL8ZSg==)
+      client-secret: ENC(tz2NM4GcmnE7sNJTYL8ZSg==)
       scope: server
 
 ## 定时任务

+ 2 - 2
pigx-config/src/main/resources/config/pigx-upms-dev.yml

@@ -2,8 +2,8 @@
 security:
   oauth2:
     client:
-      client-id: ENC(iVEZk4Gdt0UXDlX7ZN9J5g==)
-      client-secret: ENC(iVEZk4Gdt0UXDlX7ZN9J5g==)
+      client-id: ENC(ltJPpR50wT0oIY9kfOe1Iw==)
+      client-secret: ENC(ltJPpR50wT0oIY9kfOe1Iw==)
       scope: server
 
 # 数据源

+ 11 - 0
pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/config/MybatisPlusConfigurer.java

@@ -20,6 +20,7 @@
 package com.pig4cloud.pigx.admin.config;
 
 import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
+import com.pig4cloud.pigx.common.core.datascope.DataScopeInterceptor;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -40,4 +41,14 @@ public class MybatisPlusConfigurer {
 	public PaginationInterceptor paginationInterceptor() {
 		return new PaginationInterceptor();
 	}
+
+	/**
+	 * 数据权限插件
+	 *
+	 * @return DataScopeInterceptor
+	 */
+	@Bean
+	public DataScopeInterceptor dataScopeInterceptor() {
+		return new DataScopeInterceptor();
+	}
 }

+ 3 - 1
pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysUserMapper.java

@@ -22,6 +22,7 @@ package com.pig4cloud.pigx.admin.mapper;
 import com.baomidou.mybatisplus.mapper.BaseMapper;
 import com.pig4cloud.pigx.admin.api.entity.SysUser;
 import com.pig4cloud.pigx.admin.api.vo.UserVO;
+import com.pig4cloud.pigx.common.core.datascope.DataScope;
 import com.pig4cloud.pigx.common.core.util.Query;
 import org.apache.ibatis.annotations.Param;
 
@@ -49,9 +50,10 @@ public interface SysUserMapper extends BaseMapper<SysUser> {
 	 *
 	 * @param query    查询条件
 	 * @param username 用户名
+	 * @param dataScope
 	 * @return list
 	 */
-	List selectUserVoPage(Query query, @Param("username") Object username);
+	List selectUserVoPage(Query query, @Param("username") Object username, DataScope dataScope);
 
 	/**
 	 * 通过ID查询用户信息

+ 32 - 7
pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysUserServiceImpl.java

@@ -27,19 +27,19 @@ import com.baomidou.mybatisplus.plugins.Page;
 import com.baomidou.mybatisplus.service.impl.ServiceImpl;
 import com.pig4cloud.pigx.admin.api.dto.UserDTO;
 import com.pig4cloud.pigx.admin.api.dto.UserInfo;
+import com.pig4cloud.pigx.admin.api.entity.SysDeptRelation;
 import com.pig4cloud.pigx.admin.api.entity.SysRole;
 import com.pig4cloud.pigx.admin.api.entity.SysUser;
 import com.pig4cloud.pigx.admin.api.entity.SysUserRole;
 import com.pig4cloud.pigx.admin.api.vo.MenuVO;
 import com.pig4cloud.pigx.admin.api.vo.UserVO;
 import com.pig4cloud.pigx.admin.mapper.SysUserMapper;
-import com.pig4cloud.pigx.admin.service.SysMenuService;
-import com.pig4cloud.pigx.admin.service.SysRoleService;
-import com.pig4cloud.pigx.admin.service.SysUserRoleService;
-import com.pig4cloud.pigx.admin.service.SysUserService;
+import com.pig4cloud.pigx.admin.service.*;
 import com.pig4cloud.pigx.common.core.constant.enums.EnumLoginType;
+import com.pig4cloud.pigx.common.core.datascope.DataScope;
 import com.pig4cloud.pigx.common.core.util.Query;
 import com.pig4cloud.pigx.common.core.util.R;
+import com.pig4cloud.pigx.common.security.util.SecurityUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
@@ -69,6 +69,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 	private final SysUserMapper sysUserMapper;
 	private final SysRoleService sysRoleService;
 	private final SysUserRoleService sysUserRoleService;
+	private final SysDeptRelationService sysDeptRelationService;
 
 	/**
 	 * 通过用户名查用户的全部信息
@@ -121,8 +122,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 
 	@Override
 	public Page selectWithRolePage(Query query) {
+		DataScope dataScope = new DataScope();
+		dataScope.setScopeName("deptId");
+		dataScope.setIsOnly(true);
+		dataScope.setDeptIds(getChildDepts());
 		Object username = query.getCondition().get("username");
-		query.setRecords(sysUserMapper.selectUserVoPage(query, username));
+		query.setRecords(sysUserMapper.selectUserVoPage(query, username, dataScope));
 		return query;
 	}
 
@@ -151,13 +156,14 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 
 	/**
 	 * 根据用户名删除用户(真实删除)
+	 *
 	 * @param username
 	 * @return
 	 */
 	@Override
-	public Boolean deleteSysUserByUsernameAndUserId(String username,Integer userId) {
+	public Boolean deleteSysUserByUsernameAndUserId(String username, Integer userId) {
 
-		sysUserMapper.deleteSysUserByUsernameAndUserId(username,userId);
+		sysUserMapper.deleteSysUserByUsernameAndUserId(username, userId);
 		SysUserRole condition = new SysUserRole();
 		condition.setUserId(userId);
 		sysUserRoleService.delete(new EntityWrapper<>(condition));
@@ -218,4 +224,23 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 		return Boolean.TRUE;
 	}
 
+	/**
+	 * 获取当前用户的子部门信息
+	 *
+	 * @return 子部门列表
+	 */
+	private List<Integer> getChildDepts() {
+		Integer deptId = SecurityUtils.getUser().getDeptId();
+
+		//获取当前部门的子部门
+		SysDeptRelation deptRelation = new SysDeptRelation();
+		deptRelation.setAncestor(deptId);
+		List<SysDeptRelation> deptRelationList = sysDeptRelationService.selectList(new EntityWrapper<>(deptRelation));
+		List<Integer> deptIds = new ArrayList<>();
+		for (SysDeptRelation sysDeptRelation : deptRelationList) {
+			deptIds.add(sysDeptRelation.getDescendant());
+		}
+		return deptIds;
+	}
+
 }