메소드 시큐리티
- 서비스 계층을 직접 호출할 때 사용하는 보안 기능이다.
- AOP 를 이용해서 적용시킨 것이다.
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class MethodSecurity extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
accessDecisionManager.getDecisionVoters().add(new RoleHierarchyVoter(roleHierarchy));
return accessDecisionManager;
}
}
- @Secured와 @RollAllowed
- 메소드 호출 이전에 권한을 확인한다.
- 스프링 EL을 사용하지 못한다.
- @PreAuthorize와 @PostAuthorize
- 메소드 호출 이전 이후에 권한을 확인할 수 있다.
- 스프링 EL을 사용하여 메소드 매개변수와 리턴값을 검증할 수 있다.
- 아래와 같이 파라미터를 이용할 수 있다.
@PreAuthorize("#username == authentication.principal.username")
public String getMyRoles(String username){
//...
}
@PostAuthorize("returnObject.username == authentication.principal.nickname")
public CustomUser loadUserDetail(String username){
return userRoleRepository.loadUserByUserName(username);
}
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
AffirmativeBased accessDecisionManager = (AffirmativeBased) super.accessDecisionManager();
accessDecisionManager.getDecisionVoters().add(new RoleHierarchyVoter(roleHierarchy));
return accessDecisionManager;
}
}
- 웹용이 아닌 범용적(예를 들어 데스크톱)으로 사용할 configuration 정의
- Hierarchy 를 설정하기 위해서는 위와 같이 상속받아 메소드를 재정의하여 설정해준다.
테스트 코드 작성
- 아래와 같이 테스트 코드를 작성할 수 있다. (Junit 4)
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleServiceTest {
@Autowired
SampleService sampleService;
@Autowired
AccountService accountService;
@Autowired
AuthenticationManager authenticationManager;
@Test
public void dashboard() {
// 계정을 생성
Account account = new Account();
account.setRole("USER");
account.setUsername("jake");
account.setPassword("123");
accountService.createNew(account);
UserDetails userDetails = accountService.loadUserByUsername("jake");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails, "123");
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
sampleService.dashboard();
}
}
- 위의 코드를 실행시킬때, MethodSecurityConfig 를 정의해 주지 않았다면, null 포인트 에러가 발생한다.
- 그 이유는 웹을 통한 테스트가 아니기 때문이다. -> GlobalMethodSecurityConfiguration 를 상속한 config 파일을 정의해 줘야한다.
- 목 객체를 만드는 과정은 아래와 같이 @WithMockUser 로 대체할 수 있다.
@Test
@WithMockUser
public void dashboard(){
sampleService.dashboard();
}
REFERENCES