Procházet zdrojové kódy

templeDesice2022/8/19

lwhhszx před 3 roky
rodič
revize
70f868e56c

+ 118 - 0
PAS/src/main/java/cn/cslg/pas/common/config/InnerInterceptor/LizzMybatisIntercepts.java

@@ -0,0 +1,118 @@
+package cn.cslg.pas.common.config.InnerInterceptor;
+
+import cn.cslg.pas.common.utils.SecurityUtils.SecurityUtils;
+import cn.cslg.pas.common.utils.auth.TreeUtils;
+import cn.cslg.pas.domain.DataSource;
+import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.FormBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
+
+import java.lang.reflect.Field;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+@Slf4j
+public class LizzMybatisIntercepts implements InnerInterceptor {
+
+
+    @Value("${authorUrl}")
+    private String url;
+    @SneakyThrows
+    @Override
+    public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+
+        try{
+          //获得原始sql
+        String Localsql = boundSql.getSql();
+        Map<String,Object> maps= SecurityUtils.getDataScope(); //获得线程里保存的functionId
+        if (maps != null) {
+            SecurityUtils.cleanDataScope(); //当第一次进来后删除线程保存的functionId,避免后续使用的查询sql进来
+            Integer functionId =Integer.parseInt(maps.get("functionId").toString());
+            String token =maps.get("token").toString();
+            RequestBody requestBody =  new FormBody.Builder()
+                    .add("loginId", maps.get("loginId").toString())
+                    .add("functionId",functionId.toString())
+                    .build();
+            OkHttpClient okHttpClient = new OkHttpClient();
+            Request request = new Request.Builder()
+                    .url(url+"/permission/api/data/queryDataRule")
+                    .post(requestBody)
+                    .addHeader("Cookie",token)
+                    .build();
+            String resBody = okHttpClient.newCall(request).execute().body().string();
+            JSONArray jsonArray = JSONArray.parseArray(resBody);
+            String  sqls ="";
+             //拼接所有角色的限制条件
+            if(jsonArray.size()>0){
+            for(int i=0;i<jsonArray.size();i++){
+                List<DataSource> dataSources =new ArrayList<>();
+                String sql1= TreeUtils.reSql(JSONObject.parseObject( jsonArray.get(i).toString()) ,dataSources);
+                sqls += jsonArray.size()!=i+1 ?  sql1+" OR ":sql1;
+            }
+            if(Localsql.contains("desc")){
+             Localsql=   Localsql.replace("desc","");
+                Localsql+=" And (" +sqls+") desc";
+            }
+            else{
+                Localsql+=" And (" +sqls+")";
+            }
+            //将限制条件拼接到sql语句
+
+            Field field = boundSql.getClass().getDeclaredField("sql");//反射获得boundsql的sql属性并改变sql参数
+            field.setAccessible(true); //属性设为可见(反射不安全的原因)
+            field.set(boundSql, Localsql);
+        }}
+        return true;
+        }
+     finally {
+         SecurityUtils.cleanDataScope();//无论是否进行成功最后都要删除线程里的保存的参数
+
+     }
+    }
+
+    @Override
+    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+
+    }
+
+    @Override
+    public boolean willDoUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
+        return true;
+    }
+
+    @Override
+    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
+    }
+
+    @Override
+    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
+    }
+
+    @Override
+    public void beforeGetBoundSql(StatementHandler sh) {
+    }
+
+    @Override
+    public void setProperties(Properties properties) {
+    }
+}

+ 6 - 0
PAS/src/main/java/cn/cslg/pas/common/config/MybatisPlusConfig.java

@@ -1,5 +1,6 @@
 package cn.cslg.pas.common.config;
 
+import cn.cslg.pas.common.config.InnerInterceptor.LizzMybatisIntercepts;
 import com.baomidou.mybatisplus.annotation.DbType;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
@@ -11,9 +12,14 @@ import org.springframework.context.annotation.Configuration;
 @MapperScan("cn.cslg.pas.mapper")
 public class MybatisPlusConfig {
 
+    @Bean//必须加Bean注解,否则无法拦截器里无法实例化serve
+    public LizzMybatisIntercepts lizzMybatisIntercepts(){
+        return  new LizzMybatisIntercepts();
+    } //自定义拦截器
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor() {
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(lizzMybatisIntercepts());//加入自定义拦截器
         interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
         return interceptor;
     }

+ 1 - 0
PAS/src/main/java/cn/cslg/pas/common/model/PersonnelVO.java

@@ -1,5 +1,6 @@
 package cn.cslg.pas.common.model;
 
+import cn.cslg.pas.common.model.vo.BaseVO;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;

+ 2 - 0
PAS/src/main/java/cn/cslg/pas/common/model/vo/BaseVO.java

@@ -7,4 +7,6 @@ public class BaseVO {
     private Long current;
     private Long size;
     private String order;
+    private String functionId;
+    public String token;
 }

+ 31 - 0
PAS/src/main/java/cn/cslg/pas/common/utils/SecurityUtils/SecurityUtils.java

@@ -0,0 +1,31 @@
+package cn.cslg.pas.common.utils.SecurityUtils;
+
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class SecurityUtils {
+
+    protected static final ThreadLocal<Map<String,Object>> threadLocal = new ThreadLocal();
+    /**
+     * 设置权限标识
+     * @param params
+     */
+    public static void startDataScope(Map<String,Object> params){
+        threadLocal.set(params);
+    }
+    /**
+     * 获取权限标识
+     */
+    public static Map<String, Object> getDataScope(){
+        return threadLocal.get();
+    }
+    /**
+     * 清除权限标识
+     */
+    public static void cleanDataScope(){
+        threadLocal.remove();
+    }
+
+}

+ 123 - 0
PAS/src/main/java/cn/cslg/pas/common/utils/auth/AuthAop.java

@@ -0,0 +1,123 @@
+package cn.cslg.pas.common.utils.auth;
+
+import cn.hutool.json.JSONString;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import okhttp3.*;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.aspectj.lang.reflect.CodeSignature;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+
+@Aspect
+@Component
+public class AuthAop {
+    @Value("${authorUrl}")
+    private String url;
+    /**
+     * 定义切点
+     */
+    @Pointcut("@annotation(cn.cslg.pas.common.utils.auth.checkAuth)")
+    public void annotationPointcut() {
+
+    }
+    @Before("annotationPointcut()")
+    public void beforePointcut(JoinPoint joinPoint) {
+        // 此处进入到方法前  可以实现一些业务逻辑
+        //获取目标对象方法参数
+
+    }
+
+    @Around("annotationPointcut()")
+    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
+        // 获得注解上的参数值
+        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
+        Method method = ms.getMethod();
+        checkAuth myAnnotation = method.getAnnotation(checkAuth.class);
+        Integer functionId =myAnnotation.FunId();
+
+        //RequestContextHolder:持有上下文的Request容器,获取到当前请求的request
+        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+        HttpServletRequest httpRequest = sra.getRequest();
+        String tem =httpRequest.getHeader("Cookie");
+
+        Object[] args = joinPoint.getArgs();
+        //遍历参数 修改带有需求字段对象的值
+        for (Object obj : args) {
+            try {
+                Class<?> resultClz = obj.getClass();
+                //获取class里的所有字段  父类字段获取不到
+                Field[] fieldInfo = resultClz.getFields();
+                for (Field field : fieldInfo) {
+                    if ("token".equals(field.getName())) {
+                            field.set(obj,tem);
+                        break; }
+                }
+            } catch (Exception e) {
+            }
+        }
+        //根据登录人的id以及功能id获得计算逻辑
+        RequestBody requestBody =  new FormBody.Builder()
+                .add("loginId", "4")
+                .add("functionId",functionId.toString())
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient();
+
+        Request request = new Request.Builder()
+                .url(url+"/permission/api/data/queryDataRule")
+                .addHeader("Cookie",tem)
+                .post(requestBody)
+                .build();
+        String resBody = okHttpClient.newCall(request).execute().body().string();
+        JSONArray jsonArray = JSONArray.parseArray(resBody);
+
+        Boolean isPass =true;
+       if(jsonArray.size()>0){   // 如果查询结果的size大于0证明有限制逻辑
+//           //处理jsonObject,变为(x==y)&&(z==t)的形式 ,并用js引擎进行boolean判断
+//           String  sqls ="";
+//           for(int i=0;i<jsonArray.size();i++){
+//               String sql=TreeUtils.reCompute((JSONObject) jsonArray.get(i),functionId,args);
+//               sqls += jsonArray.size()!=i+1 ?  sql+" || ":sql;
+//           }
+//           //js引擎进行判断
+//           ScriptEngineManager manager = new ScriptEngineManager();
+//           ScriptEngine engine = manager.getEngineByName("javascript");//根据名字获得引擎
+//           Object result = engine.eval(sqls);//进行判断
+//            isPass =(Boolean) result;
+       }
+
+        //判断通过
+        if(isPass){ return joinPoint.proceed();}
+        //判断不通过
+
+        return  null;
+    }
+
+    /**
+     * 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
+     * @param joinPoint
+     */
+    @AfterReturning("annotationPointcut()")
+    public void doAfterReturning(JoinPoint joinPoint) {
+    }
+
+    private void checkToken(String token) {
+
+    }
+}
+

+ 164 - 0
PAS/src/main/java/cn/cslg/pas/common/utils/auth/TreeUtils.java

@@ -0,0 +1,164 @@
+package cn.cslg.pas.common.utils.auth;
+
+import cn.cslg.pas.domain.DataSource;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+@Component
+public class TreeUtils {
+    /**
+     * 分页查询设置返回参数 (当前页 每页条数 总条数)
+     */
+    public static   String reSql(JSONObject jsonObject,List<DataSource> dataSource)  {
+
+     String sql=  recursionTree(jsonObject,dataSource);
+        return sql;
+
+    }
+
+    public static   String reCompute(JSONObject jsonObject,Integer id,Object[] object) throws NoSuchFieldException, IllegalAccessException {
+
+        String sql=  cRecursionTree(jsonObject,id,object);
+        return sql;
+
+    }
+
+    /**
+     * 将二叉树json对象转为sql where后的条件语句
+     *liRJ
+     * @param jsonObject jsaonObject
+     * @return
+     */
+    public static  String recursionTree(JSONObject jsonObject, List<DataSource> dataSource)  {
+        String str1 = "";
+        String str2 = "";
+        JSONObject jsonLeft =jsonObject.getJSONObject("left");
+        JSONObject jsonRight =jsonObject.getJSONObject("right");
+        if(jsonLeft.containsKey("left")){
+            str1 = recursionTree(jsonLeft,dataSource);
+        }
+        else{
+            String field =distinguishFields(jsonLeft.get("field").toString(),dataSource);
+            String value=distinguishFields(jsonLeft.get("value").toString(),dataSource);
+            str1 = field+jsonLeft.get("opr").toString()+value;
+        }
+        if(jsonRight.containsKey("right")){
+            str2= recursionTree( jsonRight,dataSource);
+        }
+        else{
+            String field =distinguishFields(jsonRight.get("field").toString(),dataSource);
+            String value=distinguishFields(jsonRight.get("value").toString(),dataSource);
+            str2 =field+jsonRight.get("opr").toString()+value;
+        }
+        String sql ="("+ str1+") "+ jsonObject.get("logicOpr")+" ("+str2+")";
+        return sql;
+    };
+
+     //json规则判断
+    public static  String cRecursionTree(JSONObject jsonObject,Integer id, Object[] object) throws NoSuchFieldException, IllegalAccessException {
+        String str1 = "";
+        String str2 = "";
+        JSONObject jsonLeft =jsonObject.getJSONObject("left");
+        JSONObject jsonRight =jsonObject.getJSONObject("right");
+        if(jsonLeft.containsKey("left")){
+            str1 = cRecursionTree(jsonLeft,id,object);
+        }
+        else{
+            String field = distinguishFields(jsonLeft.get("field").toString(),object);
+            String value= distinguishValues(jsonLeft.get("value").toString(),object);
+            String opr = distinguishLogic(jsonLeft.getString("nodeType"),jsonLeft.getString("opr"));
+            str1 = field+opr+value;
+        }
+        if(jsonRight.containsKey("right")){
+            str2= cRecursionTree( jsonRight,id,object);
+        }
+        else{
+            String field =distinguishFields(jsonRight.get("field").toString(),object);
+            String value=distinguishValues(jsonRight.get("value").toString(),object);
+            String opr = distinguishLogic(jsonRight.getString("nodeType"),jsonRight.getString("opr"));
+            str2 =field+opr+value;
+        }
+        String sql ="("+ str1+") "+distinguishLogic(jsonObject.getString("nodeType"),jsonObject.getString("logicOpr"))+" ("+str2+")";
+
+        return sql;
+    };
+
+    //对field部分进行计算 sql查询
+    public static String distinguishFields(String field, List<DataSource> dataSources){
+        String tem ="";
+        String reField =field;
+        for(DataSource dataSource :dataSources){
+            if(field.equals(dataSource.getDataSourceField()) ){
+                tem =dataSource.getDataSourceDataBase();
+                break;
+            }}
+        switch (tem){
+            case "1":
+                reField="";
+                break;
+            case "2":
+                reField="1";
+                break;
+        }
+        return reField;
+    }
+
+    //对field部分进行计算
+    public static String distinguishFields(String field, Object[] object) throws NoSuchFieldException, IllegalAccessException {
+        String reField ="'"+field+"'";
+        //反射获方法的参数值
+        Class jsonClass = object[0].getClass();
+        for(Field field1: jsonClass.getDeclaredFields()){
+           if(field1.getName().equals(field)){     //判断field的值是否和参数名一样,一样的话变为参数值
+               Field dataField = jsonClass.getDeclaredField(field);
+               dataField.setAccessible(true);//设置data属性为可访问的
+               String  fie=dataField.get(object[0]).toString();
+               reField ="'"+fie+"'";
+               break;
+           }
+        }
+
+        return reField;
+    }
+
+    //对value部分进行计算
+    public static String distinguishValues(String value, Object[] object) throws NoSuchFieldException, IllegalAccessException {
+        String reValue ="'"+value+"'";
+        //反射获得参数值
+        Class jsonClass = object[0].getClass();
+        for(Field field1: jsonClass.getDeclaredFields()){
+            if(field1.getName().equals(value)){     //判断value的值是否和参数名一样,一样的话变为参数值
+                Field dataField = jsonClass.getDeclaredField(value);
+                dataField.setAccessible(true);//设置data属性为可访问的
+                String  fie=dataField.get(object[0]).toString();
+                reValue ="'"+fie+"'";
+                break;
+            }
+        }
+
+        return reValue;
+    }
+
+
+    public static  String distinguishLogic(String nodeType ,String opr) {
+        if(nodeType .equals("logic")){
+            switch (opr){
+                case "=":
+                    opr = "==";
+                    break;
+                case "and":
+                    opr = "&&";
+                    break;
+                case "or":
+                    opr = "||";
+                    break;
+            }
+        }
+            return  opr;
+
+    }
+}

+ 19 - 0
PAS/src/main/java/cn/cslg/pas/common/utils/auth/checkAuth.java

@@ -0,0 +1,19 @@
+package cn.cslg.pas.common.utils.auth;
+
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+/**
+ * @author LRJ
+ * @date 2022-8-23
+ * @description 数据权限(增删改)条件判断注解
+ */
+public @interface checkAuth {
+    int FunId() default 0;
+
+}
+

+ 4 - 0
PAS/src/main/java/cn/cslg/pas/controller/ProjectController.java

@@ -6,6 +6,7 @@ import cn.cslg.pas.common.core.exception.PermissionException;
 import cn.cslg.pas.common.model.PersonnelVO;
 import cn.cslg.pas.common.model.vo.*;
 import cn.cslg.pas.common.utils.*;
+import cn.cslg.pas.common.utils.auth.checkAuth;
 import cn.cslg.pas.domain.ProjectExport;
 import cn.cslg.pas.domain.User;
 import cn.cslg.pas.domain.Project;
@@ -15,6 +16,7 @@ import cn.hutool.core.util.IdUtil;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.RequiredArgsConstructor;
+import okhttp3.Request;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -42,9 +44,11 @@ public class ProjectController {
     private final ProjectExportService projectExportService;
     private final ProjectPatentLinkService projectPatentLinkService;
 
+    @checkAuth(FunId = 8)
     @PostMapping("list")
     @Operation(summary = "专题库列表")
     public String getPageList(@RequestBody ProjectVO params) {
+
         return Response.success(projectService.getPageList(params));
     }
 

+ 50 - 0
PAS/src/main/java/cn/cslg/pas/domain/DataSource.java

@@ -0,0 +1,50 @@
+package cn.cslg.pas.domain;
+
+import cn.cslg.pas.common.model.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-12
+ * @description 数据权限类 数据库对应实体
+ */
+
+@lombok.Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@TableName(value = "DATA_SOURCE")
+public class DataSource extends BaseEntity<DataSource> {
+    /**
+     * 数据字典名字
+     */
+    @TableField(value = "DATA_SOURCE_NAME")
+    private String dataSourceName;
+
+    /**
+     * 数据字典描述
+     */
+    @TableField(value = "DATA_SOURCE_DESCRIPTION")
+    private String dataSourceDescription;
+
+    /**
+     * 数据字典数据库
+     */
+    @TableField(value = "DATA_SOURCE_DATABASE")
+    private String dataSourceDataBase;
+
+    /**
+     * 数据字典表格
+     */
+    @TableField(value = "DATA_SOURCE_TABLE")
+    private String dataSourceTable;
+
+    /**
+     * 数据字典字段
+     */
+    @TableField(value = "DATA_SOURCE_FIELD")
+    private String dataSourceField;
+
+}

+ 1 - 1
PAS/src/main/java/cn/cslg/pas/service/OAuth2Service.java

@@ -162,7 +162,7 @@ public class OAuth2Service {
         PersonnelVO personnelVO = JsonUtils.jsonToPojo(token, PersonnelVO.class);
 
 
-        return Response.success(personnelVO.getToken());
+        return Response.success(token);
     }
 
     public String changePwd(String oldPassword, String newPassword) {

+ 6 - 0
PAS/src/main/java/cn/cslg/pas/service/ProjectService.java

@@ -6,6 +6,7 @@ import cn.cslg.pas.common.model.PersonnelVO;
 import cn.cslg.pas.common.model.dto.TaskWebSocketDTO;
 import cn.cslg.pas.common.model.dto.UploadFileDTO;
 import cn.cslg.pas.common.model.vo.*;
+import cn.cslg.pas.common.utils.SecurityUtils.SecurityUtils;
 import cn.cslg.pas.domain.*;
 import cn.cslg.pas.common.utils.*;
 import cn.cslg.pas.common.model.params.*;
@@ -112,6 +113,10 @@ public class ProjectService extends ServiceImpl<ProjectMapper, Project> {
     }
 
     public IPage<Project> getPageList(ProjectVO params) {
+        Map<String,Object> m =new HashMap<>();
+        m.put("token",params.getToken());
+        m.put("loginId",4);
+        m.put("functionId",8);
         PersonnelVO user = cacheUtils.getLoginUserPersonnel(3);
         List<Integer> projectIds = new ArrayList<Integer>() {{
             add(-1);
@@ -124,6 +129,7 @@ public class ProjectService extends ServiceImpl<ProjectMapper, Project> {
         }
         params.setProIds(projectIds);
         params.setCreateBy(3);
+        SecurityUtils.startDataScope(m);
         IPage<Project> pageList = baseMapper.getPageList(new Page<>(params.getCurrent(), params.getSize()), params);
         List<Project> dataList = pageList.getRecords();
         Map<String, Object> map = new HashMap<>();