인프런/스프링 시큐리티 완전 정복 [6.x 개정판]

19) 인가 프로세스 - 요청 기반 권한 부여HttpSecurity.authorizeHttpRequests()

backend dev 2024. 11. 1.

 

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

 

Spring Security는 요청 기반 권한 부여(Request Based Authorization)와

메소드 기반 권한 부여(Method Based Authorization )를 통해 자원에 대한 심층적인 방어를 제공한다

 

요청 기반 권한 부여클라이언트의 요청 즉 HttpServletRequest에 대한 권한 부여를 모델링 하는 것이며

이를 위해 HttpSecurity 인스턴스를 사용하여 권한 규칙을 선언 할 수 있다

 

@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(authorize -> authorize
            .anyRequest().authenticated()); 
            // 애플리케이션의 모든 엔드포인트가 최소한 인증된 보안 컨텍스트가 있어야 한다고 알림!!
    return http.build();
}

 

authorizeHttpRequests()

사용자의 자원접근을 위한 요청 엔드포인트와 접근에 필요한 권한을 매핑시키기 위한 규칙을 설정하는 것으로서

서블릿 기반 엔드포인트에 접근하려면 authorizeHttpRequests() 에 해당 규칙들을 포함해야 한다 

 

authorizeHttpRequests() 을 통해 요청과 권한 규칙이 설정되면 내부적으로 AuthorizationFilter 가 요청에 대한

권한 검사 및 승인 작업을 수행한다

 


authorizeHttpRequests() API

 

requestMatchers()

requestMatchers()

 

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

어떤 요청에 대해서는 특정 보안 설정을 적용하고 다른 요청에 대해서는 적용하지 않도록 세밀하게 제어할 수 있게 해준다

 

예를 들어 특정 API 경로에만 CSRF 보호를 적용하거나, 특정 경로에 대해 인증을 요구하지 않도록 설정할 수 있다.

이를 통해 애플리케이션의 보안 요구 사항에 맞춰서 유연한 보안 정책을 구성할 수 있다

 

1. requestMatchers(String... urlPatterns)
• 보호가 필요한 자원 경로를 한 개 이상 정의한다
    
2. requestMatchers(RequestMatcher... requestMatchers)
• 보호가 필요한 자원 경로를 한 개 이상 정의한다. AntPathRequestMatcher, MvcRequestMatcher 등의 구현체를 사용할 수 있다
    
3. requestMatchers(HttpMethod method, String... utlPatterns)
• Http Method 와 보호가 필요한 자원 경로를 한 개 이상 정의한다

 

 

엔드 포인트 & 권한 부여

requestMatchers("/admin").hasRole("ADMIN")
// 요청 URL 이 /admin 엔드포인트일 경우 ADMIN 권한을 필요로 한다
requestMatchers("/admin")

이 부분이 엔드포인트 패턴

 

hasRole("ADMIN")

이 부분이 권한 규칙

 

 

 

보호 자원과 권한 규칙 설정하기

 

http.authorizeHttpRequests(authorize -> authorize
        .requestMatchers("/user").hasAuthority("USER") //엔드 포인트와 권한 설정, 요청이 /user 엔드포인트 요청인 경우 USER 권한을 필요로 한다
        .requestMatchers("/mypage/**").hasAuthority("USER") //Ant 패턴을 사용할 수 있다. 요청이 /mypage 또는 하위 경로인 경우 USER 권한을 필요로 한다
        .requestMatchers(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+")).hasAuthority("USER") //정규 표현식을 사용할 수 있다
        .requestMatchers(HttpMethod.GET, "/**").hasAuthority("read") //HTTP METHOD 를 옵션으로 설정할 수 있다
        .requestMatchers(HttpMethod.POST).hasAuthority("write") // POST 방식의 모든 엔드포인트 요청은 write 권한을 필요로 한다
        .requestMatchers(new AntPathRequestMatcher("/manager/**")).hasAuthority("MANAGER") //원하는 RequestMatcher 를 직접 사용할 수 있다
        .requestMatchers("/admin/**").hasAnyAuthority("ADMIN", "MANAGER") / admin / 이하의 모든 요청은 ADMIN 과 MANAGER 권한을 필요로 한다
        .anyRequest().authenticated()); 위에서 정의한 규칙 외 모든 엔드포인트 요청은 인증을 필요로 한다
return http.build();

requestMatchers은 당연히 인증을 받고나서 검증하는 로직이다.

[ 인증을 받고 나서야 권한이 있는지 확인하는거니까 ]

 

 

주의 사항

스프링 시큐리티는 클라이언트의 요청에 대하여 위에서 부터 아래로 나열된 순서대로 처리하며 요청에 대하여

첫 번째 일치만 적용되고 다음 순서로 넘어가지 않는다

[스프링 시큐리티에서 authorizeHttpRequests 메서드를 통해 설정된 권한 규칙은 위에서 아래로 차례대로 적용됩니다.
이 방식은 요청 경로와 권한 조건을 설정할 때 우선순위를 부여할 수 있어 특정 조건이 다른 조건보다 먼저 검사되도록 할 수 있다는 장점이 있습니다. ]

 

/admin/** 가 /admin/db 요청을 포함하므로 의도한 대로 권한 규칙이 올바르게 적용 되지 않을 수 있다.

그렇기 때문에 엔드 포인트 설정 시 좁은 범위의 경로를 먼저 정의하고 그것 보다 큰 범위의 경로를

다음 설정으로 정의 해야 한다

 

더보기

Ant 패턴은 Spring에서 URL 경로를 매칭할 때 사용하는 패턴 형식입니다. Ant 패턴을 통해 특정 경로의 요청을 필터링하거나 권한을 설정할 수 있습니다. 파일 경로와 유사하게 패턴을 정의하며, 다음과 같은 와일드카드 문자를 사용하여 유연한 매칭을 지원합니다:

  1. * (별표): 한 경로의 하위 경로 없이 특정 부분에 해당하는 문자열을 의미합니다.
    • "/user/*": /user/ 경로 바로 하위의 한 경로에만 매칭됩니다. 예: /user/profile, /user/settings
    • /user/*는 /user/abc/def와 같은 더 깊은 하위 경로에는 매칭되지 않습니다.
  2. ** (더블 별표): 하위 모든 경로를 포함하여 매칭합니다.
    • "/mypage/**": /mypage 경로의 하위 모든 경로에 매칭됩니다. 예: /mypage/profile, /mypage/settings/preferences
  3. ? (물음표): 한 자리의 임의의 문자와 매칭됩니다.
    • "/file?.html": /file1.html, /fileA.html 등과 매칭됩니다.

 

 

 

권한 규칙 종류

1. authenticated – 인증된 사용자만 접근 허용

.requestMatchers("/api/secure").authenticated();

인증된 사용자만 접근할 수 있습니다.
이 규칙을 사용하면 로그인된 사용자만 특정 엔드포인트에 접근할 수 있도록 제한됩니다.


2. fullyAuthenticated – 아이디와 패스워드로 인증된 사용자만 접근 허용

.requestMatchers("/api/secure").fullyAuthenticated();

아이디와 비밀번호로 인증된 사용자만 접근할 수 있습니다.
rememberMe 인증을 제외하고, 완전하게 인증된 사용자만 허용할 때 사용합니다.


3. anonymous – 익명 사용자만 접근 허용

.requestMatchers("/api/login").anonymous();

로그인하지 않은 익명 사용자만 접근할 수 있습니다.
로그인 페이지나 회원가입 페이지 등, 인증되지 않은 사용자가 접근해야 하는 페이지에 적용할 수 있습니다.


4. rememberMe – 기억하기로 인증된 사용자만 접근 허용

.requestMatchers("/api/remember").rememberMe();

remember-me 기능으로 로그인한 사용자만 접근할 수 있습니다.
rememberMe 기능으로 인증된 사용자에게 접근을 허용하는 규칙입니다.


5. permitAll – 누구나 접근 허용

.requestMatchers("/api/public").permitAll();

모든 사용자에게 접근을 허용합니다.
API 문서, 로그인 페이지 등 누구나 접근할 수 있어야 하는 엔드포인트에 주로 사용됩니다.


6. denyAll – 접근 불가

.requestMatchers("/api/private").denyAll();

모든 접근을 차단합니다.
관리자 설정 페이지나 특정 엔드포인트를 임시로 비활성화하고 싶을 때 유용하게 사용할 수 있습니다.


7. access – 사용자 정의 조건으로 접근 허용

.requestMatchers("/api/conditional").access("hasAuthority('USER') and hasIpAddress('192.168.1.0/24')");

사용자 정의 표현식에 따라 접근을 허용합니다.
권한뿐 아니라 IP 주소 등 특정 조건을 추가해 세부적인 접근 제어가 필요할 때 사용됩니다.

원래 제공하는 hasIpAddress() 같은 메소드를 사용해도 되고, 커스텀으로 만들어서 사용해도된다.

and, or, not과 같은 논리 연산자를 조합하여 조건을 더 세밀하게 구성할 수 있습니다.

요청이 사용자 정의 AuthorizationManager 를 사용하여 액세스를 결정한다(표현식 문법 사용)


8. hasAuthority – 지정된 권한을 가진 사용자만 접근 허용

.requestMatchers("/api/user").hasAuthority("USER");

해당 권한을 가진 사용자만 접근할 수 있습니다.
사용자의 GrantedAuthority에 "USER" 권한이 포함된 경우에만 접근이 허용됩니다.


9. hasRole – 지정된 역할을 가진 사용자만 접근 허용

.requestMatchers("/api/admin").hasRole("ADMIN");

특정 역할을 가진 사용자만 접근할 수 있습니다.
스프링 시큐리티에서는 역할명 앞에 기본적으로 ROLE_을 추가합니다.

여기서 ADMIN은 실제로 ROLE_ADMIN을 의미합니다.


10. hasAnyAuthority – 여러 권한 중 하나라도 일치하는 경우 접근 허용

.requestMatchers("/api/multiple-roles").hasAnyAuthority("USER", "ADMIN");

지정된 권한 중 하나라도 부여된 사용자는 접근할 수 있습니다.
예를 들어, USER나 ADMIN 권한을 가진 사용자는 모두 접근할 수 있습니다.


11. hasAnyRole – 여러 역할 중 하나라도 일치하는 경우 접근 허용

.requestMatchers("/api/multiple-roles").hasAnyRole("USER", "ADMIN");

여러 역할 중 하나를 가진 사용자만 접근할 수 있습니다.
역할 이름은 ROLE_ 접두사가 생략된 형태로 지정되며, 스프링 시큐리티가 자동으로 ROLE_을 추가해 처리합니다.


스프링 시큐리티에서 권한 규칙을 세분화하여 설정함으로써 보안 정책을 보다 세밀하게 관리할 수 있습니다. 각 규칙을 상황에 맞게 조합하면, 사용자에 따라 접근 권한을 유연하게 설정할 수 있습니다.

 

더보기

authority와 role은 스프링 시큐리티에서 사용자의 권한을 정의하는 방식이지만,

개념과 사용 방식에 차이가 있습니다.

1. Authority

  • 정의: authority는 사용자에게 부여된 특정 권한을 나타냅니다.
  • 표기 방식: 권한 이름에 특별한 접두사가 필요하지 않습니다. 예를 들어, USER, ADMIN, READ_PRIVILEGE 등으로 사용할 수 있습니다.
  • 사용 예시:
    .requestMatchers("/api/user").hasAuthority("USER"); 
    .requestMatchers("/api/read").hasAuthority("READ_PRIVILEGE");
  • 사용 목적: authority는 보다 세부적인 권한 제어에 유리합니다. 예를 들어, 읽기, 쓰기, 삭제 등
    구체적인 행동이나 권한을 제어할 때 사용됩니다.

2. Role

  • 정의: role은 사용자의 직책, 직무 등을 나타내는 역할로, 권한을 더 추상화한 개념입니다.
  • 표기 방식: 스프링 시큐리티에서 role을 사용할 때는 기본적으로 ROLE_ 접두사가 자동으로 추가됩니다. 예를 들어 ADMIN 역할을 설정하면 실제로는 ROLE_ADMIN으로 매칭됩니다.
  • 사용 예시:
    .requestMatchers("/admin").hasRole("ADMIN"); // 실제로 ROLE_ADMIN으로 해석됨
  • 사용 목적: role은 사용자에게 일괄적인 권한을 부여할 때 유용합니다.
    예를 들어, ADMIN 역할을 가진 사용자는 관리자 페이지에서 모든 행동을 수행할 수 있도록 설정할 수 있습니다.

주요 차이점

차이점 Authority Role
접두사 접두사 필요 없음 ROLE_ 접두사가 자동으로 추가됨
용도 세부 권한 제어
(ex) READ_PRIVILEGE, WRITE_PRIVILEGE)
역할 기반 제어
(ex) ADMIN, MANAGER)
사용 방식 hasAuthority("USER"),
hasAuthority("READ_PRIVILEGE")
hasRole("ADMIN")
(실제로는 ROLE_ADMIN)

 

사용 시 주의점

  1. 혼합 사용 가능: role과 authority는 같이 사용이 가능합니다.
    role은 역할 수준에서 권한을 부여하고,
    authority는 행동 수준에서 세부적인 접근을 제어하는 방식으로 설계할 수 있습니다.

  2. 접두사 처리: hasRole을 사용할 때는 ROLE_ 접두사가 자동으로 추가되므로,
    실제로는 hasAuthority("ROLE_ADMIN")과 같은 의미로 해석됩니다.

결론적으로, role은 사용자 직책이나 그룹처럼 추상화된 역할을 나타내고, authority는 구체적인 행동이나 기능에 대한 접근 권한을 설정하는 데 사용됩니다.

 

댓글