개발바닥곰발바닥
Published 2022. 5. 11. 00:14
JPA Column Enum으로 관리하기 JAVA/Spring
728x90

1. JPA Column Enum으로 관리하기

회원 정보인 Member Entity에서 권한을 관리하는 state라는 필드가 있는데 기존에는 state를 String으로 사용했었다. 그런데 String으로 사용하면 생길 수 있는 문제점이 있는데, 현재 진행중인 프로젝트의 권한은 USER, ADMIN, ANONYMOUS(승인되지 않은 유저) 이렇게 세 개로 관리하는데 권한 변경하는 API에서 Request에 권한을 받을 때 잘 못된 값이 들어 올 수 있다는 위험이 존재한다.

이런 문제를 사전에 차단하기 위해 권한에 대한 Enum을 만들어 잘못된 입력 값이 들어오면 막아주도록 설계를 변경했다.

1.1. ROLE Enum

<java />
public enum Role { ROLE_USER("ROLE_USER"), ROLE_ANONYMOUS("ROLE_ANONYMOUS"), ROLE_ADMIN("ROLE_ADMIN"); String role; Role(String role) { this.role = role; } public String value() { return role; } }

1.2. Member Entity

<java />
public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name") private String name; @Column(name = "email") private String email; @Column(name = "department") private String department; @Column(name = "state") @Enumerated(EnumType.STRING) private Role state; /*...*/ }

Entity에 있는 Enum이 데이터베이스에 그대로 저장되려면 @Enumerated(EnumType.STRING) 어노테이션을 사용하면 DB에 Enum 값이 그대로 String으로 저장된다.

1.3. CustomUserDetails

Spring Security를 사용하는 경우

CustomUserDetails의 createUserDetails에서 권한을 넣어주는 부분에서 Enum을 toString 메소드로 String으로 변환한 뒤에 SimpleGrantedAuthority로 권한을 지정해준다.

<java />
@Service @RequiredArgsConstructor public class CustomUserDetailsService implements UserDetailsService { private final MemberRepository memberRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return memberRepository.findByLoginId(username).map(this::createUserDetails) .orElseThrow(() -> new UsernameNotFoundException(username + "는 데이터베이스에 없는 데이터입니다.")); } private UserDetails createUserDetails(Member member) { String role = member.getState().value(); GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role); return new org.springframework.security.core.userdetails.User( String.valueOf(member.getId()), member.getPassword(), Collections.singleton(grantedAuthority) ); } }

1.4. SecurityConfig

Security에서 admin에 대해 ADMIN 권한이 있어야만 접근이 가능하도록 설정할 수 있다.

권한을 지정할 때는 “ROLE_ADMIN”이었지만 Spring Security에서 prefix를 자동으로 "ROLE_"을 넣어주므로 이 때 hasRole에는 ROLE을 제외하고 뒷 부분인 ADMIN만 써주면 된다.

<java />
.authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**/*").permitAll() .antMatchers("/image/**").permitAll() .antMatchers("/auth/**").permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers(HttpMethod.GET, "/product/**").permitAll() // 상품쪽은 조회만 권한없이 가능

1.5. 번외. No enum constant 오류

이렇게 enum으로 변환하다가 가끔 No enum constant enum.값 이라는 에러가 발생할 때가 있다.

이 에러가 발생하는 원인은 Entity에서 사용하는 Enum에 존재하지 않는 값이 데이터베이스의 해당 컬럼에 존재할 경우 발생하는 오류이다. (대소문자를 구분한다.)

이 에러를 해결하려면 Enum에 존재하지 않는 값을 DB에서 삭제하거나, 반대로 DB에 존재하는 값을 Enum에 추가시켜주면 해결된다.

728x90
profile

개발바닥곰발바닥

@bestinu

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!