이 장에서는 스프링 애플리케이션에서 메소드 보안을 구성하는 방법을 다룹니다. 메소드 보안은 주로 권한 부여를 엔드포인트 수준에서 벗어나 메소드 레벨에서 적용하는 방법을 제공합니다. 이를 통해 애플리케이션의 다양한 계층에서 세밀하게 권한 부여 규칙을 설정할 수 있습니다.
다룰 내용:
- 스프링 애플리케이션에서의 메소드 보안:
- 메소드 보안은 웹 애플리케이션 뿐만 아니라, 웹이 아닌 애플리케이션에서도 유용하게 적용될 수 있습니다.
- 메소드 레벨에서의 권한 부여는 애플리케이션의 유연성을 높이고, 다양한 계층에서 특정한 보안 규칙을 적용할 수 있게 해줍니다.
- Authorities, roles 및 permissions에 기반한 메소드 사전 승인:
- 메소드가 실행되기 전에 해당 메소드에 대한 접근을 허용할지 여부를 결정합니다.
- 주로 @PreAuthorize 어노테이션을 사용하여 메소드 실행 전에 필요한 권한을 검증합니다.
- Authorities, roles 및 permissions에 기반한 메소드 사후 승인:
- 메소드 실행 후, 그 결과가 적절한 권한을 가진 사용자에 의한 것인지 확인합니다.
- @PostAuthorize 어노테이션을 사용하여 메소드 실행 후, 리턴 값에 대한 권한을 검사하는 방식입니다.
메소드 보안의 장점
- 웹 애플리케이션과 비웹 애플리케이션에서의 권한 부여: 웹 애플리케이션에서는 엔드포인트에 대해서만 권한을 설정하는 대신, 비웹 애플리케이션에서도 필요한 부분에 권한 부여를 적용할 수 있습니다.
- 세밀한 권한 제어: 메소드 레벨에서 권한을 부여함으로써, 보다 세밀하게 애플리케이션 내 특정 기능에 대한 접근을 제어할 수 있습니다.
예시
- 예를 들어, 웹 애플리케이션에서 사용자가 특정 API 엔드포인트에 접근할 수 있는 권한이 있다고 하더라도, 해당 API에서 호출되는 서비스 메소드에 대해 추가적인 권한을 요구할 수 있습니다. 이를 통해 엔드포인트뿐만 아니라 내부 메소드 호출에도 보안 규칙을 적용할 수 있습니다.
결론
이 장에서는 메소드 보안을 활용하여, 애플리케이션의 세부 계층에서 권한 부여를 어떻게 다룰 수 있는지에 대해 배웁니다. 메소드 보안을 통해 엔드포인트 레벨을 넘어서는 세밀한 권한 부여가 가능하며, 이는 특히 웹이 아닌 애플리케이션에서도 효과적으로 사용할 수 있습니다.
11.1 메소드 보안 활성화
이 섹션에서는 메소드 레벨에서 권한 부여를 활성화하는 방법을 배우고, 스프링 시큐리티가 제공하는 다양한 권한 부여 규칙을 적용하는 여러 옵션을 살펴봅니다. 메소드 보안은 엔드포인트 레벨을 넘어서는 권한 부여를 가능하게 해주어, 권한 부여를 더 유연하게 적용할 수 있게 도와줍니다.
메소드 보안 활성화
기본적으로 스프링 시큐리티에서 메소드 보안은 비활성화되어 있습니다. 따라서, 이를 활성화하려면 설정이 필요합니다. 메소드 보안을 활성화하면, 스프링 시큐리티는 메소드 호출 전후로 권한을 체크할 수 있는 다양한 방법을 제공하며, 이를 통해 더 세밀한 제어가 가능합니다.
메소드 보안 활성화 방법
메소드 보안을 활성화하기 위해서는 스프링 애플리케이션의 설정 클래스에서 @EnableGlobalMethodSecurity 어노테이션을 사용해야 합니다. 이 어노테이션을 통해 전역 메소드 보안을 활성화하고, 메소드 사전 승인(pre-authorization) 및 사후 승인(post-authorization) 같은 다양한 권한 부여 방식을 사용할 수 있습니다.
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
- @EnableGlobalMethodSecurity(prePostEnabled = true): 이 설정은 메소드 수준에서의 권한 부여를 활성화하고, @PreAuthorize, @PostAuthorize 같은 어노테이션을 사용할 수 있도록 합니다.
메소드 보안에서 할 수 있는 주요 작업
메소드 보안은 주로 두 가지 주요 작업을 수행합니다:
- 호출 권한 부여 (Call Authorization)
- 사전 권한 부여 (Pre-authorization): 메소드 호출 전에 권한을 체크하여, 사용자가 해당 메소드를 호출할 수 있는지 여부를 결정합니다.
- 사후 권한 부여 (Post-authorization): 메소드 실행 후, 리턴된 데이터에 대해 권한을 체크하여, 호출자가 반환된 데이터를 볼 수 있는지 결정합니다.
- 필터링 (Filtering)
- 사전 필터링 (Pre-filtering): 메소드가 받는 인자에 대해 권한을 체크하여, 사용자가 올바른 데이터를 전달할 수 있는지 여부를 결정합니다.
- 사후 필터링 (Post-filtering): 메소드가 리턴하는 값에 대해 권한을 체크하여, 호출자가 데이터를 받을 수 있는지 결정합니다. 이 부분은 12장에서 더 자세히 다루어집니다.
메소드 보안을 사용하는 이유
메소드 보안은 엔드포인트 레벨에서만 권한을 부여하는 것에 비해 더 유연하고 세밀한 권한 부여를 제공합니다. 엔드포인트에 대한 권한 부여는 주로 URL 경로와 HTTP 메소드에 기반을 두지만, 메소드 보안을 사용하면 애플리케이션의 특정 메소드에 대해서도 권한을 정밀하게 제어할 수 있습니다. 이 방식은 특히 웹이 아닌 애플리케이션에서 유용하며, 웹 애플리케이션에서도 서비스 계층이나 비즈니스 로직 계층에서 권한을 보다 구체적으로 적용할 수 있습니다.
결론
메소드 보안을 활성화하면, 애플리케이션에서 메소드 레벨의 권한을 정밀하게 제어할 수 있습니다. 이를 통해, 사전 승인과 사후 승인, 사전 필터링과 사후 필터링 등을 사용할 수 있으며, 더 유연하고 세밀한 보안 정책을 구현할 수 있습니다. 이 기능을 사용하면, 웹 애플리케이션과 비웹 애플리케이션 모두에서 권한 부여를 보다 효과적으로 적용할 수 있습니다.
11.1.1 호출 권한 부여 이해
**호출 권한 부여 (Call Authorization)**는 메소드가 호출될 수 있는지, 또는 메소드 호출 후 리턴된 값에 대해 호출자가 접근할 수 있는지를 결정하는 권한 부여 규칙을 적용하는 방식입니다. 이 방식은 주로 메소드 호출의 파라미터나 리턴 값에 따라 누가 특정 로직에 접근할 수 있는지를 정의하는 데 사용됩니다.
메소드 보안이 활성화되면, 스프링은 AOP(관점 지향 프로그래밍) 기능을 통해 메소드 호출을 가로채고, 미리 설정된 권한 부여 규칙을 적용합니다. 규칙이 충족되지 않으면, 해당 메소드 호출을 허용하지 않고 예외를 던집니다.
호출 권한 부여의 두 가지 접근 방식
- 사전 권한 부여 (Pre-authorization)
- 메소드 호출 전에 권한을 체크합니다. 호출자가 권한 규칙을 만족하지 않으면 메소드 호출을 허용하지 않고, 대신 AccessDeniedException 예외를 던집니다. 이는 메소드 호출 전에 권한을 검증하는 방식으로, 보안이 중요한 시스템에서 자주 사용됩니다.
- 사후 권한 부여 (Post-authorization)
- 메소드 실행 후 결과에 대해 권한을 체크합니다. 호출자가 메소드 리턴 값을 받을 수 있는지 여부를 결정합니다. 이 방식은 메소드가 실행된 후에 권한 규칙을 적용하므로, 반환된 데이터에 대한 접근을 제한할 수 있습니다.
예제: 사전 권한 부여 사용
@PreAuthorize("#username == authentication.name")
public List<Document> findDocumentsByUser(String username) {
// 문서 검색 로직
}
이 예제에서 findDocumentsByUser 메소드는 특정 사용자의 문서를 반환합니다. @PreAuthorize 어노테이션을 사용하여, 메소드가 호출되기 전에 username 파라미터가 인증된 사용자의 이름과 일치하는지 확인합니다. 이를 통해 사용자는 자신의 문서만 볼 수 있게 됩니다.
- 사전 권한 부여는 메소드가 호출되기 전에 권한 규칙을 체크하여, 인증된 사용자만 메소드를 호출하도록 보장합니다. 인증되지 않은 사용자는 메소드 호출이 차단되며, AccessDeniedException이 발생합니다.
예제: 사후 권한 부여 사용
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(int documentId) {
// 문서 검색 로직
return document;
}
이 예제에서 getDocument 메소드는 특정 문서를 반환합니다. @PostAuthorize 어노테이션을 사용하여, 메소드가 실행된 후 리턴된 document 객체의 owner가 현재 인증된 사용자와 일치하는지 확인합니다. 이를 통해 인증된 사용자만 자신의 문서를 볼 수 있도록 제한할 수 있습니다.
- 사후 권한 부여는 메소드 실행 후, 리턴 값에 대한 권한을 검사하여 호출자가 데이터를 볼 수 있는지를 결정합니다. 이 방식은 메소드 실행 후에 권한을 체크하므로, 실행 후 데이터의 접근을 제어할 수 있습니다.
중요 사항
- 사전 권한 부여는 메소드가 호출되기 전에 권한을 검증하므로, 조건이 맞지 않으면 아예 메소드 실행을 하지 않고 예외를 던집니다.
- 사후 권한 부여는 메소드가 실행된 후 리턴 값에 대해 권한을 검사합니다. 이 경우 메소드가 실행되었더라도, 결과에 접근할 수 있는지 여부가 결정됩니다. 이 점에서, 사후 권한 부여는 메소드 실행 후의 결과를 기반으로 권한을 검토하는 방식입니다.
주의사항
- 사후 권한 부여를 사용할 때는 메소드가 리턴하는 값에 대해서만 권한을 체크할 수 있으며, 메소드 실행 중에 변경된 내용은 권한 부여 여부와 관계없이 실행됩니다. 따라서 트랜잭션과 결합될 때 주의가 필요합니다. 예를 들어, @Transactional 애노테이션을 사용한 경우, 사후 권한 부여가 실패하더라도 트랜잭션은 롤백되지 않습니다. 이는 트랜잭션 커밋 이후에 권한 부여 예외가 발생하기 때문입니다.
결론적으로, 호출 권한 부여는 애플리케이션에서 메소드 레벨로 권한 부여를 세밀하게 적용할 수 있는 중요한 기능입니다. 이를 통해, 애플리케이션의 보안을 강화하고, 사용자가 접근할 수 있는 자원에 대한 세밀한 제어가 가능해집니다.
11.1.2 프로젝트에서 메소드 보안 활성화하기
메소드 보안은 기본적으로 Spring Security 프로젝트에서 활성화되어 있지 않으므로, 이 기능을 사용하려면 먼저 활성화해야 합니다. 이를 위해서는 설정 클래스에 @EnableMethodSecurity 어노테이션을 추가하면 됩니다. 이 어노테이션은 메소드 보안을 활성화하며, 사전 인가(pre-authorization) 및 사후 인가(post-authorization) 기능을 제공합니다.
1. @EnableMethodSecurity 활성화
메소드 보안을 활성화하는 과정은 매우 간단합니다. @Configuration이 지정된 설정 클래스에 @EnableMethodSecurity 어노테이션을 추가하기만 하면 됩니다. 이 어노테이션을 사용하면 사전/사후 인가(pre-/post-authorization)와 관련된 기능이 기본적으로 활성화됩니다.
@Configuration
@EnableMethodSecurity
public class ProjectConfig {
}
위와 같이 설정하면 메소드 보안이 활성화되며, 이후 프로젝트에서 메소드 수준에서 권한 부여 규칙을 적용할 수 있습니다.
2. Spring Security 의존성
메소드 보안을 사용하기 위해서는 spring-boot-starter-security와 spring-boot-starter-web 의존성을 프로젝트에 추가해야 합니다. 예를 들어, pom.xml 파일에 다음과 같은 의존성을 추가합니다:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
이 의존성들은 Spring Security와 웹 애플리케이션을 위한 기본 설정을 제공합니다. 메소드 보안은 이 의존성들이 포함된 Spring Boot 애플리케이션에서만 작동합니다.
3. 메소드 보안 접근 방식
@EnableMethodSecurity 어노테이션을 추가하면 기본적으로 pre-/post-authorization 어노테이션을 사용할 수 있습니다. 이 두 접근 방식은 메소드 호출 전후로 권한 부여 규칙을 적용할 수 있게 해 줍니다. @PreAuthorize 또는 @PostAuthorize 어노테이션을 사용하여 특정 메소드에 권한 부여 규칙을 적용할 수 있습니다.
다른 두 가지 접근 방식은 JSR 250 어노테이션인 @RolesAllowed 와 @Secured 어노테이션이 있습니다. 그러나 대부분의 경우 pre-/post-authorization 어노테이션이 가장 일반적으로 사용되므로, 이 장에서는 이 두 가지 접근 방식에 대해서만 상세히 다룹니다.
4. Spring Security의 버전 차이
이전 Spring Security 버전에서는 @EnableGlobalMethodSecurity 어노테이션을 사용했으며, pre-/post-authorization가 기본적으로 활성화되지 않았습니다. 만약 이전 버전(Spring Security 5 이하)을 사용하고 있다면, Spring Security in Action 책의 16장을 참고하면 유용합니다.
요약
- 메소드 보안 활성화는 @EnableMethodSecurity 어노테이션을 설정 클래스에 추가하는 것만으로 가능합니다.
- pre-/post-authorization 기능은 기본적으로 활성화되며, 이를 통해 메소드 호출 전후로 권한 부여 규칙을 적용할 수 있습니다.
- 프로젝트에는 spring-boot-starter-security 및 spring-boot-starter-web 의존성을 추가해야 합니다.
- Spring Security의 이전 버전에서는 @EnableGlobalMethodSecurity를 사용했으며, 권한 부여 기능이 기본적으로 활성화되지 않았습니다.
11.2 Preauthorization 규칙 적용
이 섹션에서는 preauthorization 규칙을 적용하는 방법을 다룹니다. Preauthorization는 Spring Security가 특정 메소드를 호출하기 전에 권한 부여 규칙을 적용하는 방식입니다. 만약 규칙을 만족하지 않으면, 메소드 호출은 거부됩니다.
1. 기본 시나리오 설명
이 예제는 간단한 웹 애플리케이션으로, /hello 엔드포인트를 통해 이름을 반환합니다. 사용자가 엔드포인트를 호출하려면, 그 사용자는 "write" 권한을 가지고 있어야 합니다. 이를 위해 NameService 클래스의 getName() 메소드에 preauthorization 규칙을 설정합니다.
권한이 없으면 메소드 호출은 예외를 발생시킵니다.
2. UserDetailsService와 PasswordEncoder 설정
이 프로젝트에서는 두 명의 사용자가 필요합니다: 하나는 "write" 권한을 가진 사용자(Emma)이고, 다른 하나는 권한이 없는 사용자(Natalie)입니다. UserDetailsService와 PasswordEncoder를 설정하여 사용자를 정의합니다.
@Configuration
@EnableMethodSecurity
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();
}
}
이 설정에서는 InMemoryUserDetailsManager를 사용하여 두 명의 사용자("natalie"와 "emma")를 등록하고, 사용자의 권한을 정의합니다.
3. Preauthorization 규칙 정의
NameService 클래스에서 @PreAuthorize 어노테이션을 사용하여 "write" 권한을 가진 사용자만 getName() 메소드를 호출할 수 있도록 설정합니다.
@Service
public class NameService {
@PreAuthorize("hasAuthority('write')")
public String getName() {
return "Fantastico";
}
}
이 규칙에 의해, 사용자가 "write" 권한을 가지지 않으면 메소드 호출이 거부됩니다.
4. Controller 클래스 구현
HelloController 클래스는 NameService의 getName() 메소드를 호출하는 엔드포인트를 구현합니다.
@RestController
public class HelloController {
private final NameService nameService;
// 생략된 생성자
@GetMapping("/hello")
public String hello() {
return "Hello, " + nameService.getName();
}
}
이 컨트롤러는 /hello 엔드포인트에 대한 요청을 처리하며, preauthorization 규칙에 따라 권한이 없는 사용자는 호출할 수 없습니다.
5. 테스트
이제 두 사용자로 테스트를 진행할 수 있습니다. Emma는 "write" 권한을 가지므로 엔드포인트를 호출할 수 있습니다. 반면, Natalie는 "read" 권한만 가지고 있어 엔드포인트를 호출할 수 없습니다.
- Emma로 인증하고 /hello 엔드포인트 호출:응답:
- Hello, Fantastico
- curl -u emma:12345 http://localhost:8080/hello
- Natalie로 인증하고 /hello 엔드포인트 호출:응답:
- { "status": 403, "error": "Forbidden", "message": "Forbidden", "path": "/hello" }
- curl -u natalie:12345 http://localhost:8080/hello
6. 추가 권한 부여 규칙
**SpEL (Spring Expression Language)**을 사용하여 추가적인 권한 부여 규칙을 정의할 수 있습니다. 예를 들어:
- hasAnyAuthority('authority1', 'authority2'): 사용자가 지정된 여러 권한 중 하나라도 가지면 메소드를 호출할 수 있습니다.
- hasRole('role'): 사용자가 지정된 역할을 가지면 메소드를 호출할 수 있습니다.
- hasAnyRole('role1', 'role2'): 사용자가 지정된 여러 역할 중 하나라도 가지면 메소드를 호출할 수 있습니다.
7. 메소드 파라미터 기반 권한 부여
이 예제에서는 메소드 파라미터 값을 사용하여 권한 부여 규칙을 정의할 수도 있습니다. 예를 들어, 사용자는 자신의 비밀 이름만 조회할 수 있도록 설정할 수 있습니다. 이 예제는 preauthorization 규칙을 메소드 파라미터와 비교하는 방식으로 구현됩니다.
@Service
public class NameService {
private Map<String, List<String>> secretNames = Map.of(
"natalie", List.of("Energico", "Perfecto"),
"emma", List.of("Fantastico")
);
@PreAuthorize("#name == authentication.principal.username")
public List<String> getSecretNames(String name) {
return secretNames.get(name);
}
}
이 규칙에 따라, 사용자는 자신의 이름만으로 비밀 이름을 조회할 수 있습니다. Emma는 자신의 이름으로 비밀 이름을 조회할 수 있고, 다른 사용자의 이름으로는 조회할 수 없습니다.
curl -u emma:12345 http://localhost:8080/secret/names/emma
응답:
["Fantastico"]
Natalie는 자신의 이름으로 비밀 이름을 조회할 수 있습니다:
curl -u natalie:12345 http://localhost:8080/secret/names/natalie
응답:
["Energico", "Perfecto"]
하지만, 다른 사용자의 이름으로 비밀 이름을 조회하려고 하면 403 Forbidden 오류가 발생합니다.
결론
- Preauthorization 규칙은 메소드 호출 전에 권한 부여 규칙을 적용하여, 특정 권한을 가진 사용자만 메소드를 호출할 수 있도록 합니다.
- SpEL을 사용하여 다양한 조건을 설정할 수 있으며, 메소드 파라미터를 기반으로 한 권한 부여도 가능합니다.
- 애플리케이션의 여러 계층에서 메소드 보안을 적용할 수 있습니다.
11.3 사후 인증 규칙 적용
사후 인증(postauthorization)은 메소드 실행 후 반환된 값을 기준으로 권한을 적용하는 방식입니다. 이는 주로 반환되는 데이터에 따라 추가적인 권한을 확인하려는 경우 사용됩니다. 예를 들어, 특정 조건을 만족하는 데이터를 반환한 경우에만 그 데이터에 접근할 수 있도록 하는 방식입니다. 이 방식은 메소드 실행을 허용하되, 반환된 값에 대해 후속 검증을 거쳐 접근을 제어합니다.
예시:
- BookController는 직원이 읽은 책에 대한 세부 정보를 클라이언트에게 제공하는 엔드포인트를 구현합니다.
- 클라이언트는 직원이 reader 역할을 가지고 있을 경우에만 그 직원이 읽은 책의 세부 정보를 조회할 수 있습니다. 이 정보는 메소드 호출 전에 알 수 없으며, 호출 후에 권한 규칙을 적용합니다.
- 예를 들어, getBookDetails() 메소드가 직원 'natalie'의 정보를 반환할 때, 해당 직원이 'reader' 역할을 가지지 않으면 반환된 값에 접근하지 못하도록 합니다.
스프링 시큐리티의 @PostAuthorize 어노테이션은 이와 같은 사후 인증을 처리하는 데 사용됩니다. @PostAuthorize는 메소드 실행 후 반환된 값을 검사하고, 정의된 권한 규칙이 충족되지 않으면 예외를 발생시킵니다.
코드 예시
1. ProjectConfig 클래스
@Configuration
@EnableMethodSecurity
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();
}
}
2. Employee 클래스
public class Employee {
private String name;
private List<String> books;
private List<String> roles;
public Employee(String name, List<String> books, List<String> roles) {
this.name = name;
this.books = books;
this.roles = roles;
}
// getters and setters
}
3. BookService 클래스
@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);
}
}
4. BookController 클래스
@RestController
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping("/book/details/{name}")
public Employee getDetails(@PathVariable String name) {
return bookService.getBookDetails(name);
}
}
11.4 메소드 권한 구현
스프링 시큐리티에서 **권한(permission)**은 더 세부적인 액션을 제어하는 단위입니다. **인가(authorization)**는 시스템에 대한 접근을 허용하는 광범위한 개념이라면, **권한(permission)**은 특정 작업을 수행할 수 있는지 여부를 다룹니다.
권한 부여 규칙을 위한 PermissionEvaluator 구현
권한 부여가 복잡해지면, SpEL 표현식 대신 PermissionEvaluator를 사용해 별도의 클래스로 권한 로직을 처리하는 것이 좋습니다. 예를 들어, 문서에 대한 접근을 관리하는 시스템에서, 사용자가 문서를 조회할 때 그 사용자가 ROLE_admin 역할을 가지고 있는지 확인하는 권한 로직을 구현할 수 있습니다.
1. Document 클래스
public class Document {
private String owner;
public Document(String owner) {
this.owner = owner;
}
// getters and setters
}
2. DocumentRepository 클래스
@Repository
public class DocumentRepository {
private Map<String, Document> documents =
Map.of("abc123", new Document("natalie"),
"qwe123", new Document("natalie"),
"asd555", new Document("emma"));
public Document findDocument(String code) {
return documents.get(code);
}
}
3. DocumentService 클래스
@Service
public class DocumentService {
private final DocumentRepository documentRepository;
public DocumentService(DocumentRepository documentRepository) {
this.documentRepository = documentRepository;
}
@PostAuthorize("hasPermission(returnObject, 'ROLE_admin')")
public Document getDocument(String code) {
return documentRepository.findDocument(code);
}
}
4. PermissionEvaluator 구현
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if (targetDomainObject instanceof Document) {
Document document = (Document) targetDomainObject;
return authentication.getAuthorities().stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(permission));
}
return false;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
// Additional logic for permission checks based on targetId and targetType
return false;
}
}
이와 같이 PermissionEvaluator를 활용하면 더 복잡한 권한 부여 로직을 깔끔하게 처리할 수 있습니다.
'Spring Security in Action' 카테고리의 다른 글
13장 What are OAuth 2 and OpenID Connect? (1) | 2024.12.01 |
---|---|
12장 Implement filtering at the method level (0) | 2024.12.01 |
10장 Configuring Cross-Origin Resource Sharing(CORS) (0) | 2024.12.01 |
9장 Configuring Cross-Site Request Forgery(CSRF) protection (0) | 2024.12.01 |
8장 Configuring endpoint-level authorization: Applying restrictions (0) | 2024.12.01 |