Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201

This commit is contained in:
Moon
2025-12-12 10:27:58 +09:00
9 changed files with 55 additions and 46 deletions

View File

@@ -2,8 +2,9 @@ package com.kamco.cd.kamcoback.auth;
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.List;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
public class CustomUserDetails implements UserDetails { public class CustomUserDetails implements UserDetails {
@@ -16,7 +17,7 @@ public class CustomUserDetails implements UserDetails {
@Override @Override
public Collection<? extends GrantedAuthority> getAuthorities() { public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList(); return List.of(new SimpleGrantedAuthority("ROLE_" + member.getUserRole()));
} }
@Override @Override

View File

@@ -7,9 +7,9 @@ import lombok.Getter;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum RoleType implements EnumType { public enum RoleType implements EnumType {
ROLE_ADMIN("관리자"), ADMIN("관리자"),
ROLE_LABELER("라벨러"), LABELER("라벨러"),
ROLE_REVIEWER("검수자"); REVIEWER("검수자");
private final String desc; private final String desc;
@@ -22,13 +22,4 @@ public enum RoleType implements EnumType {
public String getText() { public String getText() {
return desc; return desc;
} }
public static RoleType from(String value) {
for (RoleType type : values()) {
if (type.name().equalsIgnoreCase(value)) {
return type;
}
}
return null;
}
} }

View File

@@ -0,0 +1,19 @@
package com.kamco.cd.kamcoback.common.utils;
import com.kamco.cd.kamcoback.config.enums.EnumType;
public class Enums {
// code로 text
public static <E extends Enum<E> & EnumType> E fromId(Class<E> enumClass, String id) {
if (id == null) {
return null;
}
for (E e : enumClass.getEnumConstants()) {
if (id.equalsIgnoreCase(e.getId())) {
return e;
}
}
return null; // 못 찾으면 null
}
}

View File

@@ -168,12 +168,12 @@ public class GlobalExceptionHandler {
errorLog.getId()); errorLog.getId());
} }
@ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(AccessDeniedException.class) @ExceptionHandler(AccessDeniedException.class)
public ApiResponseDto<String> handlerAccessDeniedException( public ApiResponseDto<String> handlerAccessDeniedException(
AccessDeniedException e, HttpServletRequest request) { AccessDeniedException e, HttpServletRequest request) {
log.warn("[AccessDeniedException] resource :{} ", e.getMessage()); log.warn("[AccessDeniedException] resource :{} ", e.getMessage());
String codeName = "UNAUTHORIZED"; String codeName = "FORBIDDEN";
ErrorLogEntity errorLog = ErrorLogEntity errorLog =
saveErrorLogData( saveErrorLogData(
request, request,

View File

@@ -42,13 +42,25 @@ public class SecurityConfig {
customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용 customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용
.authorizeHttpRequests( .authorizeHttpRequests(
auth -> auth ->
auth.requestMatchers(HttpMethod.OPTIONS, "/**") auth
// ADMIN만 접근
.requestMatchers("/api/test/admin")
.hasRole("ADMIN")
// ADMIN, LABELER 접근
.requestMatchers("/api/test/label")
.hasAnyRole("ADMIN", "LABELER")
// ADMIN, REVIEWER 접근
.requestMatchers("/api/test/review")
.hasAnyRole("ADMIN", "REVIEWER")
.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll() // preflight 허용 .permitAll() // preflight 허용
.requestMatchers( .requestMatchers(
"/api/auth/signin", "/api/auth/signin",
"/api/auth/refresh", "/api/auth/refresh",
"/swagger-ui/**", "/swagger-ui/**",
"/api/members/{memberId}/password", "/api/members/*/password",
"/v3/api-docs/**") "/v3/api-docs/**")
.permitAll() .permitAll()
.anyRequest() .anyRequest()

View File

@@ -5,17 +5,4 @@ public interface EnumType {
String getId(); String getId();
String getText(); String getText();
// code로 text
static <E extends Enum<E> & EnumType> E fromId(Class<E> enumClass, String id) {
if (id == null) {
return null;
}
for (E e : enumClass.getEnumConstants()) {
if (id.equalsIgnoreCase(e.getId())) {
return e;
}
}
return null; // 못 찾으면 null
}
} }

View File

@@ -98,7 +98,6 @@ public class MapSheetMngDto {
@JsonFormatDttm private ZonedDateTime rgstEndDttm; @JsonFormatDttm private ZonedDateTime rgstEndDttm;
} }
@Schema(name = "DmlReturn", description = "영상관리 DML 수행 후 리턴") @Schema(name = "DmlReturn", description = "영상관리 DML 수행 후 리턴")
@Getter @Getter
@Setter @Setter

View File

@@ -2,8 +2,9 @@ package com.kamco.cd.kamcoback.members.dto;
import com.kamco.cd.kamcoback.common.enums.RoleType; import com.kamco.cd.kamcoback.common.enums.RoleType;
import com.kamco.cd.kamcoback.common.enums.StatusType; import com.kamco.cd.kamcoback.common.enums.StatusType;
import com.kamco.cd.kamcoback.common.utils.Enums;
import com.kamco.cd.kamcoback.common.utils.interfaces.EnumValid;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import com.kamco.cd.kamcoback.config.enums.EnumType;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
@@ -67,12 +68,12 @@ public class MembersDto {
} }
private String getUserRoleName(String roleId) { private String getUserRoleName(String roleId) {
RoleType type = EnumType.fromId(RoleType.class, roleId); RoleType type = Enums.fromId(RoleType.class, roleId);
return type.getText(); return type.getText();
} }
private String getStatusName(String status) { private String getStatusName(String status) {
StatusType type = EnumType.fromId(StatusType.class, status); StatusType type = Enums.fromId(StatusType.class, status);
return type.getText(); return type.getText();
} }
} }
@@ -83,9 +84,7 @@ public class MembersDto {
@AllArgsConstructor @AllArgsConstructor
public static class SearchReq { public static class SearchReq {
@Schema( @Schema(description = "전체, 관리자(ADMIN), 라벨러(LABELER), 검수자(REVIEWER)", example = "")
description = "전체, 관리자(ROLE_ADMIN), 라벨러(ROLE_LABELER), 검수자(ROLE_REVIEWER)",
example = "")
private String userRole; private String userRole;
@Schema(description = "키워드", example = "홍길동") @Schema(description = "키워드", example = "홍길동")
@@ -107,9 +106,9 @@ public class MembersDto {
@Setter @Setter
public static class AddReq { public static class AddReq {
@Schema(description = "관리자 유형", example = "ROLE_ADMIN") @Schema(description = "관리자 유형", example = "ADMIN")
@NotBlank @NotBlank
@Size(max = 50) @EnumValid(enumClass = RoleType.class, message = "userRole은 ADMIN, LABELER, REVIEWER만 가능합니다.")
private String userRole; private String userRole;
@Schema(description = "이름", example = "홍길동") @Schema(description = "이름", example = "홍길동")

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.test; package com.kamco.cd.kamcoback.test;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@@ -30,8 +31,8 @@ public class TestApiController {
content = @Content(schema = @Schema(implementation = ErrorResponse.class))) content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
}) })
@GetMapping("/admin") @GetMapping("/admin")
public String admin() { public ApiResponseDto<String> admin() {
return "I am administrator"; return ApiResponseDto.ok("I am administrator");
} }
@Operation(summary = "label test", description = "label test api") @Operation(summary = "label test", description = "label test api")
@@ -46,8 +47,8 @@ public class TestApiController {
content = @Content(schema = @Schema(implementation = ErrorResponse.class))) content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
}) })
@GetMapping("/label") @GetMapping("/label")
public String label() { public ApiResponseDto<String> label() {
return "Labeling is available."; return ApiResponseDto.ok("Labeling is available.");
} }
@Operation(summary = "review test", description = "review test api") @Operation(summary = "review test", description = "review test api")
@@ -62,7 +63,7 @@ public class TestApiController {
content = @Content(schema = @Schema(implementation = ErrorResponse.class))) content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
}) })
@GetMapping("/review") @GetMapping("/review")
public String review() { public ApiResponseDto<String> review() {
return "Review is available."; return ApiResponseDto.ok("Review is available.");
} }
} }