Java Spring Security 계층 권한 적용

떡ol·2023년 5월 29일
0

 .antMatchers("/mypage").hasRole("USER")
 .antMatchers("/messages").hasRole("MANAGER")
 .antMatchers("/config").hasRole("ADMIN")

다음과 같은 인가 정책을 작성하고 ADMIN계정을 로그인하면 mypagemessages 페이지를 이용할 수 없습니다. USERMANAGER의 권한이 없기 때문입니다.
하지만 RoleHierarchyVoter를 적용하면 해결이 가능하집니다.

RoleHierarchyService, Repository 만들기

해당 포스트에서는 @Service과 @Repository를 만드는 과정은 제외하겠습니다.
단, 위에 그림에서 보이듯 RoleHierarchy를 사용하기 위해서는 계층 구조를 >로 구분하여 String값으로 보내야 합니다.

@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();
        StringBuilder concatedRoles= new StringBuilder();
        while (itr.hasNext()){
            RoleHierarchy roleHierarchy = itr.next();
            if(roleHierarchy.getParentName() != null){
                concatedRoles.append(roleHierarchy.getParentName().getChildName());
                concatedRoles.append(" > ");
                concatedRoles.append(roleHierarchy.getChildName());
                concatedRoles.append("\n");
            }
        }
        return concatedRoles.toString();
    }
}

WebConfingureAdapter 수정

이전 포스트에서 계속 언급 되었던 AffirmativeBasedgetAccessDecisionVoters을 수정 합니다.

    private List<AccessDecisionVoter<?>> getAccessDecisionVoters() {
        List<AccessDecisionVoter<? extends Object>> accessDecisionVoters = new ArrayList<>();
        accessDecisionVoters.add(roleVoter());
        //return Arrays.asList(new RoleVoter()); //이젠 이게 필요없습니다.
        return accessDecisionVoters;
    }
	// 계층 구조를 만드는 Bean들 ...
    @Bean
    public AccessDecisionVoter<? extends Object> roleVoter() {
        RoleHierarchyVoter roleHierarchyVoter = new RoleHierarchyVoter(roleHierarchy());
        return roleHierarchyVoter;
    }
	// 계층 구조를 만드는 Bean들 ...
    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        return roleHierarchy;
    }

이때 Spring Security의RoleHierarchyImpl을 확인해보면 다음과 같은 매서드를 갖추고 있습니다.


public class RoleHierarchyImpl implements RoleHierarchy {
	//...
    public RoleHierarchyImpl() {
    }

    public void setHierarchy(String roleHierarchyStringRepresentation) {
        this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;
        if (logger.isDebugEnabled()) {
            logger.debug("setHierarchy() - The following role hierarchy was set: " + roleHierarchyStringRepresentation);
        }

        this.buildRolesReachableInOneStepMap();
        this.buildRolesReachableInOneOrMoreStepsMap();
    }
    //...

여기서 setHierarchy부분에 우리가 만들어 놓은 findAllHierarchy의 String값을 셋팅해주면 됩니다. setting 할때의 방법은 여러분에 몫입니다. 초기화할때 setting을 해줄건지, Application 런타임 후 작업할건지 원하시는대로, 본인의 프로젝트에 맞게 하시면 됩니다.
저는 SecurityInitializer.class 파일을 만들어 ApplicationRunner로 적용하였습니다.

@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);
    }
}
profile
하이

0개의 댓글