From e5489649279e1bf7751e426784d1d368280d24af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=B2=9C=20=EC=A7=84=EA=B0=95?= <jjjjjk12@ajou.ac.kr>
Date: Mon, 3 Mar 2025 22:56:29 +0900
Subject: [PATCH] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=EC=9D=98=20?=
 =?UTF-8?q?=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20Role=20api=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../aolda/itda/controller/AuthController.java | 12 +++--
 .../com/aolda/itda/exception/ErrorCode.java   |  5 +-
 .../com/aolda/itda/service/AuthService.java   | 47 +++++++++++++++----
 3 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/src/main/java/com/aolda/itda/controller/AuthController.java b/src/main/java/com/aolda/itda/controller/AuthController.java
index 274ad8f..79046d2 100644
--- a/src/main/java/com/aolda/itda/controller/AuthController.java
+++ b/src/main/java/com/aolda/itda/controller/AuthController.java
@@ -6,10 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequestMapping("/api/auth")
@@ -24,4 +21,11 @@ public class AuthController {
 
         return ResponseEntity.ok(authService.userLogin(response, loginRequestDTO));
     }
+
+    @GetMapping("/role")
+    public ResponseEntity<Object> roleWithinProject(@RequestHeader("X-Subject-Token") String token,
+                                                    @RequestParam String projectId) throws JsonProcessingException {
+
+        return ResponseEntity.ok(authService.getBestRoleWithinProject(token, projectId));
+    }
 }
diff --git a/src/main/java/com/aolda/itda/exception/ErrorCode.java b/src/main/java/com/aolda/itda/exception/ErrorCode.java
index 6bcb643..0916e71 100644
--- a/src/main/java/com/aolda/itda/exception/ErrorCode.java
+++ b/src/main/java/com/aolda/itda/exception/ErrorCode.java
@@ -9,7 +9,10 @@ import org.springframework.http.HttpStatus;
 public enum ErrorCode {
 
     // User
-    INVALID_USER_INFO(HttpStatus.BAD_REQUEST, "잘못된 회원 정보입니다");
+    INVALID_USER_INFO(HttpStatus.BAD_REQUEST, "잘못된 회원 정보입니다"),
+
+    // Token
+    INVALID_TOKEN(HttpStatus.BAD_REQUEST, "잘못된 토큰입니다");
 
     private final HttpStatus status;
     private final String message;
diff --git a/src/main/java/com/aolda/itda/service/AuthService.java b/src/main/java/com/aolda/itda/service/AuthService.java
index 5f071ee..6fea01e 100644
--- a/src/main/java/com/aolda/itda/service/AuthService.java
+++ b/src/main/java/com/aolda/itda/service/AuthService.java
@@ -15,6 +15,9 @@ import lombok.RequiredArgsConstructor;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.*;
 import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpStatusCodeException;
+import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.*;
@@ -88,8 +91,15 @@ public class AuthService {
                     "token", token);
     }
 
-    // 특정 사용자의 프로젝트별 Role 반환
-    private List<ProjectRoleDTO> getRolesWithProjects(Map<String, String> user) throws JsonProcessingException {
+    // 특정 사용자의 특정 프로젝트 내 최고 권한 반환
+    public Map<String, String> getBestRoleWithinProject(String token, String projectId) throws JsonProcessingException {
+        return getBestRoleWithinProject(Map.of(
+                "id", validateTokenAndGetUserId(token),
+                "token", token),
+                projectId);
+    }
+
+    private Map<String, String> getBestRoleWithinProject(Map<String, String> user, String projectId) throws JsonProcessingException {
         String userId = user.get("id");
         String token = user.get("token");
 
@@ -97,7 +107,7 @@ public class AuthService {
             throw new CustomException(ErrorCode.INVALID_USER_INFO);
         }
 
-        String url = keystone + "/role_assignments?user.id=" + userId + "&effective&include_names=true";
+        String url = keystone + "/role_assignments?user.id=" + userId + "&effective&include_names=true&scope.project.id=" + projectId;
 
         HttpHeaders headers = new HttpHeaders();
         headers.set("X-Auth-Token", getAdminToken());
@@ -108,19 +118,23 @@ public class AuthService {
         JsonNode node = objectMapper.readTree(res.getBody());
         ArrayNode arrayNode = (ArrayNode) node.get("role_assignments");
 
-        List<ProjectRoleDTO> lists = new ArrayList<>();
+        String bestRole = "reader";
 
         for (JsonNode assignment : arrayNode) {
 
-            String projectName = assignment.path("scope").path("project").path("name").asText();
             String roleName = assignment.path("role").path("name").asText();
 
-            ProjectRoleDTO projectRoleDTO = new ProjectRoleDTO(projectName, roleName);
-            lists.add(projectRoleDTO);
+            if (roleName.equals("admin")) { // admin인 경우
+                bestRole = roleName;
+            } else if (roleName.equals("manager") && !bestRole.equals("admin")) { // 최고 권한이 admin이 아닌 경우
+                bestRole = roleName;
+            } else if (roleName.equals("member") && bestRole.equals("reader")) { // 최고 권한이 reader인 경우
+                bestRole = roleName;
+            }
 
         }
 
-        return lists;
+        return Map.of("role", bestRole);
     }
 
     // 관리자용 토큰 발행
@@ -129,6 +143,7 @@ public class AuthService {
         return user.get("token");
     }
 
+    // 특정 사용자의 참여 프로젝트 반환
     private List<ProjectIdAndNameDTO> getProjectsWithUser(Map<String, String> user) throws JsonProcessingException {
         String userId = user.get("id");
         String token = user.get("token");
@@ -156,4 +171,20 @@ public class AuthService {
         }
         return lists;
     }
+
+    private String validateTokenAndGetUserId(String token) throws JsonProcessingException {
+        String url = keystone + "/auth/tokens";
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("X-Auth-Token", getAdminToken());
+        headers.set("X-Subject-Token", token);
+        HttpEntity<String> requestEntity = new HttpEntity<>(headers);
+        ResponseEntity<String> res;
+        try {
+            res = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
+        } catch (HttpClientErrorException.NotFound e) {
+            throw new CustomException(ErrorCode.INVALID_TOKEN);
+        }
+        return objectMapper.readTree(res.getBody()).path("token").path("user").path("id").asText();
+
+    }
 }
-- 
GitLab