Explorar o código

merge from release_v4.0.2

deason %!s(int64=4) %!d(string=hai) anos
pai
achega
9c47df1b56

+ 2 - 2
examcloud-core-oe-student-api-provider/src/main/java/cn/com/qmth/examcloud/core/oe/student/api/controller/ExamControlController.java

@@ -111,7 +111,7 @@ public class ExamControlController extends ControllerSupport {
         SequenceLockHelper.getLock(sequenceLockKey);
         ExamProcessResultInfo res = new ExamProcessResultInfo();
         try {
-            CheckExamInProgressInfo info = examControlService.checkExamInProgress(user.getUserId(),getIp(request));
+            CheckExamInProgressInfo info = examControlService.checkExamInProgress(user.getUserId(), getIp(request));
             res.setCode(Constants.COMMON_SUCCESS_CODE);
             res.setData(info);
             return res;
@@ -162,7 +162,7 @@ public class ExamControlController extends ControllerSupport {
         if (log.isDebugEnabled()) {
             log.debug("0 [END_EXAM] 交卷前处理耗时:" + (System.currentTimeMillis() - startTime) + " ms");
         }
-        examControlService.handInExam(examingSession.getExamRecordDataId(), HandInExamType.MANUAL,getIp(request));
+        examControlService.handInExam(examingSession.getExamRecordDataId(), HandInExamType.MANUAL, getIp(request));
         if (log.isDebugEnabled()) {
             log.debug("1 [END_EXAM]合计 耗时:" + (System.currentTimeMillis() - st) + " ms");
         }

+ 0 - 172
examcloud-core-oe-student-base/src/main/java/cn/com/qmth/examcloud/core/oe/student/base/utils/JsonMapper.java

@@ -1,172 +0,0 @@
-/*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-08-21 14:12:14.
- * *************************************************
- */
-
-package cn.com.qmth.examcloud.core.oe.student.base.utils;
-
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.*;
-import com.fasterxml.jackson.databind.util.JSONPObject;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 封装Jackson,实现JSON 与 Java Object互相转换的Mapper
- *
- * @author: QMTH
- * @since: 2018/8/20
- */
-@SuppressWarnings("unchecked")
-public class JsonMapper {
-    private static Logger log = LoggerFactory.getLogger(JsonMapper.class);
-    private ObjectMapper mapper;
-
-    public JsonMapper() {
-        this(null);
-    }
-
-    public JsonMapper(Include include) {
-        mapper = new ObjectMapper();
-        if (include != null) {
-            mapper.setSerializationInclusion(include);
-        }
-        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
-    }
-
-    public static JsonMapper nonEmptyMapper() {
-        return new JsonMapper(Include.NON_EMPTY);
-    }
-
-    public static JsonMapper nonNullMapper() {
-        return new JsonMapper(Include.NON_NULL);
-    }
-
-    public static JsonMapper nonDefaultMapper() {
-        return new JsonMapper(Include.NON_DEFAULT);
-    }
-
-    public String toJson(Object object) {
-        try {
-            return mapper.writeValueAsString(object);
-        } catch (IOException e) {
-            log.error("write to json string error:" + object);
-            return null;
-        }
-    }
-
-    public <T> T fromJson(String jsonString, Class<T> clazz) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            return mapper.readValue(jsonString, clazz);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    public <T> T fromJson(String jsonString, JavaType javaType) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            return (T) mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    public <T> T fromJson(String jsonString, TypeReference javaType) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            return (T) mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    public <T> List<T> toList(String jsonString, Class<T> bean) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            JavaType javaType = constructCollectionType(List.class, bean);
-            return mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error", e);
-            return null;
-        }
-    }
-
-    public <T> Map<String, T> toHashMap(String jsonString, Class<T> bean) {
-        if (StringUtils.isEmpty(jsonString)) {
-            return null;
-        }
-        try {
-            JavaType javaType = constructMapType(HashMap.class, String.class, bean);
-            return mapper.readValue(jsonString, javaType);
-        } catch (IOException e) {
-            log.error("parse json string error:", e);
-            return null;
-        }
-    }
-
-    public JavaType constructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
-        return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
-    }
-
-    public JavaType constructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
-        return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
-    }
-
-    public void update(String jsonString, Object object) {
-        try {
-            mapper.readerForUpdating(object).readValue(jsonString);
-        } catch (JsonProcessingException e) {
-            log.error("update json string:" + jsonString + " to object:" + object + " error.");
-        } catch (IOException e) {
-            log.error("update json string:" + jsonString + " to object:" + object + " error.");
-        }
-    }
-
-    public String toJsonP(String functionName, Object object) {
-        return toJson(new JSONPObject(functionName, object));
-    }
-
-    public void enableEnumUseToString() {
-        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
-        mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
-    }
-
-    public ObjectMapper getMapper() {
-        return mapper;
-    }
-
-    public JsonNode getNode(String jsonStr) {
-        try {
-            //mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
-            return mapper.readTree(jsonStr);
-        } catch (IOException e) {
-            log.error(e.getMessage(), e);
-            return null;
-        }
-    }
-
-}

+ 1 - 0
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/ExamRecordDataService.java

@@ -71,4 +71,5 @@ public interface ExamRecordDataService {
      * @param req
      */
     void updatePartialExamRecord(UpdatePartialExamRecordReq req);
+
 }

+ 65 - 16
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamControlServiceImpl.java

@@ -6,8 +6,9 @@ import cn.com.qmth.examcloud.api.commons.enums.SubmitType;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.commons.util.UUID;
 import cn.com.qmth.examcloud.commons.util.*;
+import cn.com.qmth.examcloud.commons.util.UUID;
+import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
 import cn.com.qmth.examcloud.core.oe.admin.api.ExamRecordCloudService;
 import cn.com.qmth.examcloud.core.oe.admin.api.SyncExamDataCloudService;
 import cn.com.qmth.examcloud.core.oe.admin.api.bean.ExamQuestionBean;
@@ -65,6 +66,8 @@ import cn.com.qmth.examcloud.ws.api.enums.WebSocketEventType;
 import cn.com.qmth.examcloud.ws.api.request.SendFileAnswerMessageReq;
 import cn.com.qmth.examcloud.ws.api.request.SendScanQrCodeMessageReq;
 import cn.com.qmth.examcloud.ws.api.request.SendTextReq;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.google.common.base.Splitter;
 import main.java.com.upyun.Base64Coder;
 import main.java.com.upyun.UpException;
@@ -138,6 +141,7 @@ public class ExamControlServiceImpl implements ExamControlService {
 
     @Autowired
     private ExamRecordDataRepo examRecordDataRepo;
+
     @Autowired
     private ExamContinuedRecordRepo examContinuedRecordRepo;
 
@@ -585,11 +589,16 @@ public class ExamControlServiceImpl implements ExamControlService {
                 || (examSettingsCacheBean.getExamLimit() != null && examSettingsCacheBean.getExamLimit())) {
             throw new StatusException("100016", "暂无考试资格,请与学校老师联系");
         }
-        if (new Date().before(examSettingsCacheBean.getBeginTime())) {
-            throw new StatusException("100017", "考试未开始");
-        }
-        if (examSettingsCacheBean.getEndTime().before(new Date())) {
-            throw new StatusException("100018", "本次考试已结束");
+        ExamPropertyCacheBean examCycleEnabledCache = CacheHelper.getExamProperty(examId, ExamProperties.EXAM_CYCLE_ENABLED.name());
+        if (examCycleEnabledCache != null && StringUtil.isTrue(examCycleEnabledCache.getValue())) {//设置周期的只校验周期
+            checkExamCycle(examId);
+        } else {
+            if (new Date().before(examSettingsCacheBean.getBeginTime())) {
+                throw new StatusException("100017", "考试未开始");
+            }
+            if (examSettingsCacheBean.getEndTime().before(new Date())) {
+                throw new StatusException("100018", "本次考试已结束");
+            }
         }
 
         if ((!ExamType.ONLINE.name().equals(examSettingsCacheBean.getExamType()))
@@ -691,6 +700,9 @@ public class ExamControlServiceImpl implements ExamControlService {
         examRecordData.setHandInExamType(handInExamType);
 
         Long studentId = examRecordData.getStudentId();
+        Long examId = examRecordData.getExamId();
+        Long rootOrgId = examRecordData.getRootOrgId();
+
         if (handInExamType == HandInExamType.MANUAL) {
 
             // 得到考试时长,校验是否达到冻结时间
@@ -700,9 +712,6 @@ public class ExamControlServiceImpl implements ExamControlService {
             examRecordData.setEndTime(new Date());
 
             // 手工手卷时,如果开启人脸检测,则更新抓拍队列优先级
-            Long rootOrgId = examRecordData.getRootOrgId();
-            Long examId = examRecordData.getExamId();
-
             if (FaceBiopsyHelper.isFaceEnable(rootOrgId, examId, studentId)) {
                 //更新照片处理的优先级不影响交卷业务
                 try {
@@ -1762,12 +1771,12 @@ public class ExamControlServiceImpl implements ExamControlService {
                 examSessionInfo.getExamId(), examSessionInfo.getExamStudentId()));
 
         // 返回考试剩余时间
-        long leftTime =0;
-        if(examSessionInfo.getTimingEnd()) {//定点收卷
-        	Date now=new Date();
-        	leftTime=examSessionInfo.getFixedSubmitTime().getTime()-now.getTime();
-        }else {
-        	leftTime=examSessionInfo.getExamDuration() - (examingHeartbeat.getCost() * 1000);
+        long leftTime = 0;
+        if (examSessionInfo.getTimingEnd()) {//定点收卷
+            Date now = new Date();
+            leftTime = examSessionInfo.getFixedSubmitTime().getTime() - now.getTime();
+        } else {
+            leftTime = examSessionInfo.getExamDuration() - (examingHeartbeat.getCost() * 1000);
         }
         return leftTime < 0 ? 0 : leftTime;
     }
@@ -1840,7 +1849,7 @@ public class ExamControlServiceImpl implements ExamControlService {
         //考试总时长
 //        long examTotalMilliSeconds = calcExamTotalMilliSeconds(examingSession.getExamRecordDataId());
         //如果开启场次,并且设置了定点交卷,且已到定点收卷时间,则不需要校验冻结时间,直接返回考试时长
-        if (examingSession.getTimingEnd() && examingSession.getFixedSubmitTime().getTime()<=new Date().getTime()) {
+        if (examingSession.getTimingEnd() && examingSession.getFixedSubmitTime().getTime() <= new Date().getTime()) {
             return examUsedMilliSeconds;
         }
 
@@ -2050,4 +2059,44 @@ public class ExamControlServiceImpl implements ExamControlService {
 
         return bean;
     }
+
+    /**
+     * 校验考试周期
+     *
+     * @param examId
+     */
+    private void checkExamCycle(Long examId) {
+
+        Date now = new Date();
+
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(now);
+        int weekIndex = (cal.get(Calendar.DAY_OF_WEEK) + 6) % 7;
+        if (weekIndex == 0) {
+            weekIndex = 7;
+        }
+
+        ExamPropertyCacheBean examCycleWeekCache = CacheHelper.getExamProperty(examId, ExamProperties.EXAM_CYCLE_WEEK.name());
+        if (!examCycleWeekCache.getValue().contains(String.valueOf(weekIndex))) {
+            throw new StatusException("500", "不处于指定开放时间,请稍后进入考试");
+        }
+
+        ExamPropertyCacheBean examCycleTimeRangeCache = CacheHelper.getExamProperty(examId, ExamProperties.EXAM_CYCLE_TIME_RANGE.name());
+
+        String day = DateUtil.format(now, DatePatterns.YYYY_MM_DD);
+
+        JSONArray ja = JSONObject.parseArray(examCycleTimeRangeCache.getValue());
+        for (int i = 0; i < ja.size(); i++) {
+            JSONObject jo = ja.getJSONObject(i);
+            JSONArray timeRange = jo.getJSONArray("timeRange");
+            String joStart = timeRange.getString(0);
+            String joEnd = timeRange.getString(1);
+            long start = DateUtil.parse(day + " " + joStart + ":00", DatePatterns.CHINA_DEFAULT).getTime();
+            long end = DateUtil.parse(day + " " + joEnd + ":59", DatePatterns.CHINA_DEFAULT).getTime();
+            if (start <= now.getTime() && end >= now.getTime()) {
+                return;
+            }
+        }
+        throw new StatusException("500", "不处于指定开放时间,请稍后进入考试");
+    }
 }

+ 13 - 15
examcloud-core-oe-student-service/src/main/java/cn/com/qmth/examcloud/core/oe/student/service/impl/ExamRecordDataServiceImpl.java

@@ -1,22 +1,7 @@
 package cn.com.qmth.examcloud.core.oe.student.service.impl;
 
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.stream.Collectors;
-
 import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
 import cn.com.qmth.examcloud.api.commons.enums.ExamStageStartExamStatus;
-import cn.com.qmth.examcloud.examwork.api.ExamStageCloudService;
-import cn.com.qmth.examcloud.examwork.api.request.ModifyExamStageStartExamStatusReq;
-import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.oe.student.api.request.CalcExamScoreReq;
@@ -37,6 +22,8 @@ import cn.com.qmth.examcloud.core.oe.student.dao.entity.FaceBiopsyEntity;
 import cn.com.qmth.examcloud.core.oe.student.dao.enums.FaceVerifyResult;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordDataService;
 import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordQuestionsService;
+import cn.com.qmth.examcloud.examwork.api.ExamStageCloudService;
+import cn.com.qmth.examcloud.examwork.api.request.ModifyExamStageStartExamStatusReq;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.ExamSettingsCacheBean;
@@ -52,6 +39,17 @@ import cn.com.qmth.examcloud.support.examing.ExamingSession;
 import cn.com.qmth.examcloud.support.helper.FaceBiopsyHelper;
 import cn.com.qmth.examcloud.support.redis.RedisKeyHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @author chenken

+ 1 - 1
examcloud-core-oe-student-starter/src/main/java/cn/com/qmth/examcloud/core/oe/student/starter/OEStudentApp.java

@@ -37,7 +37,7 @@ public class OEStudentApp {
 	static {
 		String runtimeLevel = System.getProperty("log.commonLevel");
 		if (null == runtimeLevel) {
-			System.setProperty("log.commonLevel", "DEBUG");
+			System.setProperty("log.commonLevel", "INFO");
 		}
 		System.setProperty("hibernate.dialect.storage_engine", "innodb");
 		DataIntegrityViolationTransverter.setUniqueRules(UniqueRuleHolder.getUniqueRuleList());

+ 120 - 105
examcloud-core-oe-student-starter/src/main/java/cn/com/qmth/examcloud/core/oe/student/starter/config/ExamCloudResourceManager.java

@@ -1,28 +1,27 @@
 package cn.com.qmth.examcloud.core.oe.student.starter.config;
 
-import java.util.List;
-import java.util.Set;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import com.google.common.collect.Sets;
-
-import cn.com.qmth.examcloud.api.commons.security.bean.AccessApp;
-import cn.com.qmth.examcloud.api.commons.security.bean.Role;
-import cn.com.qmth.examcloud.api.commons.security.bean.User;
-import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
+import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
+import cn.com.qmth.examcloud.api.commons.security.bean.*;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
 import cn.com.qmth.examcloud.commons.util.PathUtil;
 import cn.com.qmth.examcloud.commons.util.PropertiesUtil;
 import cn.com.qmth.examcloud.commons.util.RegExpUtil;
+import cn.com.qmth.examcloud.core.basic.api.UserDataRuleCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.QueryUserDataRuleReq;
+import cn.com.qmth.examcloud.core.basic.api.response.QueryUserDataRuleResp;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.AppCacheBean;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import cn.com.qmth.examcloud.web.security.ResourceManager;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
+import com.google.common.collect.Sets;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Set;
 
 /**
  * Demo资源管理器
@@ -34,96 +33,112 @@ import cn.com.qmth.examcloud.web.support.ApiInfo;
 @Component
 public class ExamCloudResourceManager implements ResourceManager {
 
-	@Autowired
-	RedisClient redisClient;
-
-	static {
-		PropertiesUtil.loadFromPath(PathUtil.getResoucePath("security.properties"));
-	}
-
-	@Override
-	public AccessApp getAccessApp(Long appId) {
-		AppCacheBean appCacheBean = CacheHelper.getApp(appId);
-		AccessApp app = new AccessApp();
-		app.setAppId(appCacheBean.getId());
-		app.setAppCode(appCacheBean.getCode());
-		app.setAppName(appCacheBean.getName());
-		app.setSecretKey(appCacheBean.getSecretKey());
-		app.setTimeRange(appCacheBean.getTimeRange());
-		return app;
-	}
-
-	@Override
-	public boolean isNaked(ApiInfo apiInfo, String mapping) {
-		if (null == apiInfo) {
-			return true;
-		}
-
-		if (null != apiInfo) {
-			if (apiInfo.isNaked()) {
-				return true;
-			}
-		}
-		if(mapping.matches(".*swagger.*")) {
-			return true;
-		}
-		return false;
-	}
-
-	@Override
-	public boolean hasPermission(User user, ApiInfo apiInfo, String mapping) {
-
-		// 学生鉴权
-		if (user.getUserType().equals(UserType.STUDENT)) {
-			return true;
-		}
-
-		List<Role> roleList = user.getRoleList();
-
-		if (CollectionUtils.isEmpty(roleList)) {
-			return false;
-		}
-
-		for (Role role : roleList) {
-			if (role.getRoleCode().equals(RoleMeta.SUPER_ADMIN.name())) {
-				return true;
-			}
-		}
-
-		// 权限组集合
-		String privilegeGroups = PropertiesUtil.getString(mapping);
-		if (StringUtils.isBlank(privilegeGroups)) {
-			return true;
-		}
-
-		// 用户权限集合
-		Set<String> rolePrivilegeList = Sets.newHashSet();
-		Long rootOrgId = user.getRootOrgId();
-		for (Role role : roleList) {
-			String key = "$_P_" + rootOrgId + "_" + role.getRoleId();
-			String rolePrivileges = redisClient.get(key, String.class);
-
-			List<String> rpList = RegExpUtil.findAll(rolePrivileges, "\\w+");
-			rolePrivilegeList.addAll(rpList);
-		}
-
-		List<String> privilegeGroupList = RegExpUtil.findAll(privilegeGroups, "[^\\;]+");
-
-		for (String pg : privilegeGroupList) {
-			pg = pg.trim();
-			if (StringUtils.isBlank(pg)) {
-				continue;
-			}
-
-			List<String> pList = RegExpUtil.findAll(pg, "[^\\,]+");
-			if (rolePrivilegeList.containsAll(pList)) {
-				return true;
-			} else {
-				continue;
-			}
-		}
-
-		return false;
-	}
+    @Autowired
+    RedisClient redisClient;
+
+    @Autowired
+    UserDataRuleCloudService userDataRuleCloudService;
+
+    static {
+        PropertiesUtil.loadFromPath(PathUtil.getResoucePath("security.properties"));
+    }
+
+    @Override
+    public AccessApp getAccessApp(Long appId) {
+        AppCacheBean appCacheBean = CacheHelper.getApp(appId);
+        AccessApp app = new AccessApp();
+        app.setAppId(appCacheBean.getId());
+        app.setAppCode(appCacheBean.getCode());
+        app.setAppName(appCacheBean.getName());
+        app.setSecretKey(appCacheBean.getSecretKey());
+        app.setTimeRange(appCacheBean.getTimeRange());
+        return app;
+    }
+
+    @Override
+    public boolean isNaked(ApiInfo apiInfo, String mapping) {
+        if (null == apiInfo) {
+            return true;
+        }
+
+        if (null != apiInfo) {
+            if (apiInfo.isNaked()) {
+                return true;
+            }
+        }
+        if (mapping.matches(".*swagger.*")) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean hasPermission(User user, ApiInfo apiInfo, String mapping) {
+
+        // 学生鉴权
+        if (user.getUserType().equals(UserType.STUDENT)) {
+            return true;
+        }
+
+        List<Role> roleList = user.getRoleList();
+
+        if (CollectionUtils.isEmpty(roleList)) {
+            return false;
+        }
+
+        for (Role role : roleList) {
+            if (role.getRoleCode().equals(RoleMeta.SUPER_ADMIN.name())) {
+                return true;
+            }
+        }
+
+        // 权限组集合
+        String privilegeGroups = PropertiesUtil.getString(mapping);
+        if (StringUtils.isBlank(privilegeGroups)) {
+            return true;
+        }
+
+        // 用户权限集合
+        Set<String> rolePrivilegeList = Sets.newHashSet();
+        Long rootOrgId = user.getRootOrgId();
+        for (Role role : roleList) {
+            String key = "$_P_" + rootOrgId + "_" + role.getRoleId();
+            String rolePrivileges = redisClient.get(key, String.class);
+
+            List<String> rpList = RegExpUtil.findAll(rolePrivileges, "\\w+");
+            rolePrivilegeList.addAll(rpList);
+        }
+
+        List<String> privilegeGroupList = RegExpUtil.findAll(privilegeGroups, "[^\\;]+");
+
+        for (String pg : privilegeGroupList) {
+            pg = pg.trim();
+            if (StringUtils.isBlank(pg)) {
+                continue;
+            }
+
+            List<String> pList = RegExpUtil.findAll(pg, "[^\\,]+");
+            if (rolePrivilegeList.containsAll(pList)) {
+                return true;
+            } else {
+                continue;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public UserDataRule loadUserDataRule(Long userId, DataRuleType dataRuleType) {
+        QueryUserDataRuleReq req = new QueryUserDataRuleReq();
+        req.setUserId(userId);
+        req.setType(dataRuleType);
+        QueryUserDataRuleResp resp = userDataRuleCloudService.queryUserDataRule(req);
+
+        UserDataRule userDataRule = new UserDataRule();
+        userDataRule.setGlobalStatus(resp.getGlobalStatus());
+        userDataRule.setRefIds(resp.getRefIds());
+        return userDataRule;
+    }
 
 }

+ 28 - 27
examcloud-core-oe-student-starter/src/main/java/cn/com/qmth/examcloud/core/oe/student/starter/config/ExamCloudWebMvcConfigurer.java

@@ -2,19 +2,19 @@ package cn.com.qmth.examcloud.core.oe.student.starter.config;
 
 import cn.com.qmth.examcloud.web.interceptor.ApiFlowLimitedInterceptor;
 import cn.com.qmth.examcloud.web.interceptor.ApiStatisticInterceptor;
+import cn.com.qmth.examcloud.web.interceptor.FirstInterceptor;
 import cn.com.qmth.examcloud.web.interceptor.SeqlockInterceptor;
+import cn.com.qmth.examcloud.web.redis.RedisClient;
+import cn.com.qmth.examcloud.web.security.DataRuleInterceptor;
+import cn.com.qmth.examcloud.web.security.RequestPermissionInterceptor;
+import cn.com.qmth.examcloud.web.security.ResourceManager;
+import cn.com.qmth.examcloud.web.security.RpcInterceptor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
-import cn.com.qmth.examcloud.web.interceptor.FirstInterceptor;
-import cn.com.qmth.examcloud.web.redis.RedisClient;
-import cn.com.qmth.examcloud.web.security.RequestPermissionInterceptor;
-import cn.com.qmth.examcloud.web.security.ResourceManager;
-import cn.com.qmth.examcloud.web.security.RpcInterceptor;
-
 /**
  * WebMvcConfigurer
  *
@@ -25,29 +25,30 @@ import cn.com.qmth.examcloud.web.security.RpcInterceptor;
 @Configuration
 public class ExamCloudWebMvcConfigurer implements WebMvcConfigurer {
 
-	@Autowired
-	ResourceManager resourceManager;
+    @Autowired
+    ResourceManager resourceManager;
+
+    @Autowired
+    RedisClient redisClient;
 
-	@Autowired
-	RedisClient redisClient;
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");
+        registry.addInterceptor(new ApiFlowLimitedInterceptor()).addPathPatterns("/**");
+        registry.addInterceptor(new RpcInterceptor(resourceManager)).addPathPatterns("/**");
 
-	@Override
-	public void addInterceptors(InterceptorRegistry registry) {
-		registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");
-		registry.addInterceptor(new ApiFlowLimitedInterceptor()).addPathPatterns("/**");
-		registry.addInterceptor(new RpcInterceptor(resourceManager)).addPathPatterns("/**");
+        RequestPermissionInterceptor permissionInterceptor = new RequestPermissionInterceptor(resourceManager, redisClient);
+        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
+        registry.addInterceptor(new SeqlockInterceptor(redisClient)).addPathPatterns("/**");
+        registry.addInterceptor(new ApiStatisticInterceptor()).addPathPatterns("/**");
 
-		RequestPermissionInterceptor permissionInterceptor = new RequestPermissionInterceptor(
-				resourceManager, redisClient);
-		registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
-		registry.addInterceptor(new SeqlockInterceptor(redisClient)).addPathPatterns("/**");
-		registry.addInterceptor(new ApiStatisticInterceptor()).addPathPatterns("/**");
-	}
+        registry.addInterceptor(new DataRuleInterceptor(resourceManager)).addPathPatterns("/api/**");
+    }
 
-	@Override
-	public void addCorsMappings(CorsRegistry registry) {
-		registry.addMapping("/**").allowedOrigins("*").allowCredentials(false).allowedMethods("*")
-				.maxAge(3600);
-	}
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**").allowedOrigins("*").allowCredentials(false).allowedMethods("*")
+                .maxAge(3600);
+    }
 
-}
+}