1. Role 엔티티 추가
새로운 Role 엔티티를 생성하여 권한 정보를 관리합니다.
package net.macaronics.springboot.webapp.entity;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "tbl_roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Long id;
@Enumerated(EnumType.STRING)
@Column(nullable = false, unique = true)
private RoleType name;
public Role(RoleType name) {
this.name = name;
}
}
그리고 RoleType enum은 다음과 같이 선언합니다:
package net.macaronics.springboot.webapp.enums;
public enum RoleType {
USER, ADMIN, MANAGER, SUPPORT
}
2. User 엔티티 수정 - 다대다 관계 설정
여러 권한을 가질 수 있도록 User 엔티티를 수정하여 Role과 다대다 관계를 설정합니다.
package net.macaronics.springboot.webapp.entity;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(name = "tbl_users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(nullable = false, unique = true)
private String username;
private String password;
private String name;
@Column(unique = true)
private String email;
private LocalDate birthDate;
// 다대다 관계 설정
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
// 권한 추가 메소드
public void addRole(Role role) {
this.roles.add(role);
}
}
@ManyToMany를 사용해 User와 Role이 다대다 관계임을 설정하고, 연결 테이블 user_roles를 통해 관계를 맺습니다.
3. 권한 설정 및 검증
다양한 권한을 부여하고 검증하기 위해 다음을 수행할 수 있습니다.
- 권한 부여: 사용자 생성 시 필요한 권한을 User 객체에 추가합니다.
- 권한 검증: Spring Security의 권한 체크 기능을 통해 API별로 필요한 권한을 설정하고 검증합니다.
4. Spring Security 설정
각 권한별로 접근을 제한하려면 Spring Security 설정을 통해 권한 기반 접근 제어를 적용할 수 있습니다.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/manager/**").hasRole("MANAGER")
.antMatchers("/support/**").hasRole("SUPPORT")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN", "MANAGER", "SUPPORT")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.logout();
}
}
여기서 hasRole() 메소드를 사용해 특정 URL에 대해 해당 역할을 가진 사용자만 접근하도록 설정할 수 있습니다.
5. 예제 - 사용자 권한 추가
예를 들어, 새로운 사용자를 만들면서 ADMIN과 MANAGER 권한을 부여하려면 아래와 같은 방식으로 사용 가능합니다.
// 예시: 새로운 사용자를 생성하고 권한 부여
User user = new User();
user.setUsername("testUser");
user.setPassword("password");
// 권한 추가
Role adminRole = roleRepository.findByName(RoleType.ADMIN).orElseThrow();
Role managerRole = roleRepository.findByName(RoleType.MANAGER).orElseThrow();
user.addRole(adminRole);
user.addRole(managerRole);
userRepository.save(user);
RoleRepository
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import net.macaronics.springboot.webapp.entity.Role;
import net.macaronics.springboot.webapp.enums.RoleType;
public interface RoleRepository extends JpaRepository<Role, Long>{
Optional<Role> findByName(RoleType roleType);
}
UserService
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import net.macaronics.springboot.webapp.dto.user.UserLoginFormDTO;
import net.macaronics.springboot.webapp.dto.user.UserResponse;
import net.macaronics.springboot.webapp.dto.user.UserUpdateFormDTO;
import net.macaronics.springboot.webapp.entity.Role;
import net.macaronics.springboot.webapp.entity.User;
import net.macaronics.springboot.webapp.enums.RoleType;
import net.macaronics.springboot.webapp.exception.ResourceNotFoundException;
import net.macaronics.springboot.webapp.repository.RoleRepository;
@Service
@RequiredArgsConstructor
@Transactional
public class UserService {
private final RoleRepository roleRepository;
//권한 추가
public void addSupportRoleToUser(User user, RoleType roleType) {
// RoleType.SUPPORT 권한을 RoleRepository에서 가져오기
Role supportRole = roleRepository.findByName(roleType)
.orElseThrow(() -> new IllegalArgumentException("RoleType SUPPORT not found"));
// User 객체에 SUPPORT 권한 추가
user.addRole(supportRole);
}
}
PrincipalDetails
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Getter;
import net.macaronics.springboot.webapp.entity.Role;
import net.macaronics.springboot.webapp.entity.User;
@Getter
public class PrincipalDetails implements UserDetails {
@Serial
private static final long serialVersionUID = 1L;
private final User user;
private final Long id;
private final String username;
private final Set<Role> roles;
public PrincipalDetails(User user) {
this.user = user;
this.id = user.getId();
this.username = user.getUsername();
this.roles = user.getRoles(); // Set<Role>을 가져옴
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream()
.map(role -> new SimpleGrantedAuthority(role.getName().name())) // RoleType을 가져와서 GrantedAuthority로 변환
.collect(Collectors.toList());
}
public List<String> getRoleNames() {
return roles.stream()
.map(role -> role.getName().name()) // Role 엔티티에서 이름을 가져오는 방법에 따라 다름
.collect(Collectors.toList());
}
/**
* 사용자를 인증하는 데 사용된 암호를 반환합니다.
*/
@Override
public String getPassword() {
return user.getPassword();
}
/**
* 사용자를 인증하는 데 사용된 사용자 이름을 반환합니다. null을 반환할 수 없습니다.
*/
@Override
public String getUsername() {
return user.getUsername();
}
/**
* 사용자의 계정이 만료되었는지 여부를 나타냅니다. 만료된 계정은 인증할 수 없습니다.
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 사용자가 잠겨 있는지 또는 잠금 해제되어 있는지 나타냅니다. 잠긴 사용자는 인증할 수 없습니다.
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 사용자의 자격 증명(암호)이 만료되었는지 여부를 나타냅니다. 만료된 자격 증명은 인증을 방지합니다.
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 사용자가 활성화되었는지 비활성화되었는지 여부를 나타냅니다. 비활성화된 사용자는 인증할 수 없습니다.
*/
@Override
public boolean isEnabled() {
// 우리 사이트 1년동안 회원이 로그인을 안하면!! 휴먼 계정으로 하기로 함.
// 현재시간-로긴시간=>1년을 초과하면 return false;
return true;
}
}
이렇게 구성하면 사용자는 여러 권한을 가질 수 있으며, Spring Security를 통해 각 권한별 접근 제어를 세밀하게 설정할 수 있습니다.
더미 데이터
-- tbl_users 데이터 삽입
INSERT INTO tbl_users (username, password, name, email, birth_date) VALUES
('user1', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저1', 'user1@gmail.com', '1994-09-29'),
('user2', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저2', 'user2@gmail.com', '2000-10-29'),
('user3', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저3', 'user3@gmail.com', '1995-09-29'),
('user4', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저4', 'user4@gmail.com', '1999-09-29'),
('user5', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저5', 'user5@gmail.com', '2008-09-29'),
('user6', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저6', 'user6@gmail.com', '2007-09-29'),
('user7', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저7', 'user7@gmail.com', '2006-09-29'),
('user8', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저8', 'user8@gmail.com', '2015-09-29'),
('user9', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저9', 'user9@gmail.com', '2012-09-29'),
('user10', '$2a$10$8VKmqNwV0x/bQEN8Z54w7uUpLPTGeHgoJR73dyH2S6ZxoHkVkxGSm', '유저10', 'user10@gmail.com', '2008-09-29');
-- tbl_roles 데이터 삽입
INSERT INTO tbl_roles (name) VALUES
('USER'),
('ADMIN'),
('MANAGER'),
('SUPPORT');
-- tbl_user_roles 데이터 삽입 (USER 역할 할당)
INSERT INTO user_roles (user_id, role_id) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 1),
(7, 1),
(8, 1),
(9, 1),
(10, 1);
-- tbl_todos 데이터 삽입
INSERT INTO tbl_todos (user_id, title, description, target_date, done) VALUES
(1, '첫 번째 할 일', '첫 번째 할 일', '2024-09-30', false),
(1, '두 번째 할 일', '두 번째 할 일', '2024-10-01', false),
(1, '세 번째 할 일', '세 번째 할 일', '2024-10-02', true),
(1, '네 번째 할 일', '네 번째 할 일', '2024-10-03', false),
(1, '다섯 번째 할 일', '다섯 번째 할 일', '2024-10-04', true),
(1, '여섯 번째 할 일', '여섯 번째 할 일', '2024-10-05', false),
(1, '일곱 번째 할 일', '일곱 번째 할 일', '2024-10-06', true),
(1, '여덟 번째 할 일', '여덟 번째 할 일', '2024-10-07', false),
(1, '아홉 번째 할 일', '아홉 번째 할 일', '2024-10-08', true),
(1, '열 번째 할 일', '열 번째 할 일', '2024-10-09', false),
(2, '할 일 11', '할 일 11', '2024-10-10', true),
(2, '할 일 12', '할 일 12', '2024-10-11', false),
(2, '할 일 13', '할 일 13', '2024-10-12', true),
(2, '할 일 14', '할 일 14', '2024-10-13', false),
(2, '할 일 15', '할 일 15', '2024-10-14', true),
(2, '할 일 16', '할 일 16', '2024-10-15', false),
(2, '할 일 17', '할 일 17', '2024-10-16', true),
(2, '할 일 18', '할 일 18', '2024-10-17', false),
(2, '할 일 19', '할 일 19', '2024-10-18', true),
(2, '할 일 20', '할 일 20', '2024-10-19', false),
(3, '할 일 21', '할 일 21', '2024-10-20', true),
(3, '할 일 22', '할 일 22', '2024-10-21', false),
(3, '할 일 23', '할 일 23', '2024-10-22', true),
(3, '할 일 24', '할 일 24', '2024-10-23', false),
(3, '할 일 25', '할 일 25', '2024-10-24', true),
(3, '할 일 26', '할 일 26', '2024-10-25', false),
(3, '할 일 27', '할 일 27', '2024-10-26', true),
(3, '할 일 28', '할 일 28', '2024-10-27', false),
(3, '할 일 29', '할 일 29', '2024-10-28', true),
(3, '할 일 30', '할 일 30', '2024-10-29', false),
-- (나머지 할 일 데이터 계속해서 추가...)
(4, '할 일 31', '할 일 31', '2024-10-30', true),
(5, '할 일 41', '할 일 41', '2024-11-09', true),
(6, '할 일 51', '할 일 51', '2024-11-19', true),
(7, '할 일 61', '할 일 61', '2024-11-29', true),
(8, '할 일 71', '할 일 71', '2024-12-09', true),
(9, '할 일 81', '할 일 81', '2024-12-19', true),
(10, '할 일 91', '할 일 91', '2024-12-29', true);

















댓글 ( 0)
댓글 남기기