Git :)

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ch16 전역 메서드 보안 : 사전 및 사후 권한 부여
    IT 서적/Spring Security In Action 2024. 1. 11. 16:37

    # 전역 메서드 보안 활성화

    • 스프링 시큐리티에서는 웹 애플리케이션과 웹이 아닌 애플리케이션의 권한 부여를 구성할 수 있으며 이를 '전역 메서드 보안' 이라고 부른다.
    • 방법은 크게 두 가지가 있다.
      • 호출 권한 부여
      • 필터링

     

    # 호출 권한 부여의 이해

    • 호출 권한 부여 방식은 메서드를 호출할 수 있는지를 결정하거나 메서드를 호출하도록 허용한 후 호출자가 메서드에서 반환된 값에 액세스할 수 있는지를 결정하는 권한 부여 규칙을 적용하는 것을 말한다.
    • 전역 메서드 보안을 활성화하면 스프링 애스펙트 하나가 활성화된다.
    • 이를 그림으로 나타내면 아래와 같다.

    • 스프링 프레임워크의 구현은 상당수가 AOP(관점 지향 프로그래밍)에 의존한다.
    • 전역 메서드 보안은 애스펙트에 의존하는 스프링 애플리케이션의 많은 구성 요소 중 하나다.

     

    # 프로젝트에서 전역 메서드 보안 활성화

    • 스프링 시큐리티에서 전역 메서드 보안은 기본적으로 활성화되지 않고 먼저 활성화해야 이용할 수 있지만 그 방법은 간단하며 구성 클레스에 @EnableGlobalMethodSecurity 어노테이션을 추가하면 된다.
    • 전연 메서드 보안에는 권한 부여 규칙을 정의하는 세 가지 접근 방식이 있다.
      • 사전/사후 권한 부여 어노테이션
      • JSR 250 어노테이션(@RoleAllowed)
      • @Secured 어노테이션
    • 거의 모든 상황에 사전/사후 권한 부여 어노테이션을 이용하므로 이 방법에 대해서 알아보자.
    • 이 접근 방식을 활성화하려면 @EnableGlobalMethodSecurity 어노테이션의 prePostEnabled 특성을 이용한다.
    • 예제 소스는 아래와 같다.

    - ProjectConfig 클레스

    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class ProjectConfig {
    
        @Bean
        public UserDetailsService userDetailsService() {
            var service = new InMemoryUserDetailsManager() ;
    
            var u1 = User.withUsername("natalie")
                         .password("12345")
                    .authorities("read")
                    .build() ;
    
            var u2 = User.withUsername("emma")
                    .password("12345")
                    .authorities("write")
                    .build() ;
    
            service.createUser(u1);
            service.createUser(u2);
    
            return service ;
    
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return NoOpPasswordEncoder.getInstance() ;
        }
    }

     

    - Controller 클레스

    @RestController
    public class HelloController {
    
        @Autowired
        private NameService nameService ;
    
        @GetMapping
        public String hello() {
            return "Hello, " + nameService.getName() ;
        }
    
    }
    - Service 클레스
    @Service
    public class NameService {
    
        @PreAuthorize("hasAuthority('write')")
        public String getName() {
            return "Fantastico" ;
        }
    }

     

    - 결과

     

    # 사후 권한 부여 적용

    • 메서드 호출 후에 권한 부여 규칙을 적용하고 싶다면 사후 권한 부여를 이용하면 된다.
    • 메서드 실행은 허용하되 반환되는 내용을 검증하고 기준이 충족되지 않으면 호출자가 반환 값에 접근하지 못하게 할 수 있다.
    • 스프링 시큐리티로 사후 권한 부여를 적용하려면 @PostAuthproze 어노테이션을 이용한다.
    • 사용 방법은 아래와 같다.
    @Service
    public class BookService {
    	private Map<String, Employee> records =
        	Map.of("emma", new Employee("Emma Thompson",
                                        List.of("Karamazov Brothers"),
                                        List.of("accountant", "reader")),
                   "natalie", new Employee("Natalie Parker",
                                        List.of("Beautiful Paris"),
                                        List.of("researcher"))
            ) ;
    
        @PostAuthorize("returnObject.roles.contains('reader')")
        public Employee getBookDetails(String name) {
            return records.get(name) ;
        }
    }

     

    • 실무에서 썼던 예시로는 아래와 같다.
    • 첫번째 코드처럼 보안 컨텍스트의 authentication을 설정하고, 두번째 코드처럼 Method 위에 보안을 설정했다.
    UsernamePasswordAuthenticationToken upat = new UsernamePasswordAuthenticationToken(payload.getSysId(),null,roles);
    
    /** SET : Security Context Holder */
    SecurityContextHolder.getContext().setAuthentication(upat);
    @PreAuthorize("isAuthenticated() and hasRole('ROLE_C')")

     

    • @RolesAllowed와 @Secured 어노테이션은 @PreAuthorize, @PostAuthorize 보다는 기능이 떨어지므로 실제 시나리오에서는 그리 많이 사용되지 않는다.
    • 사용법은 아래와 같다.
    @RolesAllowed("ROLE_ADMIN")
    public String getName() {
    	return "ADMIN" ;
    }
    
    @Secured("ROLE_ADMIN")
    public String getName() {
    	return "ADMIN" ;
    }