2025-04-08T19:56:24

This commit is contained in:
2025-04-08 19:56:24 +09:00
parent a75a1dbd0f
commit eef061c1c9
100 changed files with 18639 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
아래는 "스프링 시큐리티" 책의 5장에 포함될 "역할(Role)과 권한(Authority)의 차이"와 "URL 기반 접근 제어"에 대한 내용입니다. 개념을 명확히 설명하고 실습 가능한 예제를 포함해 실무에서의 활용성을 높였습니다.
---
### 5장. 인가와 권한 관리
#### 5.1 역할(Role)과 권한(Authority)의 차이
스프링 시큐리티에서 **역할(Role)**과 **권한(Authority)**은 사용자가 시스템에서 무엇을 할 수 있는지를 정의하는 핵심 개념입니다. 두 용어는 종종 혼용되지만, 미묘한 차이가 있으며 이를 이해하면 인가를 더 세밀하게 관리할 수 있습니다.
##### 역할(Role)이란?
역할은 사용자가 속한 그룹이나 직책을 나타내는 상위 수준의 개념입니다. 예를 들어, "관리자(ADMIN)", "일반 사용자(USER)", "게스트(GUEST)" 같은 이름으로 정의됩니다. 역할은 보통 사용자의 주요 책임이나 접근 범위를 나타내며, 스프링 시큐리티에서는 `ROLE_` 접두사를 붙여 표현합니다(예: `ROLE_ADMIN`).
역할은 단순하고 직관적이어서 소규모 애플리케이션이나 기본적인 권한 관리에 적합합니다. 예를 들어, 관리자 역할은 모든 기능을 사용할 수 있고, 일반 사용자는 제한된 기능만 접근할 수 있도록 설정할 수 있습니다.
##### 권한(Authority)이란?
권한은 더 세분화된 접근 제어 단위로, 특정 작업이나 리소스에 대한 권한을 나타냅니다. 예를 들어, "게시글 작성(WRITE_POST)", "댓글 삭제(DELETE_COMMENT)", "사용자 관리(MANAGE_USERS)" 같은 구체적인 권한을 정의할 수 있습니다. 권한은 `ROLE_` 접두사 없이도 사용 가능하며, 역할보다 유연하게 설계할 수 있습니다.
권한은 역할에 포함될 수 있으며, 복잡한 시스템에서 세밀한 접근 제어를 구현할 때 유용합니다. 예를 들어, `ROLE_USER``READ_POST``WRITE_POST` 권한을 가질 수 있고, `ROLE_ADMIN`은 추가로 `MANAGE_USERS` 권한을 가질 수 있습니다.
##### 차이점과 활용
- **수준**: 역할은 상위 수준(추상적), 권한은 하위 수준(구체적).
- **표기**: 역할은 `ROLE_` 접두사를 기본으로 사용, 권한은 자유롭게 정의.
- **복잡성**: 역할은 단순한 분류에 적합, 권한은 세부적인 제어에 유리.
스프링 시큐리티에서는 `GrantedAuthority` 인터페이스를 통해 두 개념을 통합적으로 관리하며, 설정에 따라 역할과 권한을 혼합해 사용할 수 있습니다. 예를 들어, `ROLE_ADMIN` 역할을 가진 사용자가 `MANAGE_USERS` 권한을 추가로 가질 수 있습니다.
#### 5.2 URL 기반 접근 제어
URL 기반 접근 제어는 스프링 시큐리티에서 가장 흔히 사용되는 인가 방식으로, 요청 URL 패턴에 따라 사용자의 접근을 허용하거나 차단합니다. 이를 통해 애플리케이션의 각 엔드포인트를 역할이나 권한에 따라 보호할 수 있습니다.
##### 기본 설정
스프링 시큐리티는 `HttpSecurity`를 사용해 URL 기반 접근 제어를 설정합니다. 기본적으로 모든 요청을 인증된 사용자만 접근 가능하도록 설정할 수 있습니다.
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public UserDetailsService userDetailsService() {
var user = User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build();
var admin = User.withUsername("admin")
.password("{noop}adminpass")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN") // /admin 하위는 ADMIN만 접근
.requestMatchers("/user/**").hasRole("USER") // /user 하위는 USER만 접근
.requestMatchers("/public/**").permitAll() // /public은 누구나 접근 가능
.anyRequest().authenticated() // 나머지 요청은 인증 필요
)
.formLogin(); // 기본 로그인 폼 활성화
return http.build();
}
}
```
##### 주요 메서드 설명
- **`requestMatchers()`**: 특정 URL 패턴을 지정합니다. 와일드카드(`**`, `*`)를 사용해 여러 경로를 매핑할 수 있습니다.
- **`hasRole()`**: 주어진 역할이 있는 사용자만 접근을 허용합니다. `ROLE_` 접두사는 자동으로 추가됩니다(예: `hasRole("ADMIN")``ROLE_ADMIN`).
- **`permitAll()`**: 인증 없이 누구나 접근 가능하도록 설정합니다.
- **`anyRequest()`**: 위에서 정의되지 않은 모든 요청에 대해 적용할 규칙을 지정합니다.
- **`authenticated()`**: 인증된 사용자만 접근 가능하도록 설정합니다.
##### 동작 원리
1. 사용자가 `/admin/dashboard`에 접근하면, `FilterSecurityInterceptor`가 요청을 가로챕니다.
2. `SecurityConfig`에 정의된 규칙을 확인해 사용자가 `ROLE_ADMIN` 역할을 가졌는지 검사합니다.
3. 역할이 일치하면 요청이 통과되고, 그렇지 않으면 `403 Forbidden` 오류가 발생하거나 로그인 페이지로 리다이렉트됩니다.
##### 권한 기반 제어
역할 대신 권한으로 제어하려면 `hasAuthority()`를 사용합니다:
```java
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/posts/write").hasAuthority("WRITE_POST")
.requestMatchers("/posts/delete").hasAuthority("DELETE_POST")
.anyRequest().authenticated()
);
```
이 경우, `UserDetailsService`에서 사용자에게 `WRITE_POST``DELETE_POST` 같은 권한을 부여해야 합니다.
##### 추가 설정
- **순서 중요성**: 규칙은 위에서 아래로 평가되므로, 더 구체적인 규칙을 먼저 작성해야 합니다. 예를 들어, `/public/**``anyRequest()`보다 뒤에 두면 적용되지 않습니다.
- **로그인 페이지 접근 허용**: 기본 로그인 페이지(`/login`)는 `permitAll()`로 열어둬야 인증되지 않은 사용자도 접근할 수 있습니다.
- **커스터마이징**: `.access()` 메서드를 사용하면 더 복잡한 조건(예: IP 주소나 시간 기반)을 추가할 수 있습니다.
##### 실습 예제
1. `/public/welcome`은 누구나, `/user/profile``USER`, `/admin/manage``ADMIN`만 접근 가능하도록 설정하세요.
2. 브라우저에서 각 URL에 접근해 결과를 확인하세요.
3. `hasAuthority()``MANAGE_USERS` 권한을 추가하고 테스트해보세요.
---
위 내용은 역할과 권한의 차이를 명확히 하고, URL 기반 접근 제어의 설정과 동작을 실습 가능하도록 설명했습니다. 추가적인 코드 예제나 세부 사항이 필요하면 말씀해 주세요!