권한 체크 추가
This commit is contained in:
parent
a1ca9d1328
commit
e51837e6dd
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.goi.erp.common.exception;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(RuntimeException.class)
|
||||||
|
public ResponseEntity<?> handleRuntimeException(RuntimeException ex) {
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("error", ex.getMessage());
|
||||||
|
body.put("timestamp", LocalDateTime.now());
|
||||||
|
body.put("status", HttpStatus.BAD_REQUEST.value());
|
||||||
|
|
||||||
|
return ResponseEntity.badRequest().body(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(AccessDeniedException.class)
|
||||||
|
public ResponseEntity<String> handleAccessDenied(AccessDeniedException ex) {
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.goi.erp.common.permission;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Permission {
|
||||||
|
private PermissionEnums.Module module;
|
||||||
|
private PermissionEnums.Action action;
|
||||||
|
private PermissionEnums.Scope scope;
|
||||||
|
private final boolean all;
|
||||||
|
|
||||||
|
public boolean isAll() {
|
||||||
|
return all || module == PermissionEnums.Module.ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.goi.erp.common.permission;
|
||||||
|
|
||||||
|
public class PermissionChecker {
|
||||||
|
|
||||||
|
public static boolean canCreateCRM(PermissionSet set) {
|
||||||
|
if (set.hasAll()) return true;
|
||||||
|
return set.has(PermissionEnums.Module.C, PermissionEnums.Action.C);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canReadCRM(PermissionSet set) {
|
||||||
|
if (set.hasAll()) return true;
|
||||||
|
return set.has(PermissionEnums.Module.C, PermissionEnums.Action.R);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canUpdateCRM(PermissionSet set) {
|
||||||
|
if (set.hasAll()) return true;
|
||||||
|
return set.has(PermissionEnums.Module.C, PermissionEnums.Action.U);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canDeleteCRM(PermissionSet set) {
|
||||||
|
if (set.hasAll()) return true;
|
||||||
|
return set.has(PermissionEnums.Module.C, PermissionEnums.Action.D);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 범위까지 체크
|
||||||
|
public static boolean canReadCRMAll(PermissionSet set) {
|
||||||
|
if (set.hasAll()) return true;
|
||||||
|
return set.hasFull(
|
||||||
|
PermissionEnums.Module.C,
|
||||||
|
PermissionEnums.Action.R,
|
||||||
|
PermissionEnums.Scope.A
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.goi.erp.common.permission;
|
||||||
|
|
||||||
|
public class PermissionEnums {
|
||||||
|
|
||||||
|
public enum Module {
|
||||||
|
H, // HCM
|
||||||
|
C, // CRM
|
||||||
|
A, // ACC
|
||||||
|
O, // OPERATION
|
||||||
|
S, // SYSTEM
|
||||||
|
ALL // ADMIN
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
C, R, U, D
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Scope {
|
||||||
|
S, P, A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.goi.erp.common.permission;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PermissionParser {
|
||||||
|
|
||||||
|
public static PermissionSet parse(List<String> permissionStrings) {
|
||||||
|
|
||||||
|
List<Permission> list = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String str : permissionStrings) {
|
||||||
|
// ALL 권한 추가
|
||||||
|
if ("ALL".equalsIgnoreCase(str)) {
|
||||||
|
list.add(new Permission(PermissionEnums.Module.ALL, null, null, true));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 문자 세개 조합 인지 확인
|
||||||
|
String[] parts = str.split(":");
|
||||||
|
if (parts.length != 3) continue;
|
||||||
|
|
||||||
|
PermissionEnums.Module module = PermissionEnums.Module.valueOf(parts[0]);
|
||||||
|
PermissionEnums.Action action = PermissionEnums.Action.valueOf(parts[1]);
|
||||||
|
PermissionEnums.Scope scope = PermissionEnums.Scope.valueOf(parts[2]);
|
||||||
|
//
|
||||||
|
list.add(new Permission(module, action, scope, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PermissionSet(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.goi.erp.common.permission;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record PermissionSet(List<Permission> permissions) {
|
||||||
|
|
||||||
|
public boolean has(PermissionEnums.Module module,
|
||||||
|
PermissionEnums.Action action) {
|
||||||
|
return permissions.stream()
|
||||||
|
.anyMatch(p -> p.getModule() == module &&
|
||||||
|
p.getAction() == action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFull(PermissionEnums.Module module,
|
||||||
|
PermissionEnums.Action action,
|
||||||
|
PermissionEnums.Scope scope) {
|
||||||
|
return permissions.stream()
|
||||||
|
.anyMatch(p -> p.getModule() == module &&
|
||||||
|
p.getAction() == action &&
|
||||||
|
p.getScope().ordinal() >= scope.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAll() {
|
||||||
|
return permissions.stream().anyMatch(p -> p.isAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.goi.erp.controller;
|
package com.goi.erp.controller;
|
||||||
|
|
||||||
|
import com.goi.erp.common.permission.PermissionChecker;
|
||||||
|
import com.goi.erp.common.permission.PermissionSet;
|
||||||
import com.goi.erp.dto.CustomerRequestDto;
|
import com.goi.erp.dto.CustomerRequestDto;
|
||||||
import com.goi.erp.dto.CustomerResponseDto;
|
import com.goi.erp.dto.CustomerResponseDto;
|
||||||
import com.goi.erp.service.CustomerService;
|
import com.goi.erp.service.CustomerService;
|
||||||
|
|
@ -7,6 +9,8 @@ import com.goi.erp.service.CustomerService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -22,6 +26,12 @@ public class CustomerController {
|
||||||
// CREATE
|
// CREATE
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<CustomerResponseDto> createCustomer(@RequestBody CustomerRequestDto requestDto) {
|
public ResponseEntity<CustomerResponseDto> createCustomer(@RequestBody CustomerRequestDto requestDto) {
|
||||||
|
// 권한 체크
|
||||||
|
PermissionSet permissionSet = (PermissionSet) SecurityContextHolder.getContext().getAuthentication().getDetails();
|
||||||
|
if (!PermissionChecker.canCreateCRM(permissionSet)) {
|
||||||
|
throw new AccessDeniedException("You do not have permission to create CRM data");
|
||||||
|
}
|
||||||
|
|
||||||
CustomerResponseDto responseDto = customerService.createCustomer(requestDto);
|
CustomerResponseDto responseDto = customerService.createCustomer(requestDto);
|
||||||
return new ResponseEntity<>(responseDto, HttpStatus.CREATED);
|
return new ResponseEntity<>(responseDto, HttpStatus.CREATED);
|
||||||
}
|
}
|
||||||
|
|
@ -29,12 +39,24 @@ public class CustomerController {
|
||||||
// READ ALL
|
// READ ALL
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseEntity<List<CustomerResponseDto>> getAllCustomers() {
|
public ResponseEntity<List<CustomerResponseDto>> getAllCustomers() {
|
||||||
|
// 권한 체크
|
||||||
|
PermissionSet permissionSet = (PermissionSet) SecurityContextHolder.getContext().getAuthentication().getDetails();
|
||||||
|
if (!PermissionChecker.canReadCRMAll(permissionSet)) {
|
||||||
|
throw new AccessDeniedException("You do not have permission to read all CRM data");
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseEntity.ok(customerService.getAllCustomers());
|
return ResponseEntity.ok(customerService.getAllCustomers());
|
||||||
}
|
}
|
||||||
|
|
||||||
// READ ONE
|
// READ ONE
|
||||||
@GetMapping("/{uuid}")
|
@GetMapping("/{uuid}")
|
||||||
public ResponseEntity<CustomerResponseDto> getCustomer(@PathVariable UUID uuid) {
|
public ResponseEntity<CustomerResponseDto> getCustomer(@PathVariable UUID uuid) {
|
||||||
|
// 권한 체크
|
||||||
|
PermissionSet permissionSet = (PermissionSet) SecurityContextHolder.getContext().getAuthentication().getDetails();
|
||||||
|
if (!PermissionChecker.canReadCRM(permissionSet)) {
|
||||||
|
throw new AccessDeniedException("You do not have permission to read CRM data");
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseEntity.ok(customerService.getCustomerByUuid(uuid));
|
return ResponseEntity.ok(customerService.getCustomerByUuid(uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,12 +65,24 @@ public class CustomerController {
|
||||||
public ResponseEntity<CustomerResponseDto> updateCustomer(
|
public ResponseEntity<CustomerResponseDto> updateCustomer(
|
||||||
@PathVariable UUID uuid,
|
@PathVariable UUID uuid,
|
||||||
@RequestBody CustomerRequestDto requestDto) {
|
@RequestBody CustomerRequestDto requestDto) {
|
||||||
|
// 권한 체크
|
||||||
|
PermissionSet permissionSet = (PermissionSet) SecurityContextHolder.getContext().getAuthentication().getDetails();
|
||||||
|
if (!PermissionChecker.canUpdateCRM(permissionSet)) {
|
||||||
|
throw new AccessDeniedException("You do not have permission to update CRM data");
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseEntity.ok(customerService.updateCustomer(uuid, requestDto));
|
return ResponseEntity.ok(customerService.updateCustomer(uuid, requestDto));
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
@DeleteMapping("/{uuid}")
|
@DeleteMapping("/{uuid}")
|
||||||
public ResponseEntity<Void> deleteCustomer(@PathVariable UUID uuid) {
|
public ResponseEntity<Void> deleteCustomer(@PathVariable UUID uuid) {
|
||||||
|
// 권한 체크
|
||||||
|
PermissionSet permissionSet = (PermissionSet) SecurityContextHolder.getContext().getAuthentication().getDetails();
|
||||||
|
if (!PermissionChecker.canDeleteCRM(permissionSet)) {
|
||||||
|
throw new AccessDeniedException("You do not have permission to delete CRM data");
|
||||||
|
}
|
||||||
|
|
||||||
customerService.deleteCustomer(uuid);
|
customerService.deleteCustomer(uuid);
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ import io.jsonwebtoken.security.Keys;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.goi.erp.common.permission.PermissionParser;
|
||||||
|
import com.goi.erp.common.permission.PermissionSet;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
@ -95,6 +98,16 @@ public class JwtService {
|
||||||
.getBody();
|
.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission Set 변환
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public PermissionSet getPermissions(String token) {
|
||||||
|
Claims claims = extractAllClaims(token);
|
||||||
|
List<String> permissions = claims.get("permissions", List.class);
|
||||||
|
return PermissionParser.parse(permissions);
|
||||||
|
}
|
||||||
|
|
||||||
private Key getSignInKey() {
|
private Key getSignInKey() {
|
||||||
byte[] keyBytes = Decoders.BASE64.decode(secretKey); // auth-service와 동일한 Base64 secret
|
byte[] keyBytes = Decoders.BASE64.decode(secretKey); // auth-service와 동일한 Base64 secret
|
||||||
return Keys.hmacShaKeyFor(keyBytes);
|
return Keys.hmacShaKeyFor(keyBytes);
|
||||||
|
|
@ -104,7 +117,7 @@ public class JwtService {
|
||||||
JwtService jwtService = new JwtService();
|
JwtService jwtService = new JwtService();
|
||||||
jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8=";
|
jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8=";
|
||||||
|
|
||||||
String token = "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdE5hbWUiOiJIeW9KaW4iLCJsYXN0TmFtZSI6IkFobiIsInBlcm1pc3Npb25zIjpbIkFMTCJdLCJyb2xlcyI6WyJBZG1pbiJdLCJzdWIiOiJhMjM4ZWQ0OC03OGRjLTQ2YWEtOWNiMC1hNWYxZGQyZDJmMTMiLCJpYXQiOjE3NjM1NzE2ODYsImV4cCI6MTc2MzY1ODA4Nn0.0fQT-I4dqHMapIEbxfy8X_SdCReYhUy6djnXUzw4gWc";
|
String token = "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdE5hbWUiOiJIeW9qaW4iLCJsYXN0TmFtZSI6IkFobiIsInBlcm1pc3Npb25zIjpbIkFMTCJdLCJyb2xlcyI6WyJBZG1pbiJdLCJzdWIiOiJhMjM4ZWQ0OC03OGRjLTQ2YWEtOWNiMC1hNWYxZGQyZDJmMTMiLCJpYXQiOjE3NjM2NDYzNzQsImV4cCI6MTc2MzczMjc3NH0.HwFZeNbxVldcBeiqc3TUO3x5on2Quy7_Yd_HTkIfOR4";
|
||||||
|
|
||||||
// user 정보
|
// user 정보
|
||||||
Claims claims = jwtService.extractAllClaims(token);
|
Claims claims = jwtService.extractAllClaims(token);
|
||||||
|
|
@ -115,7 +128,7 @@ public class JwtService {
|
||||||
System.out.println("IssuedAt: " + claims.getIssuedAt());
|
System.out.println("IssuedAt: " + claims.getIssuedAt());
|
||||||
System.out.println("Expiration: " + claims.getExpiration());
|
System.out.println("Expiration: " + claims.getExpiration());
|
||||||
System.out.println("FirstName: " + claims.get("firstName", String.class));
|
System.out.println("FirstName: " + claims.get("firstName", String.class));
|
||||||
System.out.println("LastName: " + claims.get("LastName", String.class));
|
System.out.println("LastName: " + claims.get("lastName", String.class));
|
||||||
|
|
||||||
// 모든 Claims 확인
|
// 모든 Claims 확인
|
||||||
// Claims claims = Jwts.parserBuilder()
|
// Claims claims = Jwts.parserBuilder()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue