Spring/스프링 시큐리티 인 액션

[7장] 권한 부여 구성: 액세스 제한

꾸준함. 2025. 5. 30. 22:55

주의

이 책은 Spring Security 5 버전을 기준으로 작성되었으므로, Spring Boot 3.X 버전에서는 일부 클래스가 더 이상 사용되지(deprecated) 않을 수 있습니다.

 

1. Authorization

  • 권한 부여 (Authorization)는 식별된 클라이언트가 요청된 리소스에 접근할 권한이 있는지 시스템이 결정하는 프로세스
  • 스프링 시큐리티에서 애플리케이션은 인증 흐름을 완료한 뒤 요청을 권한 부여 필터에 위임함
    • 필터는 구성된 권한 부여 규칙에 따라 요청을 허용하거나 거부함

 

https://assu10.github.io/dev/2023/12/09/springsecurity-authorization-1/

 

2. 권한과 역할에 따라 접근 제한

  • 사용자는 가진 권한에 따라 특정 작업만 실행할 수 있음
  • 권한은 사용자가 시스템 리소스로 수행할 수 있는 작업이며 권한의 이름은 객체의 getAuthority()가 String 형식으로 반환하는 값에서 얻을 수 있음
  • 권한의 이름은 맞춤형 권한 부여 규칙을 정의할 때 필요하며 권한 부여 규칙은 다음과 같음
    • 제인은 제품 레코드를 삭제할 수 있음 (허가된 권한 DELETE)
    • 존은 문서 레코드 읽을 수 있음 (허가된 권한 READ)
    • 애플리케이션은 사용자 제인과 존이 읽기, 쓰기 및 삭제와 같은 이름의 작업을 수행할 수 있게 해 줌

 

public interface GrantedAuthority extends Serializable {
String getAuthority();
}
view raw .java hosted with ❤ by GitHub

 

  • 스프링 시큐리티의 사용자를 나타내는 계약인 UserDetails는 GrantedAuthority 인스턴스의 컬렉션을 가짐
    • 한 사용자는 하나 잇아의 이용 권리를 가질 수 있으며 getAuthorities() 메서드는 GrantedAuthority 인스턴스의 컬렉션을 반환
    • UserDetails 내 getAuthorities() 메서드를 통해 사용자에게 허가된 모든 권한을 조회 가능

 

public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
// 중략
}
view raw .java hosted with ❤ by GitHub

https://assu10.github.io/dev/2023/12/09/springsecurity-authorization-1/

 

 

2.1 사용자 권한을 기준으로 모든 엔드포인트에 접근 제한

  • 사용자의 권한을 기반으로 엔드포인트에 대한 접근을 구성하는 방법은 세 가지가 있음
    • hasAuthority(): 애플리케이션이 제한을 구성하는 하나의 권한만 매개변수로 받으며 해당 권한이 있는 사용자만 엔드포인트 호출 가능
    • hasAnyAuthority(): 애플리케이션이 제한을 구성하는 권한을 하나 이상 받을 수 있으며 사용자는 요청하려면 지정된 권한 중 하나라도 있어야 함
    • access(): SpEL을 기반으로 권한 부여 규칙을 구축하므로 액세스를 구성하는 데 무한한 가능성이 있지만 코드를 읽고 디버그 하기 어려운 단점이 있음 (추천하지 않는 방법)


@Configuration
public class ProjectConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public UserDetailsService userDetailsService() {
var manager = new InMemoryUserDetailsManager(
var user1 = User.withUsername("john")
.password("12345")
.authorities("READ")
.build();
var user2 = User.withUsername("jane")
.password("12345")
.authorities("WRITE")
.build();
manager.createUser(user1);
manager.createUser(user2);
return manager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic();
// WRITE 및 READ 권한이 있는 사용자의 요청을 모두 허용
http.authorizeRequests().anyRequest().hasAnyAuthority("WRITE", "READ");
// 사용자가 엔드포인트에 접근하기 위한 조건 지정
// http.authorizeRequests().anyRequest().hasAuthority("WRITE");
// hasAuthority 또는 hasAnyAuthority() 메서드를 적용할 수 없을 때 최후의 수단으로만 권장
// 하지만 매개변수로 지정하는 식으로 규칙을 유연하게 구성할 수 있다는 장점은 있음
// 사용자에게 읽기 권한이 있어야 하지만 삭제 권한은 없어야
// Spring expression = "hasAuthority('READ') and !hasAuthority('DELETE')";
// http.authorizeRequests().anyRequest().access(expression);
}
}
view raw .java hosted with ❤ by GitHub

 

2.2 사용자 역할 (Role)을 기준으로 모든 엔드포이니트에 대한 접근 제한

  • 역할은 사용자가 착용하는 배지와 비슷하며 사용자에게 작업 그룹에 속한 이용 권리를 제공
  • 일부 애플리케이션은 특정 사용자에게 항상 같은 권한 그룹을 제공
    • i.g. 사용자가 읽기 권한만 가지거나 읽기, 쓰기, 삭제의 모든 권한을 가진다면 사용자는 읽기 권한만 있는 독자 역할이나 읽기, 쓰기, 삭제 권한이 있는 관리자 역할 중 하나를 가진다고 생각하면 이해하기 쉬움

 

  • 역할 이름은 권한 이름과 마찬가지로 개발자가 선택 가능
  • 내부적으로 역할도 스프링 시큐리티에서 같은 GrantedAuthority 계약으로 나타냄
    • 역할을 정의할 때 역할 이름은 ROLE_ 접두사로 시작해야 함

 

  • 사용자 역할에 대한 제약 조건을 설정하기 위해 다음 메서드 중 하나를 이용할 수 있음
    • hasRole(): 애플리케이션이 요청을 승인할 하나의 역할 이름을 매개변수로 받음
    • hasAnyRole(): 애플리케이션이 요청을 승인할 여러 역할 이름을 매개변수로 받음
    • access(): 애플리케이션의 요청을 승인할 역할을 스프링 식으로 지정, 역할을 지정하는 데는 hasRole() 또는 hasAnyRole()을 SpEL 식으로 이용 가능


@Configuration
public class ProjectConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public UserDetailsService userDetailsService() {
var manager = new InMemoryUserDetailsManager();
var user1 = User.withUsername("john")
.password("12345")
.roles("ADMIN")
.build();
var user2 = User.withUsername("jane")
.password("12345")
.roles("MANAGER")
.build();
manager.createUser(user1);
manager.createUser(user2);
return manager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic();
// hasRole() 메서드는 엔드포인트에 접근할 수 있는 역할을 지정
// 여기에 ROLE_접두사는 나오지 않는 것에 주의
http.authorizeRequests().anyRequest().hasRole("ADMIN");
}
}
view raw .java hosted with ❤ by GitHub

 

2.3 모든 엔드포인트에 대한 접근 제한

  • permitAll() 메서드로 모든 요청에 대한 액세스를 허용할 수 있으며 권한과 역할을 기준으로 접근 규칙을 적용할 수 있음
  • 반대로 denyAll() 메서드를 통해 모든 요청을 거부할 수도 있음
  • 실제 애플리케이션에서는 종종 이상하게 보일 수 있는 다양한 아키텍처 요구 사항을 해결해야 하며 프레임워크는 어떤 상황이라도 해결할 수 있는 유연성을 제공해야 하기 때문에 denyAll() 메서드는 다른 모든 옵션과 마찬가지로 중요함

 

https://livebook.manning.com/book/spring-security-in-action/chapter-7/

 

참고

스프링 시큐리티 인 액션

반응형

'Spring > 스프링 시큐리티 인 액션' 카테고리의 다른 글

[10장] CSRF 보호와 CORS 적용  (0) 2025.05.31
[8장] 권한 부여 구성: 제한 적용  (0) 2025.05.30
[5장] 인증 구현  (0) 2025.05.21
[4장] 암호 처리  (0) 2025.05.19
[3장] 사용자 관리  (0) 2025.05.18