瀏覽代碼

feat: 用户权限验证

sky 5 年之前
父節點
當前提交
9116d1f95e

+ 12 - 0
seec-data-server/pom.xml

@@ -20,6 +20,7 @@
 		<seecoder.bok.version>0.1.2</seecoder.bok.version>
 		<seecoder.judgement.version>0.2.0</seecoder.judgement.version>
 		<httpclient.version>4.5.6</httpclient.version>
+		<java.jwt.version>3.10.3</java.jwt.version>
 	</properties>
 	<dependencies>
 		<dependency>
@@ -69,6 +70,8 @@
 			<artifactId>junit</artifactId>
 			<scope>test</scope>
 		</dependency>
+
+		<!-- fastjson -->
 		<dependency>
 			<groupId>com.alibaba</groupId>
 			<artifactId>fastjson</artifactId>
@@ -86,6 +89,14 @@
 			<version>${aspectJVersion}</version>
 		</dependency>
 
+		<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
+		<dependency>
+			<groupId>com.auth0</groupId>
+			<artifactId>java-jwt</artifactId>
+			<version>${java.jwt.version}</version>
+		</dependency>
+
+
 		<!-- Seecoder -->
 		<dependency>
 			<groupId>cn.seecoder</groupId>
@@ -98,6 +109,7 @@
 			<version>${seecoder.judgement.version}</version>
 		</dependency>
 
+		<!-- Httpclient -->
 		<dependency>
 			<groupId>org.apache.httpcomponents</groupId>
 			<artifactId>httpclient</artifactId>

+ 3 - 0
seec-data-server/src/main/java/cn/seecoder/data/server/controller/EvaluateController.java

@@ -1,8 +1,10 @@
 package cn.seecoder.data.server.controller;
 
 import cn.seecoder.data.server.dto.evaluate.Response;
+import cn.seecoder.data.server.utils.aspects.auth.Auth;
 import cn.seecoder.data.server.utils.enums.ErrorCodeEnum;
 import cn.seecoder.data.server.service.EvaluateService;
+import cn.seecoder.data.server.utils.enums.UserRole;
 import cn.seecoder.data.server.utils.exception.GlobalException;
 import cn.seecoder.data.server.vo.Result;
 import cn.seecoder.data.server.vo.knowledge.*;
@@ -35,6 +37,7 @@ public class EvaluateController {
         return root;
     }
 
+    @Auth(roles = {UserRole.ADMIN})
     @RequestMapping("/eval/analysis/{examId}")
     public Result<Map<String, Map<String,Double>>> evalAnalysisByExamId(@PathVariable("examId") Integer examId) {
         Map<String, Map<String, Double>> res = evaluateService.analyzeEvalTest(examId);

+ 1 - 3
seec-data-server/src/main/java/cn/seecoder/data/server/schedule/CoderSchedule.java

@@ -1,13 +1,11 @@
 package cn.seecoder.data.server.schedule;
 
 import cn.seecoder.data.server.domain.CoderDao;
-import cn.seecoder.data.server.domain.GeneralRecordDao;
 import cn.seecoder.data.server.dto.coder.CoderDto;
 import cn.seecoder.data.server.dto.coder.Response;
-import cn.seecoder.data.server.dto.evaluate.ExamDetailsDto;
 import cn.seecoder.data.server.repository.CoderRepository;
 import cn.seecoder.data.server.service.ExtractionLogService;
-import cn.seecoder.data.server.utils.aspects.DataExtractor;
+import cn.seecoder.data.server.utils.aspects.dataExtraction.DataExtractor;
 import cn.seecoder.data.server.utils.enums.ErrorCodeEnum;
 import cn.seecoder.data.server.utils.exception.GlobalException;
 import org.springframework.beans.factory.annotation.Autowired;

+ 1 - 1
seec-data-server/src/main/java/cn/seecoder/data/server/schedule/EvaluateSchedule.java

@@ -2,7 +2,7 @@ package cn.seecoder.data.server.schedule;
 
 
 import cn.seecoder.data.server.repository.EvaluateRepository;
-import cn.seecoder.data.server.utils.aspects.DataExtractor;
+import cn.seecoder.data.server.utils.aspects.dataExtraction.DataExtractor;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;

+ 12 - 0
seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/auth/Auth.java

@@ -0,0 +1,12 @@
+package cn.seecoder.data.server.utils.aspects.auth;
+
+import cn.seecoder.data.server.utils.enums.UserRole;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Auth {
+    UserRole[] roles() default {};
+}

+ 60 - 0
seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/auth/AuthHandlerAspectJ.java

@@ -0,0 +1,60 @@
+package cn.seecoder.data.server.utils.aspects.auth;
+
+import cn.hutool.core.util.StrUtil;
+import cn.seecoder.data.server.utils.enums.ErrorCodeEnum;
+import cn.seecoder.data.server.utils.enums.UserRole;
+import cn.seecoder.data.server.utils.exception.GlobalException;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Aspect
+@Component
+@Order(1)
+public class AuthHandlerAspectJ {
+    @Value("${jwt.secret}")
+    private String jwtSecret;
+
+    @Before("execution(public * cn.seecoder.data.server.controller.*.*(..)) && @annotation(auth)")
+    public void authCheck(JoinPoint joinPoint, Auth auth) {
+        HttpServletRequest httpServletRequest =
+                ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
+                        .getRequest();
+        String token = Optional.ofNullable(httpServletRequest.getHeader("Authorization"))
+                .orElseThrow(() -> new GlobalException(ErrorCodeEnum.USER_ERROR_A0001));
+
+        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(jwtSecret)).build();
+
+        DecodedJWT decodedJWT;
+
+        try {
+            decodedJWT = jwtVerifier.verify(token);
+        } catch (JWTVerificationException e) {
+            throw new GlobalException(ErrorCodeEnum.USER_ERROR_A0002);
+        }
+
+        UserInfo userInfo = decodedJWT.getClaim("user_info").as(UserInfo.class);
+
+        for (UserRole role : auth.roles()) {
+            if (role == userInfo.getRole()) return;
+        }
+        throw new GlobalException(ErrorCodeEnum.USER_ERROR_A0003);
+    }
+}

+ 13 - 0
seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/auth/UserInfo.java

@@ -0,0 +1,13 @@
+package cn.seecoder.data.server.utils.aspects.auth;
+
+import cn.seecoder.data.server.utils.enums.UserRole;
+import lombok.Data;
+
+@Data
+class UserInfo {
+    private Long id;
+    private String phone;
+    private String email;
+    private String name;
+    private UserRole role;
+}

+ 2 - 2
seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/DataExtractionHandlerAspectJ.java → seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/dataExtraction/DataExtractionHandlerAspectJ.java

@@ -1,4 +1,4 @@
-package cn.seecoder.data.server.utils.aspects;
+package cn.seecoder.data.server.utils.aspects.dataExtraction;
 
 import cn.seecoder.data.server.domain.ExtractionLogDao;
 import cn.seecoder.data.server.repository.ExtractionLogRepository;
@@ -26,7 +26,7 @@ public class DataExtractionHandlerAspectJ {
 
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
-    @Pointcut("execution(* *(..)) && @annotation(DataExtractor)")
+    @Pointcut("execution(* *(..)) && @annotation(cn.seecoder.data.server.utils.aspects.dataExtraction.DataExtractor)")
     public void dataExtractorLogic() {}
 
     @Around("dataExtractorLogic()")

+ 1 - 1
seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/DataExtractor.java → seec-data-server/src/main/java/cn/seecoder/data/server/utils/aspects/dataExtraction/DataExtractor.java

@@ -1,4 +1,4 @@
-package cn.seecoder.data.server.utils.aspects;
+package cn.seecoder.data.server.utils.aspects.dataExtraction;
 
 import java.lang.annotation.*;
 

+ 3 - 1
seec-data-server/src/main/java/cn/seecoder/data/server/utils/enums/ErrorCodeEnum.java

@@ -6,7 +6,9 @@ package cn.seecoder.data.server.utils.enums;
 public enum ErrorCodeEnum {
     SUCCESS("00000", "成功"),
 
-    USER_ERROR_A0001("A0001", "无效的Token"),
+    USER_ERROR_A0001("A0001", "未识别到Token"),
+    USER_ERROR_A0002("A0002", "无效的Token"),
+    USER_ERROR_A0003("A0003", "用户无访问权限"),
 
     SYSTEM_ERROR_B0001("B0001", "未知的系统错误"),
     SYSTEM_ERROR_B0002("B0002", "系统执行出错"),

+ 16 - 0
seec-data-server/src/main/java/cn/seecoder/data/server/utils/enums/UserRole.java

@@ -0,0 +1,16 @@
+package cn.seecoder.data.server.utils.enums;
+
+public enum UserRole {
+    /**
+     * 教师
+     */
+    TEACHER,
+    /**
+     * 学生
+     */
+    STUDENT,
+    /**
+     * 管理员
+     */
+    ADMIN
+}

+ 2 - 0
seec-data-server/src/main/resources/application.yml

@@ -14,3 +14,5 @@ logging:
   config: classpath:logback-spring.xml
   file:
     path: logs
+jwt:
+  secret: 'SEEC-1919810-OIDC-114514'