Browse Source

1.将数据权限和操作权限分开,允许仅使用操作权限而不开启数据权限

2.将操作权限判断放入common-tools
master
wxz 5 years ago
parent
commit
654bb25e31
  1. 114
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/aspect/DataFilterAspect.java
  2. 106
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/aspect/DataFilterAspectBak.java
  3. 14
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/MybatisGovAccessFeignClient.java
  4. 7
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/MybatisGovOrgFeignClient.java
  5. 9
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/fallback/MybatisGovAccessFeignClientFallback.java
  6. 5
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/fallback/MybatisGovOrgFeignClientFallback.java
  7. 3
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/interceptor/DataFilterInterceptor.java
  8. 100
      epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/interceptor/DataFilterInterceptorBak.java
  9. 45
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/aspect/AccessOpeAspect.java
  10. 132
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/aspect/RequirePermissionAspect.java
  11. 14
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/aspect/ThreadLocalInitAspect.java
  12. 24
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/constant/ThreadLocalConstant.java
  13. 59
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/LoginUserInfoFormDTO.java
  14. 7
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/LoginUserInfoResultDTO.java
  15. 33
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/RoleOpeScopeResultDTO.java
  16. 2
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java
  17. 5
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/RenExceptionHandler.java
  18. 37
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/feign/CommonGovAccessFeignClient.java
  19. 33
      epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/feign/fallback/CommonGovAccessFeignClientFallback.java
  20. 5
      epmet-module/gov-access/gov-access-client/src/main/java/com/epmet/dto/result/LoginUserInfoResultDTO.java
  21. 1
      epmet-module/gov-access/gov-access-server/src/main/java/com/epmet/controller/AccessController.java

114
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/aspect/DataFilterAspect.java

@ -9,15 +9,14 @@
package com.epmet.commons.mybatis.aspect;
import com.epmet.commons.mybatis.annotation.DataFilter;
import com.epmet.commons.mybatis.feign.MybatisGovAccessFeignClient;
import com.epmet.commons.tools.constant.AccessSettingConstant;
import com.epmet.commons.tools.constant.OpeScopeConstant;
import com.epmet.commons.mybatis.dto.form.*;
import com.epmet.commons.mybatis.feign.GovAccessFeignClient;
import com.epmet.commons.mybatis.feign.GovOrgFeignClient;
import com.epmet.commons.tools.aspect.AccessOpeAspect;
import com.epmet.commons.tools.constant.ThreadLocalConstant;
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO;
import com.epmet.commons.tools.exception.EpmetErrorCode;
import com.epmet.commons.tools.exception.RenException;
import com.epmet.commons.tools.security.user.LoginUserUtil;
import com.epmet.commons.tools.utils.Result;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
@ -32,7 +31,6 @@ import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* 数据过滤切面处理类
@ -51,30 +49,19 @@ public class DataFilterAspect {
*/
private static final ThreadLocal<Boolean> hasConditions = new ThreadLocal();
/**
* 用于向DataFilterInterceptor传递权限过滤的sql片段(需要在Controller相关的AOP中进行清理防止变量残留)
*/
public static final ThreadLocal<String> sqlFilter = new ThreadLocal();
//public static final ThreadLocal<String> gridIdTL = new ThreadLocal();
//public static final ThreadLocal<String> deptIdTL = new ThreadLocal();
@Autowired
private LoginUserUtil loginUserUtil;
@Autowired
private GovAccessFeignClient govAccessFeignClient;
@Autowired
private GovOrgFeignClient govOrgFeignClient;
public static final String orgIdPathSpliter = ":";
private MybatisGovAccessFeignClient govAccessFeignClient;
@Before("@annotation(com.epmet.commons.mybatis.annotation.DataFilter)")
public void dataFilter(JoinPoint point) {
//清空
//sqlFilter.remove();
// 从ThreadLocal中取所需权限
String requirePermission = ThreadLocalConstant.requirePermissionTl.get();
// 没有配置所需权限,不做操作,打印提示日志
if (StringUtils.isBlank(requirePermission)) {
log.warn("接口缺少所需权限配置,请在Controller方法上使用@RequirePermission注解完成所需权限配置");
return;
}
// 取到注解属性
MethodSignature methodSignature = (MethodSignature) point.getSignature();
@ -101,48 +88,22 @@ public class DataFilterAspect {
}
}
// 从ThreadLocal中取所需权限
String requirePermission = AccessOpeAspect.requirePermissionTl.get();
// 没有配置所需权限,不做操作,打印提示日志
if (StringUtils.isBlank(requirePermission)) {
log.warn("接口缺少所需权限配置,请在Controller方法上使用@RequirePermission注解完成所需权限配置");
return;
}
String app = loginUserUtil.getLoginUserApp();
String client = loginUserUtil.getLoginUserClient();
String userId = loginUserUtil.getLoginUserId();
StaffPermCacheFormDTO staffPermissionFormDTO = new StaffPermCacheFormDTO();
staffPermissionFormDTO.setApp(app);
staffPermissionFormDTO.setClient(client);
staffPermissionFormDTO.setStaffId(userId);
Result<LoginUserInfoResultDTO> result = govAccessFeignClient.getLoginUserInfo(staffPermissionFormDTO);
if (result.getCode() != 0) {
// 查询不到权限,记录日志,抛出8000异常
log.error("调用Access查询权限失败:{}", result.getMsg());
throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode());
}
LoginUserInfoResultDTO userDetail = result.getData();
if (userDetail == null) {
log.error("操作权限不足,查询不到登录用户信息");
throw new RenException(EpmetErrorCode.REQUIRE_PERMISSION.getCode());
}
Set<String> currPermissions = getPermissions(userDetail.getRoleIdList());
// 校验操作权限
validateOpePermission(currPermissions, requirePermission);
LoginUserInfoResultDTO loginUserInfo = ThreadLocalConstant.loginUserInfoTl.get();
hasConditions.set(false);
// 生成过滤sql
String sqlFilterSegment = getSqlFilterSegment(userId, userDetail.getRoleIdList(), requirePermission,
userDetail.getOrgIdPath(), userDetail.getGridIdList(), tableAlias, userDetail.getDeptIdList(),
gridId, deptId, requirePermission);
String sqlFilterSegment = getSqlFilterSegment(
loginUserInfo.getUserId(),
loginUserInfo.getRoleIdList(),
requirePermission,
loginUserInfo.getOrgIdPath(),
loginUserInfo.getGridIdList(),
tableAlias,
loginUserInfo.getDeptIdList(),
gridId,
deptId,
requirePermission);
// 方式1.填充到Service方法列表中的DataScope对象中。如果dao入参是用DTO的话,那么再加一个DataScope入参,sql中会报错提示#{}参数找不到,因此改用方法2
//Object[] methodArgs = point.getArgs();
@ -155,34 +116,7 @@ public class DataFilterAspect {
// 方式2,采用ThreadLocal传参到DataFilterInterceptor中
if (StringUtils.isNotBlank(sqlFilterSegment)) {
sqlFilter.set(sqlFilterSegment);
}
}
private Set<String> getPermissions(Set<String> roleIdList) {
Set<String> permissions = new HashSet<>();
roleIdList.forEach(role -> {
// 找出该角色的所有功能操作列表
Result<List<RoleOpeScopeResultDTO>> result = govAccessFeignClient.listRoleAllOperationScopesByRoleId(role);
if (!result.success()) {
// 获取operation异常
log.error("调用GovAccess,根据RoleId查询Operation列表失败:{}", result.getMsg());
throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode());
}
List<RoleOpeScopeResultDTO> roleOperations = result.getData();
permissions.addAll(roleOperations.stream().map(ope -> ope.getOperationKey()).collect(Collectors.toSet()));
});
return permissions;
}
/**
* 校验操作权限
*/
private void validateOpePermission(Set<String> permissions, String reqiurePermission) {
if (!permissions.contains(reqiurePermission)) {
// 权限不足
log.error("操作权限不足");
throw new RenException(EpmetErrorCode.REQUIRE_PERMISSION.getCode());
ThreadLocalConstant.sqlFilter.set(sqlFilterSegment);
}
}

106
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/aspect/DataFilterAspectBak.java

@ -1,106 +0,0 @@
///**
// * Copyright (c) 2018 人人开源 All rights reserved.
// *
// * https://www.renren.io
// *
// * 版权所有,侵权必究!
// */
//
//package com.epmet.commons.mybatis.aspect;
//
//import cn.hutool.core.collection.CollUtil;
//import com.epmet.commons.mybatis.annotation.DataFilter;
//import com.epmet.commons.mybatis.entity.DataScope;
//import com.epmet.commons.tools.constant.Constant;
//import com.epmet.commons.tools.enums.SuperAdminEnum;
//import com.epmet.commons.tools.exception.ErrorCode;
//import com.epmet.commons.tools.exception.RenException;
//import com.epmet.commons.tools.security.user.SecurityUser;
//import com.epmet.commons.tools.security.user.UserDetail;
//import org.apache.commons.lang3.StringUtils;
//import org.aspectj.lang.JoinPoint;
//import org.aspectj.lang.annotation.Aspect;
//import org.aspectj.lang.annotation.Before;
//import org.aspectj.lang.annotation.Pointcut;
//import org.aspectj.lang.reflect.MethodSignature;
//import org.springframework.stereotype.Component;
//
//import java.util.Arrays;
//import java.util.List;
//import java.util.Map;
//
///**
// * 数据过滤,切面处理类
// *
// * @author Mark sunlightcs@gmail.com
// * @since 1.0.0
// */
//@Aspect
//@Component
//public class DataFilterAspectBak {
// @Pointcut("@annotation(com.epmet.commons.mybatis.annotation.DataFilter)")
// public void dataFilterCut() {
//
// }
//
// @Before("dataFilterCut()")
// public void dataFilter(JoinPoint point) {
// Object params = point.getArgs()[0];
// if(params != null && params instanceof Map){
// UserDetail user = SecurityUser.getUser();
//
// //如果不是超级管理员,则进行数据过滤
// if(user.getSuperAdmin() == SuperAdminEnum.NO.value()){
// Map map = (Map)params;
// String sqlFilter = getSqlFilter(user, point);
// map.put(Constant.SQL_FILTER, new DataScope(sqlFilter));
// }
//
// return ;
// }
//
// throw new RenException(ErrorCode.DATA_SCOPE_PARAMS_ERROR);
// }
//
// /**
// * 获取数据过滤的SQL
// */
// private String getSqlFilter(UserDetail user, JoinPoint point){
// MethodSignature signature = (MethodSignature) point.getSignature();
// DataFilter dataFilter = signature.getMethod().getAnnotation(DataFilter.class);
// //获取表的别名
// String tableAlias = dataFilter.tableAlias();
// if(StringUtils.isNotBlank(tableAlias)){
// tableAlias += ".";
// }
//
// StringBuilder sqlFilter = new StringBuilder();
//
// //查询条件前缀
// String prefix = dataFilter.prefix();
// if(StringUtils.isNotBlank(prefix)){
// sqlFilter.append(" ").append(prefix);
// }
//
// sqlFilter.append(" (");
//
// //部门ID列表
// List<Long> deptIdList = user.getDeptIdList();
// if(CollUtil.isNotEmpty(deptIdList)){
// sqlFilter.append(tableAlias).append(dataFilter.deptId());
//
// sqlFilter.append(" in(").append(StringUtils.join(deptIdList, ",")).append(")");
// }
//
// //查询本人数据
// if (dataFilter.isPendingCreator()) {
// if(CollUtil.isNotEmpty(deptIdList)){
// sqlFilter.append(" or ");
// }
// sqlFilter.append(tableAlias).append(dataFilter.userId()).append("=").append(user.getId());
// }
// sqlFilter.append(")");
//
// return sqlFilter.toString();
// }
//}

14
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/GovAccessFeignClient.java → epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/MybatisGovAccessFeignClient.java

@ -1,13 +1,12 @@
package com.epmet.commons.mybatis.feign;
import com.epmet.commons.mybatis.dto.form.*;
import com.epmet.commons.mybatis.feign.fallback.GovAccessFeignClientFallback;
import com.epmet.commons.mybatis.feign.fallback.MybatisGovAccessFeignClientFallback;
import com.epmet.commons.tools.constant.ServiceConstant;
import com.epmet.commons.tools.utils.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.Map;
@ -18,15 +17,8 @@ import java.util.Set;
* @Author sun
*/
//, url = "localhost:8099"
@FeignClient(name = ServiceConstant.GOV_ACCESS_SERVER, fallback = GovAccessFeignClientFallback.class)
public interface GovAccessFeignClient {
/**
* 查询用户当前权限列表
* @return
*/
@PostMapping("/gov/access/access/loginuserinfo")
Result<LoginUserInfoResultDTO> getLoginUserInfo(@RequestBody StaffPermCacheFormDTO dto);
@FeignClient(name = ServiceConstant.GOV_ACCESS_SERVER, fallback = MybatisGovAccessFeignClientFallback.class)
public interface MybatisGovAccessFeignClient {
/**
* 查询角色的操作key对应操作范围列表

7
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/GovOrgFeignClient.java → epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/MybatisGovOrgFeignClient.java

@ -1,8 +1,7 @@
package com.epmet.commons.mybatis.feign;
import com.epmet.commons.mybatis.dto.form.*;
import com.epmet.commons.mybatis.feign.fallback.GovAccessFeignClientFallback;
import com.epmet.commons.mybatis.feign.fallback.GovOrgFeignClientFallback;
import com.epmet.commons.mybatis.feign.fallback.MybatisGovOrgFeignClientFallback;
import com.epmet.commons.tools.constant.ServiceConstant;
import com.epmet.commons.tools.utils.Result;
import org.springframework.cloud.openfeign.FeignClient;
@ -17,8 +16,8 @@ import java.util.Set;
* @Author sun
*/
//, url = "localhost:8092"
@FeignClient(name = ServiceConstant.GOV_ORG_SERVER, fallback = GovOrgFeignClientFallback.class)
public interface GovOrgFeignClient {
@FeignClient(name = ServiceConstant.GOV_ORG_SERVER, fallback = MybatisGovOrgFeignClientFallback.class)
public interface MybatisGovOrgFeignClient {
/**
* 查询人员部门列表

9
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/fallback/GovAccessFeignClientFallback.java → epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/fallback/MybatisGovAccessFeignClientFallback.java

@ -1,7 +1,7 @@
package com.epmet.commons.mybatis.feign.fallback;
import com.epmet.commons.mybatis.dto.form.*;
import com.epmet.commons.mybatis.feign.GovAccessFeignClient;
import com.epmet.commons.mybatis.feign.MybatisGovAccessFeignClient;
import com.epmet.commons.tools.constant.ServiceConstant;
import com.epmet.commons.tools.utils.ModuleUtils;
import com.epmet.commons.tools.utils.Result;
@ -19,12 +19,7 @@ import java.util.Set;
* @Date 2020/4/24 11:17
**/
@Component
public class GovAccessFeignClientFallback implements GovAccessFeignClient {
@Override
public Result<LoginUserInfoResultDTO> getLoginUserInfo(StaffPermCacheFormDTO dto) {
return ModuleUtils.feignConError(ServiceConstant.GOV_ACCESS_SERVER, "getLoginUserInfo", dto);
}
public class MybatisGovAccessFeignClientFallback implements MybatisGovAccessFeignClient {
@Override
public Result<Set<OperationScopeDTO>> getOperationScopesByRoleId(OperationScopeFormDTO operationScopeFormDTO) {

5
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/fallback/GovOrgFeignClientFallback.java → epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/feign/fallback/MybatisGovOrgFeignClientFallback.java

@ -1,8 +1,7 @@
package com.epmet.commons.mybatis.feign.fallback;
import com.epmet.commons.mybatis.dto.form.*;
import com.epmet.commons.mybatis.feign.GovAccessFeignClient;
import com.epmet.commons.mybatis.feign.GovOrgFeignClient;
import com.epmet.commons.mybatis.feign.MybatisGovOrgFeignClient;
import com.epmet.commons.tools.constant.ServiceConstant;
import com.epmet.commons.tools.utils.ModuleUtils;
import com.epmet.commons.tools.utils.Result;
@ -18,7 +17,7 @@ import java.util.Set;
* @Date 2020/4/24 11:17
**/
@Component
public class GovOrgFeignClientFallback implements GovOrgFeignClient {
public class MybatisGovOrgFeignClientFallback implements MybatisGovOrgFeignClient {
@Override
public Result<List<DepartmentListResultDTO>> getDepartmentListByStaffId(String staffId) {

3
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/interceptor/DataFilterInterceptor.java

@ -11,6 +11,7 @@ package com.epmet.commons.mybatis.interceptor;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import com.epmet.commons.mybatis.aspect.DataFilterAspect;
import com.epmet.commons.tools.constant.ThreadLocalConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
@ -78,7 +79,7 @@ public class DataFilterInterceptor extends AbstractSqlParserHandler implements I
*/
// 方式2.从ThreadLocal中取sqlFilter
String sqlFilter = DataFilterAspect.sqlFilter.get();
String sqlFilter = ThreadLocalConstant.sqlFilter.get();
if (StringUtils.isBlank(sqlFilter)) {
return invocation.proceed();

100
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/interceptor/DataFilterInterceptorBak.java

@ -1,100 +0,0 @@
///**
// * Copyright (c) 2018 人人开源 All rights reserved.
// * <p>
// * https://www.renren.io
// * <p>
// * 版权所有,侵权必究!
// */
//
//package com.epmet.commons.mybatis.interceptor;
//
//import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
//import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
//import com.epmet.commons.mybatis.entity.DataScope;
//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.Map;
//import java.util.Properties;
//
///**
// * 数据过滤
// *
// * @author Mark sunlightcs@gmail.com
// * @since 1.0.0
// */
//@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
//public class DataFilterInterceptorBak extends AbstractSqlParserHandler implements Interceptor {
//
// @Override
// public Object intercept(Invocation invocation) throws Throwable {
// StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
// MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
//
// // SQL解析
// this.sqlParser(metaObject);
//
// // 先判断是不是SELECT操作
// MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
// if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
// return invocation.proceed();
// }
//
// // 针对定义了rowBounds,做为mapper接口方法的参数
// BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
// String originalSql = boundSql.getSql();
// Object paramObj = boundSql.getParameterObject();
//
// // 判断参数里是否有DataScope对象
// DataScope scope = null;
// if (paramObj instanceof DataScope) {
// scope = (DataScope) paramObj;
// } else if (paramObj instanceof Map) {
// for (Object arg : ((Map) paramObj).values()) {
// if (arg instanceof DataScope) {
// scope = (DataScope) arg;
// break;
// }
// }
// }
//
// // 不用数据过滤
// if (scope == null) {
// return invocation.proceed();
// }
//
// // 拼接新SQL
// String orderBy = "ORDER BY";
// String groupBy = "GROUP BY";
// if (originalSql.indexOf(groupBy) > -1) {
// originalSql = originalSql.replace(groupBy, scope.getSqlFilter() + groupBy);
// } else if (originalSql.indexOf(orderBy) > -1) {
// originalSql = originalSql.replace(orderBy, scope.getSqlFilter() + orderBy);
// } else {
// originalSql = originalSql + scope.getSqlFilter();
// }
//
// // 重写SQL
// metaObject.setValue("delegate.boundSql.sql", originalSql);
// return invocation.proceed();
// }
//
// @Override
// public Object plugin(Object target) {
// if (target instanceof StatementHandler) {
// return Plugin.wrap(target, this);
// }
// return target;
// }
//
// @Override
// public void setProperties(Properties properties) {
//
// }
//}

45
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/aspect/AccessOpeAspect.java

@ -1,45 +0,0 @@
/**
* Copyright (c) 2018 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有侵权必究
*/
package com.epmet.commons.tools.aspect;
import com.epmet.commons.tools.annotation.RequirePermission;
import com.epmet.commons.tools.enums.RequirePermissionEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
/**
* 每次请求过滤Api中配置的权限key出来
* @Author wxz
* @Description
* @Date 2020/4/23 16:16
**/
@Aspect
@Component
public class AccessOpeAspect {
/**
* 存储所需操作权限的 ThreadLocal
*/
public static final ThreadLocal<String> requirePermissionTl = new ThreadLocal<>();
@Before("@annotation(com.epmet.commons.tools.annotation.RequirePermission)")
public void before(JoinPoint point) throws Throwable {
// 取RequirePermission注解
MethodSignature methodSignature = (MethodSignature) point.getSignature();
RequirePermission requirePermissionAnno = methodSignature.getMethod().getAnnotation(RequirePermission.class);
RequirePermissionEnum requirePermissionEnum = requirePermissionAnno.requirePermission();
String key = requirePermissionEnum.getKey();
// 放入ThreadLocal,供DataFilterAspect中使用
requirePermissionTl.set(key);
}
}

132
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/aspect/RequirePermissionAspect.java

@ -0,0 +1,132 @@
/**
* Copyright (c) 2018 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有侵权必究
*/
package com.epmet.commons.tools.aspect;
import com.epmet.commons.tools.annotation.RequirePermission;
import com.epmet.commons.tools.constant.ThreadLocalConstant;
import com.epmet.commons.tools.dto.form.LoginUserInfoFormDTO;
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO;
import com.epmet.commons.tools.dto.form.RoleOpeScopeResultDTO;
import com.epmet.commons.tools.enums.RequirePermissionEnum;
import com.epmet.commons.tools.exception.EpmetErrorCode;
import com.epmet.commons.tools.exception.RenException;
import com.epmet.commons.tools.feign.CommonGovAccessFeignClient;
import com.epmet.commons.tools.security.user.LoginUserUtil;
import com.epmet.commons.tools.utils.Result;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 每次请求过滤Api中配置的权限key出来并且判断是否具有该功能权限
* @Author wxz
* @Description
* @Date 2020/4/23 16:16
**/
@Aspect
@Component
@Order(10)
public class RequirePermissionAspect {
private static final Logger log = LoggerFactory.getLogger(RequirePermissionAspect.class);
@Autowired
private CommonGovAccessFeignClient govAccessFeignClient;
@Autowired
private LoginUserUtil loginUserUtil;
@Before("@annotation(com.epmet.commons.tools.annotation.RequirePermission)")
public void before(JoinPoint point) throws Throwable {
// 取RequirePermission注解
MethodSignature methodSignature = (MethodSignature) point.getSignature();
RequirePermission requirePermissionAnno = methodSignature.getMethod().getAnnotation(RequirePermission.class);
RequirePermissionEnum requirePermissionEnum = requirePermissionAnno.requirePermission();
if (requirePermissionEnum == null) {
return;
}
String requirePermission = requirePermissionEnum.getKey();
LoginUserInfoResultDTO loginUserInfo = getLoginUserInfo();
Set<String> ownPermissions = getPermissions(loginUserInfo.getRoleIdList());
// 校验操作权限
validateOpePermission(ownPermissions, requirePermission);
// 操作权限校验通过。将该操作key放入ThreadLocal,供DataFilterAspect中数据权限过滤器进一步使用
ThreadLocalConstant.requirePermissionTl.set(requirePermission);
ThreadLocalConstant.loginUserInfoTl.set(loginUserInfo);
}
/**
* 获取登陆用户信息
* @return
*/
private LoginUserInfoResultDTO getLoginUserInfo() {
LoginUserInfoFormDTO loginUserinfoFormDTO = new LoginUserInfoFormDTO();
loginUserinfoFormDTO.setApp(loginUserUtil.getLoginUserApp());
loginUserinfoFormDTO.setClient(loginUserUtil.getLoginUserClient());
loginUserinfoFormDTO.setStaffId(loginUserUtil.getLoginUserId());
Result<LoginUserInfoResultDTO> result = govAccessFeignClient.getLoginUserInfo(loginUserinfoFormDTO);
if (result.getCode() != 0) {
// 查询不到权限,记录日志,抛出8000异常
log.error("调用Access查询权限失败:{}", result.getMsg());
throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode());
}
LoginUserInfoResultDTO loginUserInfo = result.getData();
if (loginUserInfo == null) {
log.error("操作权限不足,查询不到登录用户信息");
throw new RenException(EpmetErrorCode.REQUIRE_PERMISSION.getCode());
}
return loginUserInfo;
}
/**
* 校验操作权限
*/
private void validateOpePermission(Set<String> permissions, String reqiurePermission) {
if (!permissions.contains(reqiurePermission)) {
// 权限不足
log.error("操作权限不足");
throw new RenException(EpmetErrorCode.REQUIRE_PERMISSION.getCode());
}
}
private Set<String> getPermissions(Set<String> roleIdList) {
Set<String> permissions = new HashSet<>();
roleIdList.forEach(role -> {
// 找出该角色的所有功能操作列表
Result<List<RoleOpeScopeResultDTO>> result = govAccessFeignClient.listRoleAllOperationScopesByRoleId(role);
if (!result.success()) {
// 获取operation异常
log.error("调用GovAccess,根据RoleId查询Operation列表失败:{}", result.getMsg());
throw new RenException(EpmetErrorCode.SERVER_ERROR.getCode());
}
List<RoleOpeScopeResultDTO> roleOperations = result.getData();
permissions.addAll(roleOperations.stream().map(ope -> ope.getOperationKey()).collect(Collectors.toSet()));
});
return permissions;
}
}

14
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/aspect/ThreadLocalPreCleanAspect.java → epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/aspect/ThreadLocalInitAspect.java

@ -6,14 +6,17 @@
* 版权所有侵权必究
*/
package com.epmet.commons.mybatis.aspect;
package com.epmet.commons.tools.aspect;
import com.epmet.commons.tools.constant.ThreadLocalConstant;
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO;
import com.epmet.commons.tools.exception.ExceptionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
@ -24,15 +27,18 @@ import org.springframework.stereotype.Component;
**/
@Aspect
@Component
public class ThreadLocalPreCleanAspect {
@Order(0)
public class ThreadLocalInitAspect {
private static final Logger log = LoggerFactory.getLogger(ThreadLocalPreCleanAspect.class);
private static final Logger log = LoggerFactory.getLogger(ThreadLocalInitAspect.class);
@Before(value = "execution(* com.epmet.controller.*Controller*.*(..)) ")
public void before(JoinPoint point) throws Throwable {
// 清理权限过滤中的变量残留
try {
DataFilterAspect.sqlFilter.remove();
ThreadLocalConstant.sqlFilter.remove();
ThreadLocalConstant.requirePermissionTl.remove();
ThreadLocalConstant.loginUserInfoTl.remove();
} catch (Exception e) {
log.error("清理sqlFilter缓存失败:{}", ExceptionUtils.getErrorStackTrace(e));
}

24
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/constant/ThreadLocalConstant.java

@ -0,0 +1,24 @@
package com.epmet.commons.tools.constant;
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO;
/**
* ThreadLocal常亮
*/
public class ThreadLocalConstant {
/**
* 存储所需操作权限的 ThreadLocal
*/
public static final ThreadLocal<String> requirePermissionTl = new ThreadLocal<>();
/**
* 登陆用户信息的 ThreadLocal
*/
public static final ThreadLocal<LoginUserInfoResultDTO> loginUserInfoTl = new ThreadLocal<>();
/**
* 用于向DataFilterInterceptor传递权限过滤的sql片段(需要在Controller相关的AOP中进行清理防止变量残留)
*/
public static final ThreadLocal<String> sqlFilter = new ThreadLocal();
}

59
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/LoginUserInfoFormDTO.java

@ -0,0 +1,59 @@
package com.epmet.commons.tools.dto.form;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.Set;
@Data
public class LoginUserInfoFormDTO {
/**
* 更新权限缓存分组
*/
public interface UpdatePermissionCache {}
/**
* 查询当前权限列表
*/
public interface GetStaffCurrPermissions {}
/**
* 工作人员 id
*/
@NotBlank(message = "工作人员ID不能为空", groups = {UpdatePermissionCache.class, GetStaffCurrPermissions.class})
private String staffId;
/**
* 登录头信息app
*/
@NotBlank(message = "登录头信息app不能为空", groups = {UpdatePermissionCache.class, GetStaffCurrPermissions.class})
private String app;
/**
* 登录头信息client
*/
@NotBlank(message = "登录头信息client不能为空", groups = {UpdatePermissionCache.class, GetStaffCurrPermissions.class})
private String client;
/**
* 组织ID路径
*/
private String orgIdPath;
/**
* 权限列表
*/
private Set<String> permissions;
/**
* 角色列表
*/
private Set<String> roleIdList;
/**
* 当前所在网格id
*/
private String gridId;
}

7
epmet-commons/epmet-commons-mybatis/src/main/java/com/epmet/commons/mybatis/dto/form/LoginUserInfoResultDTO.java → epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/LoginUserInfoResultDTO.java

@ -1,4 +1,4 @@
package com.epmet.commons.mybatis.dto.form;
package com.epmet.commons.tools.dto.form;
import lombok.Data;
@ -7,6 +7,11 @@ import java.util.Set;
@Data
public class LoginUserInfoResultDTO {
/**
* 用户ID
*/
private String userId;
/**
* 权限列表
*/

33
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/dto/form/RoleOpeScopeResultDTO.java

@ -0,0 +1,33 @@
package com.epmet.commons.tools.dto.form;
import lombok.Data;
@Data
public class RoleOpeScopeResultDTO {
/**
* 角色ID
*/
private String roleId;
/**
* 操作key
*/
private String operationKey;
/**
* 范围key
*/
private String scopeKey;
/**
* 范围名称
*/
private String scopeName;
/**
* 范围序号
*/
private String scopeIndex;
}

2
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/EpmetErrorCode.java

@ -34,7 +34,7 @@ public enum EpmetErrorCode {
NOT_DEL_AGENCY_PER(8205, "该机关存在工作人员,不允许删除"),
NOT_DEL_DEPARTMENT(8206, "该部门存在工作人员,不允许删除"),
REQUIRE_PERMISSION(8301, "没有足够的操作权限"),
REQUIRE_PERMISSION(8301, "没有足够的操作权限"),
NOT_ADD_GRID(8401,"您当前的网格名称已存在,请重新修改"),
MOBILE_USED(8402,"该手机号已注册"),

5
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/exception/RenExceptionHandler.java

@ -55,6 +55,11 @@ public class RenExceptionHandler {
@ExceptionHandler(RenException.class)
public Result handleRRException(RenException ex){
logger.error(ExceptionUtils.getErrorStackTrace(ex));
if (ex.getCode() > 8000) {
Result result=new Result().error(ex.getCode());
result.setData(ex.getMsg());
return result;
}
Result result=new Result().error();
result.setData(ex.getMsg());
return result;

37
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/feign/CommonGovAccessFeignClient.java

@ -0,0 +1,37 @@
package com.epmet.commons.tools.feign;
import com.epmet.commons.tools.constant.ServiceConstant;
import com.epmet.commons.tools.dto.form.LoginUserInfoFormDTO;
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO;
import com.epmet.commons.tools.dto.form.RoleOpeScopeResultDTO;
import com.epmet.commons.tools.feign.fallback.CommonGovAccessFeignClientFallback;
import com.epmet.commons.tools.utils.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* @Description
* @Author sun
*/
//, url = "localhost:8099"
@FeignClient(name = ServiceConstant.GOV_ACCESS_SERVER, fallback = CommonGovAccessFeignClientFallback.class)
public interface CommonGovAccessFeignClient {
/**
* 查询登陆用户信息
* @return
*/
@PostMapping("/gov/access/access/loginuserinfo")
Result<LoginUserInfoResultDTO> getLoginUserInfo(@RequestBody LoginUserInfoFormDTO dto);
/**
* 查询角色所有operation及其范围(缓存)
* @return
*/
@PostMapping("/gov/access/access/roleallopesandscopes/{roleId}")
Result<List<RoleOpeScopeResultDTO>> listRoleAllOperationScopesByRoleId(@PathVariable("roleId") String roleId);
}

33
epmet-commons/epmet-commons-tools/src/main/java/com/epmet/commons/tools/feign/fallback/CommonGovAccessFeignClientFallback.java

@ -0,0 +1,33 @@
package com.epmet.commons.tools.feign.fallback;
import com.epmet.commons.tools.constant.ServiceConstant;
import com.epmet.commons.tools.dto.form.LoginUserInfoFormDTO;
import com.epmet.commons.tools.dto.form.LoginUserInfoResultDTO;
import com.epmet.commons.tools.dto.form.RoleOpeScopeResultDTO;
import com.epmet.commons.tools.feign.CommonGovAccessFeignClient;
import com.epmet.commons.tools.utils.ModuleUtils;
import com.epmet.commons.tools.utils.Result;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
/**
* 调用政府端权限
* @Author wxz
* @Description
* @Date 2020/4/24 11:17
**/
@Component
public class CommonGovAccessFeignClientFallback implements CommonGovAccessFeignClient {
@Override
public Result<LoginUserInfoResultDTO> getLoginUserInfo(LoginUserInfoFormDTO dto) {
return ModuleUtils.feignConError(ServiceConstant.GOV_ACCESS_SERVER, "getLoginUserInfo", dto);
}
@Override
public Result<List<RoleOpeScopeResultDTO>> listRoleAllOperationScopesByRoleId(@PathVariable("roleId") String roleId){
return ModuleUtils.feignConError(ServiceConstant.GOV_ACCESS_SERVER, "listRoleAllOperationScopesByRoleId", roleId);
}
}

5
epmet-module/gov-access/gov-access-client/src/main/java/com/epmet/dto/result/LoginUserInfoResultDTO.java

@ -7,6 +7,11 @@ import java.util.Set;
@Data
public class LoginUserInfoResultDTO {
/**
* 用户ID
*/
private String userId;
/**
* 权限列表
*/

1
epmet-module/gov-access/gov-access-server/src/main/java/com/epmet/controller/AccessController.java

@ -64,6 +64,7 @@ public class AccessController {
resultDTO.setOrgIdPath(govTokenDto.getOrgIdPath());
resultDTO.setGridIdList(govTokenDto.getGridIdList());
resultDTO.setDeptIdList(govTokenDto.getDeptIdList());
resultDTO.setUserId(govTokenDto.getUserId());
}
return new Result<LoginUserInfoResultDTO>().ok(resultDTO);
}

Loading…
Cancel
Save