모르지 않다는 것은 아는것과 다르다.

Spring Security

권한 계층 적용하기

채마스 2022. 2. 28. 20:53

개요

  • 상윈 권한이 하위 권한을 포함할 수 있도록 설정할 수 있다.





권한 계층 적용

  • RoleHierarchy 클래스는 상위 계층 Role은 하위 계층 Role의 자원에 접근 가능하도록 설정할 수 있는 클래스다.
  • 예를들어 ROLE_ADMIN > ROLE_MANAGER > ROLE_USER 일 경우 ROLE_ADMIN 만 있으면 하위 ROLE 의 권한을 모두 포함되게 설정할 수 있다.
  • ROLE_HIERARCHY 테이블을 보면 부모와 자식 권한이 매핑되어 저장되어 있다.
  • ROLE_HIERARCHY 테이블에 저장된 정보는 정해진 format에 따라 포매팅 되어야 한다.
  • 포매팅된 데이터는 RoleHierarchy 가 가지고 있게 된다.
  • RoleHierarchyVoter 는 RoleHierarchy 를 생성자로 받으며 RoleHierarchy 에서 설정된 규칙이 적용되어 심사한다.
    • ">" 와 줄바꿈을 꼭 지켜서 포매팅해야된다.





코드 구현

  • RoleHierarchy 클래스 구현
@Entity
@Table(name="ROLE_HIERARCHY")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class RoleHierarchy implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "child_name")
    private String childName;

    @ManyToOne(cascade = {CascadeType.ALL},fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_name", referencedColumnName = "child_name")
    private RoleHierarchy parentName;

    @OneToMany(mappedBy = "parentName", cascade={CascadeType.ALL})
    private Set<RoleHierarchy> roleHierarchy = new HashSet<RoleHierarchy>();
}
  • 다음과 같이 조인컬럼을 형성해서 상위 계층 Role은 하위 계층 Role의 자원에 접근 가능하도록 엔티티를 구성한다.
  • 디비로 부터 권한 정보를 가져와서 정보를 포매팅하는 클래스인 RoleHierarchyServiceImpl 를 구현한다.
@Service
public class RoleHierarchyServiceImpl implements RoleHierarchyService {

    @Autowired
    private RoleHierarchyRepository roleHierarchyRepository;

    @Transactional
    @Override
    public String findAllHierarchy() {

        List<RoleHierarchy> rolesHierarchy = roleHierarchyRepository.findAll();

        Iterator<RoleHierarchy> itr = rolesHierarchy.iterator();
        StringBuffer concatedRoles = new StringBuffer();
        while (itr.hasNext()) {
            RoleHierarchy model = itr.next();
            if (model.getParentName() != null) {
                concatedRoles.append(model.getParentName().getChildName());
                concatedRoles.append(" > ");
                concatedRoles.append(model.getChildName());
                concatedRoles.append("\n");
            }
        }
        return concatedRoles.toString();

    }
}
  • 디비에서 권한정보를 불러온다.
  • 권한 정보를 바탕으로 권한 계층을 ">" 로 설정하고 줄바꿈도 반드시 해줘서 포매팅 한다.





Config 파일 설정

    private AccessDecisionManager affirmativeBased() {
        AffirmativeBased affirmativeBased = new AffirmativeBased(getAccessDecisionVoters());
        return affirmativeBased;
    }

    private List<AccessDecisionVoter<?>> getAccessDecisionVoters() {

        List<AccessDecisionVoter<? extends Object>> accessDecisionVoters = new ArrayList<>();
        accessDecisionVoters.add(roleVoter());

        return accessDecisionVoters;
    }

    @Bean
    public AccessDecisionVoter<? extends Object> roleVoter() {

        RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());
        return roleHierarchyVoter;
    }

    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        return roleHierarchy;
    }
  • AccessDecisionManager 의 구현체인 affirmativeBased 에서 AccessDecisionVoter 를 설정해야한다.
  • RoleHierarchyVoter 의 생성자로 RoleHierarchy 객체를 인자로 넘긴다. -> 정확히는 RoleHierarchy 의 구현체인 RoleHierarchyImpl 을 넘긴다.
  • 그렇게 되면 RoleHierarchyImpl 의 getReachableGrantedAuthorities 에서 상위 권한이 하위 권한을 포함하도록 설정되는 작업이 이루어 진다.
  • RoleHierarchyImpl 의 setHierarchy 메소드에 계층을 포매팅한 정보를 넣어줘야 한다.
  • 포매팅은 위에서 구현한 RoleHierarchyServiceImpl 의 findAllHierarchy 메소드에서 진행했다.
  • 포매팅한 정보는 원하는 시점에 넣어주면 되는데, 애플리케이션이 실행될때 넣어주도록 설정하겠다.
  • 아래와 같이 설정할 수 있다.
@Component
public class SecurityInitializer implements ApplicationRunner {

    @Autowired
    private RoleHierarchyService roleHierarchyService;

    @Autowired
    private RoleHierarchyImpl roleHierarchy;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        String allHierarchy = roleHierarchyService.findAllHierarchy();
        roleHierarchy.setHierarchy(allHierarchy);
    }
}
  • run 메소드 안에 SecurityConfig 파일에서 빈으로 등록한 RoleHierarchyImpl 의 setHierarchy 메소드를 통해서 roleHierarchyService 로부터 얻은 계층 정보를 넘겨주면, 서버가 구동될때 계층이 설정된다.




REFERENCES

  • 정수원님의 스프링시큐리티

'Spring Security' 카테고리의 다른 글

Method 시큐리티 프로세스 커스텀  (0) 2022.02.28
URL 시큐리티 프로세스 커스텀  (0) 2022.02.28
Voter 커스텀 하기  (0) 2022.02.28
@AuthenticationPrincipal  (0) 2022.02.28
메소드 시큐리티  (0) 2022.02.28