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

Spring Security

메소드 시큐리티

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

메소드 시큐리티

  • 서비스 계층을 직접 호출할 때 사용하는 보안 기능이다.
  • 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);
}
  • MethodSecurityConfig
@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

  • 백기선님의 스프링 시큐리티

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

Voter 커스텀 하기  (0) 2022.02.28
@AuthenticationPrincipal  (0) 2022.02.28
Custom DSL 적용  (0) 2022.02.28
Ajax 인증처이  (0) 2022.02.28
Custom Filter  (0) 2022.02.28