Spring Security - 접근 제어 설정

July 29, 2021

Authorize

보안을 구성할 때는 인증만이 아니라 특정 역할, 권한에 따른 접근 제어가 필요하다. Spring Security에서는 아래와 같이 authorizeRequests() 를 사용해 URL 패턴에 대한 요구사항을 지정할 수 있다.

이를 구성할 때 주의할 점은 순차적으로 패턴을 검사하기에 작성 순서가 중요하다. 만약 아래 코드에서 anyRequest().denyAll()을 제일 상단에 위치시키면 Spring Security에서는 모든 요청을 모두 거부하게 된다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http
        // ...
        .authorizeRequests(authorize -> authorize                                  
            .mvcMatchers("/resources/**", "/signup", "/about").permitAll()         
            .mvcMatchers("/admin/**").hasRole("ADMIN")                             
            .mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")   
            .anyRequest().denyAll();
        );
    }
}
method description
hasRole(String) 해당 롤을 가지고 있어야 허용한다
hasAnyRole(String...) 지정된 역할 중 하나 이상을 가지고 있으면 허용한다
hasAuthority(String) 지정된 권한을 가지고 있으면 허용한다
hasAnyAuthority(String...) 지정된 권한 중 하나 이상을 가지고 있으면 허용한다
permitAll() 모든 요청을 허용한다
denyAll() 모든 요청을 거부한다
anonymous() 인증되지 않은 사용자만 허용한다
rememberMe() 이전 로그인 정보를 쿠키나 DB에서 가져온 Remember me 방식 인증 사용자를 허용한다
authenticated() 인증된 사용자를 허용한다
fullyAuthenticated() remember-me가 아닌 인증을한 사용자를 허용한다
hasIpAddress(String) 지정된 IP의 요청을 허용한다
not() 다른 접근 메서드를 무효화한다
access(String) 인자로 전달된 SpEL 식이 참이면 허용한다

Hierarchical Roles

애플리케이션 내에서 ADMIN과 USER 역할이 있다고 가정한다. 보통 이러한 설계에서는 두 개의 역할은 계층적인 구조를 가진다. ADMIN은 USER의 상위 계층으로 USER가 할 수 있는 것은 모두 할 수 있는 것이다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    public SecurityExpressionHandler expressionHandler() {
      // 계층 구조 지정
      RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
      roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");

      DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
      handler.setRoleHierarchy(roleHierarchy);

      return handler;
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http
        // ...
        .authorizeRequests(authorize -> authorize                                  
            .mvcMatchers("/resources/**", "/signup", "/about").permitAll()         
            .mvcMatchers("/admin/**").hasRole("ADMIN")                             
            .mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")   
            .anyRequest().denyAll()
            .expressionHandler(expressionHandler()); // 핸들러 등록
        );
    }
}

참고


songmk 🙁