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