.antMatchers("/mypage").hasRole("USER")
.antMatchers("/messages").hasRole("MANAGER")
.antMatchers("/config").hasRole("ADMIN")
다음과 같은 인가 정책을 작성하고 ADMIN
계정을 로그인하면 mypage
와 messages
페이지를 이용할 수 없습니다. USER
와 MANAGER
의 권한이 없기 때문입니다.
하지만 RoleHierarchyVoter
를 적용하면 해결이 가능하집니다.
해당 포스트에서는 @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();
}
}
이전 포스트에서 계속 언급 되었던 AffirmativeBased
의 getAccessDecisionVoters
을 수정 합니다.
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);
}
}