[스프링시큐리티] 인가 - 요청 / 메서드 기반 권한 부여

Welcome to Seoyun Dev Log·2024년 11월 3일
0

보안

목록 보기
8/18

요청 기반 권한 부여HttpSecurity.authorizeHttpRequests()

📌보통 요청기반 권한 부여는 컨트롤러에서 받도록하고 메서드 기반 권한 부여는 서비스단에서 필터링하여 이중 보안으로 사용한다

클라이언트 요청(일반적으로 브라우저로 URL로 요청하는 것) request(경로 등)를 통해서 서버가 어떤 권한을 부여할 것인지 모델링 하는 것
HttpSecurity 인스턴스를 사용하여 권한 규칙을 선언한다.

위 설정을 통해 스프링시큐리티가 서버측에 설정한 권한을 사용할 것이라 알리는 것

  • 요청, 권한 규칙 -> 어떠한 요청에 대하여 , 어떠한 권한을 줄 것인가

authorizeHttpRequests() API

1. requestMatchers()

: HTTP 요청의 URL 패턴, HTTP 메소드, 요청 파라미터 등을 기반으로 제어

서버가 보호해야할 자원

  • 매개변수를 통해 동일한 API만 사용을 달리할 수 있다.
  • 문자열로 URL 필터를 주는 방법, 여러개의 파라미터를 지정할 수 있고 이는 서버가 보호해야할 자원이다.
  • 파라미터로 requestMatcher를 전달
  • 메소드와 파라미터 전달

보호된 자원을 어떤식으로 보호할 것인지 명시해야한다.

당연한 말이지만 인가는 인증을 받은 사용자에 한해 권한을 확인하는 것.
⭐️⭐️ 스프링 시큐리티는 클라이언트 요청에 대하여 위에서부터 아래로 순차대로 처리하고 하위의 권한을 확인하지 않는다
⭐️ 좁은 범위의 경로를 먼저 정의하고 그것보다 큰 범위의 경로를 다음으로 설정하여 걸러내야한다.

2. securityMatcher() / securityMatchers(Customizer < RequestMatcherConfigurer> )

: 특정 패턴에 해당하는 요청에만 보안 규칙(보안 권한 부여하는 것)을 적용하도록 설정할 수 있으며 중복해서 정의할 경우 마지막에 설정한 것으로 대체한다

  • 패턴 설정
//api로 시작하는지부터 확인하는 것 
//api로 시작하는 경우에만 authorizeHttpRequests 권한 확인
http
.securityMatcher("/api/**")
.authorizeHttpRequests(
	auth -> auth.requestMatchers(...)
)
  • 내부 흐름
    • HttpSecurity 를 /api/로 시작하는 URL에만 적용하도록 구성한다
      Spring MVC가 클래스 경로에 있으면 MvcRequestMatcher 가 사용되고, 그렇지 않으면 AntPathRequestMatcher 가 사용된다

securityMatchers(Customizer < RequestMatcherConfigurer > )

: 다중 패턴 설정
특정 패턴에 해당하는 요청을 단일이 아닌 다중 설정으로 구성해서 보안 규칙을 적용할 수 있으며 현재의 규칙은 이전의 규칙을 대체하지 않는다

//패턴1
http. securityMatchers((matchers) -> matchers.requestMatchers("/api/**", "/oauth/**")); 
//패턴2
http. securityMatchers((matchers) -> matchers.requestMatchers("/api/**").requestMatchers("/oauth/**")); 
//패턴3
http.securityMatchers((matchers) -> matchers.requestMatchers("/api/**") .securityMatchers((matchers) -> matchers.requestMatchers("/oauth/**"));

	@Bean
    public SecurityFilterChain securityFilterChain2(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated());
        return http.build();
    }
    
	@Bean
    @Order(1) ⭐️//좁은 범위부터 필터링 실행하여야 한다.
    public SecurityFilterChain securityFilterChain2(HttpSecurity http) throws Exception {
        http
                .securityMatchers(matchers -> matchers.requestMatchers("/open-banking/oauth/"))
                .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll());
        return http.build();
    }

권한 규칙 종류

권한의 경우 계층적 개념을 적용할 수 있지만 (ex: admin이 manager를 포함하고 있다)
위에서 권한을 확인하는 것은 단순 문자열로 비교하는 것이다


표현식 및 커스텀 권한 구현

  • access는 new WebExpressionAuthorizationManager() 즉, AuthorizationManager의 구현체가 반드시 들어가야 한다.
  • 매개변수는 표현식 구문을 전달한다.
  • 적용하기의 첫번째 reqeust는 구문 조건식에 부합하면 requestMatchers의 경로로 이동할 수 있다는 의미이다.

  1. access에 (권한)들어가는 AuthorizationManager의 구현체에 들어갈 빈을 생성하여 주입할 수 있다.
  2. requestMatcher에 들어갈 URI를 만들 수 있다 (엔드포인트).


메서드 기반 권한부여

@PreAuthorize, @PostAuthorize

  • 메서드 기반 권한 부여는 서비스단에서 필터링하여 이중 보안으로 사용한다 컨트롤러에서 사용한다고 안되는것은 아니지만 요청기반은 컨트롤러 메서드 기반은 서비스에서 사용하는것이 목적에 부합하다 볼 수 있다
  • Spring Security 는 요청 수준의 권한 부여뿐만 아니라 메서드 수준에서의 권한 부여를 지원
  • 메서드 수준 권한 부여를 활성화 하기 위해서는 설정 클래스에 @EnableMethodSecurity 어노테이션을 추가해야 한다
  • SpEL(Spring Expression Language) 표현식을 사용하여 다양한 보안 조건을 정의할 수 있다

@PreAuthorize

: 메소드가 실행되기 전에 특정한 보안 조건이 충족되는지 확인하는 데 사용되며 보통 서비스 또는 컨트롤러 레이어의 메소드에 적용되어 해당 메소드가 호출되기 전에 사용자의 인증 정보와 권한을 검사한다

@Secured

: 어노테이션을 메소드에 적용하면 지정된 권한(역할)을 가진 사용자만 해당 메소드를 호출할 수 있으며 더 풍부한 형식을 지원하는 @PreAuthorize 사용을 권장한다
@Secured는 아주 단순한 권한만 지정할 수 있다

  • 어노테이션을 사용하려면 스프링 시큐리티 설정에서 @EnableMethodSecurity(securedEnabled = true) 설정을 활성화해야 한다

본 어노테이션은 잘 사용하지 않는다

@Secured("ROLE_USER")
public void performUserOperation() {
// ROLE_USER 권한을 가진 사용자만 이 메소드를 실행할 수 있습니다.
}

@PostAuthorize

: @PostAuthorize 어노테이션은 메소드가 실행된 후에 보안 검사를 수행하는 데 사용된다
• @PreAuthorize 와는 달리, @PostAuthorize는 메소드 실행 후 결과에 대한 보안 조건을 검사하여 특정 조건을 만족하는 경우에 사용자가 결과를 받을 수 있도록 한다

PostAuthorize 조건을 충족해야지만 결과를 반환한다

@PreFilter

: 메소드가 실행되기 전에 메소드에 전달된 컬렉션 타입의 파라미터에 대한 필터링을 수행하는데 사용. 사용자가 보내온 컬렉션(배열, 리스트, 맵, 스트림) 내의 객체들을 특정 기준에 따라 필터링하고 그 중 보안 조건을 만족하는 객체들에 대해서만 메소드가 처리하도록 할 때 사용된다

@PostFilter

: 메소드가 반환하는 컬렉션 타입의 결과에 대해 필터링을 수행하는 데 사용된다
• @PostFilter 어노테이션은 메소드가 컬렉션을 반환할 때 반환되는 각 객체가 특정 보안 조건을 충족하는지 확인하고 조건을 만족하지 않는 객체들을 결과에서 제거한다

JSR-250

: JSR-250 기능을 적용하면 @RolesAllowed, @PermitAll 및 @DenyAll 어노테이션 보안 기능이 활성화 된다

  • JSR-250 어노테이션을 사용하려면 스프링 시큐리티 설정에서 @EnableMethodSecurity(jsr250Enabled = true) 설정을 활성화해야 한다
@RolesAllowed("USER") public void editDocument() {
// 'ROLE_USER' 권한을 가진 사용자만 문서를 편집할 수 있습니다.
}

@PermitAll
public void viewDocument() { //모든사용자가문서를볼수있습니다.
}

@DenyAll
public void hiddenMethod() {
// 어떠한 사용자에게도 접근이 허용되지 않습니다.
}

메타 주석 사용

: 메서드 보안은 애플리케이션의 특정 사용을 위해 편리성과 가독성을 높일 수 있는 메타 주석을 지원한다

  • 어노테이션을 생성하여 해당 어노테이션을 사용하여 가독성을 높일 수 있다

특정 주석 활성화

: Method Security 의 사전 구성을 비활성화한 다음 @PostAuthorize 를 활성화한다

@EnableMethodSecurity(prePostEnabled = false) 
class MethodSecurityConfig {

@Bean 
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) 
Advisor postAuthorize() {
	return AuthorizationManagerAfterMethodInterceptor.postAuthorize(); }
    
}

커스텀 빈을 사용하여 표현식 구현

: 사용자 정의 빈을 생성하고 새로운 표현식으로 사용할 메서드를 정의하고 권한 검사 로직을 구현한다


클래스 레벨 권한 부여

: 모든 메소드는 클래스 수준의 권한 처리 동작을 상속하나 메서드에 어노테이션을 선언한 메소드는 클래스 수준의 어노테이션을 덮어쓰게 된다 (메소드 우선 적용)

  • 클래스 수준
@Controller 
@PreAuthorize("hasAuthority('ROLE_USER')") 
public class MyController {

@GetMapping("/endpoint")
public String endpoint() { ... } 

}

📌 인터페이스에도 동일한 규칙이 적용되지만
클래스가 두 개의 다른 인터페이스로부터 동일한 메서드의 어노테이션을 상속받는 경우에는
시작할 때 실패한다.

그래서 구체적인 메소드에
어노테이션을 추가함으로써 모호성을 해결할 수 있다

@Controller 
@PreAuthorize("hasAuthority('ROLE_USER')") 
public class MyController {

@GetMapping("/endpoint")
@PreAuthorize("hasAuthority('ROLE_ADMIN')") // 이 설정이 우선적으로 동작한다
public String endpoint() { ... }

}
profile
하루 일지 보단 행동 고찰 과정에 대한 개발 블로그

0개의 댓글

관련 채용 정보