[개요]
서비스에는 인증 되지 않은 모든 유저가 접근할 수 있는 리소스가 있다. 하지만 특정 리소스는 로그인 인증이 되어야만, 인증이 되어도 특정 권한이 있어야만 접근할 수 있는 것이 필요할 수도 있다. 이를 Spring security로 쉽게 설정할 수 있다. 이 방법을 정리해보려 한다.
[본문]
package com.example.testsecurity.config;
import lombok.Getter;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // Spring Security 에서 관리 되도록 한다.
public class SecurityConfig {
private final String[] WHITE_LIST = {
"/",
"/login"
};
private final String[] ADMIN_LIST = {
"/admin"
};
private final String[] LOGIN_LIST = {
"/my/**"
};
private final String USER = "USER";
private final String ADMIN = "ADMIN";
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(auth -> auth // 위부터 작동하기 떄문에 위에서 적용한 것은 아래에서 다시 적용되지 않는다.
.requestMatchers(WHITE_LIST).permitAll()
.requestMatchers(ADMIN_LIST).hasRole(ADMIN)
.requestMatchers(LOGIN_LIST).hasAnyRole(ADMIN, USER)
.anyRequest().authenticated()
);
return httpSecurity.build();
}
}
Spring security가 관리하는 Configuration 객체 만들기
@Configuration, @EnableWebSecurity 어노테이션을 클래스 위에 작성해야 하고, 또 SecurityFilterChain 인터페이스를 반환하는 메서드를 구현 후 @Bean 어노테이션을 메서드 위에 작성한다.
- @Configuration은 Spring이 해당 클래스를 실행 시 설정 객체로 등록하도록 하는 어노테이션이다.
- @EnableWebSecurity는 Spring이 실행 시 Spring security에서 관리되도록 설정하는 어노테이션이다.
public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
- SecurityFilterChain은 위와 같은 인터페이스이다. 위의 두 어노테이션을 붙인 클래스에 해당 인터페이스를 반환하는 메서드를 구현해야 한다. 해당 메서드는 HttpSecurity 타입의 객체를 매개변수로 받는다.
- 해당 메서드는 Spring container가 Bean으로써 관리되도록 @Bean 어노테이션을 메서드 위에 추가한다.
- @Configuratoin, @EnableWebSecurity 어노테이션이 있는 클래스에 Bean으로 관리 되고, SecurityFilterChain 객체를 반환하는 메서드를 filterChain()이라 하겠다.
특정 리소스 마다 권한 설정하기
특정 리소스 마다 접근 권한을 설정하고, 권한이 없는 유저의 접근을 제한할 수 있다. 이를 서비스 입장에서 인가라고 한다. filterChain() 메서드의 매개변수로 받는 httpSecurity 객체의 authorizeRequests() 메서드를 호출해야 한다. 이는 3.1.x 버전 이상의 Spring boot부터는 람다 식을 받아야 한다. 특정 리소스 마다 권한을 설정해볼 것인데 다음 경우에 대한 방법을 찾아볼 것이다.
- 권한 인증이 되어야만 접근 가능한 리소스
- 모두가 접근 가능한 리소스
- 특정 권한이 있는 유저만 접근 가능한 리소스
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(auth -> auth
.requestMatchers(WHITE_LIST).permitAll()
.requestMatchers(ADMIN_LIST).hasRole(ADMIN)
.requestMatchers(LOGIN_LIST).hasAnyRole(ADMIN, USER)
.anyRequest().authenticated()
);
return httpSecurity.build();
}
권한 인증이 되어야만 접근 가능하도록 설정
- 람다 식의 인자로 받은 Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> 타입의 객체 메서드인 anyRequest()는 모든 요청에 대해 권한을 설정할 수 있다. 여기에서 authenticated()라는 메서드를 호출할 것인데, 이는 무조건 인증을 해야만 한다는 의미이다. 때문에 이를 추가하면 Spring security는 모든 리소스 접근 요청을 로그인을 하도록 리다이렉트 시켜준다.
모두가 접근 가능한 권한 설정
private final String[] WHITE_LIST = {
"/",
"/login",
};
- 모두가 접근 가능하도록 할 리소스에 대한 문자열 리스트를 WHITE_LIST로 정의하여 requestMatchers() 메서드의 인자로 넣는다. 하나 이상의 문자열을 받을 수 있기 때문이다. 이렇게 하면 문자열 리스트에 있는 모든 리소스 접근에 대해 특정 권한에 대한 설정이 가능하게 된다. 여기에선 permitAll()이라는 메서드를 통해 접근하는 모든 유저가 인가 받지 않아도 접근 가능하도록 한다.
- "/"와 "/login"을 인가 받지 않아도 접근 가능하도록 한 이유는 서비스의 메인 페이지와 로그인을 하도록 하는 페이지는 별도의 권한이 없어도 모든 사람이 접근할 수 있어야 하기 때문이다.
특정 권한만 접근 가능한 권한 설정
.requestMatchers(ADMIN_LIST).hasRole(ADMIN)
.requestMatchers(LOGIN_LIST).hasAnyRole(ADMIN, USER)
- requestMatchers() 메서드 내에 특정 권한이 있는 유저만 접근 가능하도록 할 리소스를 넣는다. 하나 이상의 문자열을 받을 수 있다.
- hasRole() 메서드는 하나의 권한에 대해 설정할 수 있다. ADMIN_LIST에 있는 리소스는 ADMIN이라는 권한이 있지 않으면 접근할 수 없다.
- hasAnyRole()은 하나 이상의 권한에 대해 설정할 수 있다. LOGIN_LIST에 있는 리소스는 ADMIN, USER에 대한 권한이 있지 않으면 접근할 수 없다.
[결론]
Spring security를 통해 특정 권한이 있어야 접근할 수 있는 리소스와 인가 받지 않아도 무조건 접근 가능할 수 있는 리소스를 설정했다.
'보안(인증, 인가, Spring security)' 카테고리의 다른 글
Spring security architecture 해석 part1 (0) | 2024.02.25 |
---|---|
인증과 인가 (0) | 2024.02.09 |
[개요]
서비스에는 인증 되지 않은 모든 유저가 접근할 수 있는 리소스가 있다. 하지만 특정 리소스는 로그인 인증이 되어야만, 인증이 되어도 특정 권한이 있어야만 접근할 수 있는 것이 필요할 수도 있다. 이를 Spring security로 쉽게 설정할 수 있다. 이 방법을 정리해보려 한다.
[본문]
package com.example.testsecurity.config;
import lombok.Getter;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // Spring Security 에서 관리 되도록 한다.
public class SecurityConfig {
private final String[] WHITE_LIST = {
"/",
"/login"
};
private final String[] ADMIN_LIST = {
"/admin"
};
private final String[] LOGIN_LIST = {
"/my/**"
};
private final String USER = "USER";
private final String ADMIN = "ADMIN";
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(auth -> auth // 위부터 작동하기 떄문에 위에서 적용한 것은 아래에서 다시 적용되지 않는다.
.requestMatchers(WHITE_LIST).permitAll()
.requestMatchers(ADMIN_LIST).hasRole(ADMIN)
.requestMatchers(LOGIN_LIST).hasAnyRole(ADMIN, USER)
.anyRequest().authenticated()
);
return httpSecurity.build();
}
}
Spring security가 관리하는 Configuration 객체 만들기
@Configuration, @EnableWebSecurity 어노테이션을 클래스 위에 작성해야 하고, 또 SecurityFilterChain 인터페이스를 반환하는 메서드를 구현 후 @Bean 어노테이션을 메서드 위에 작성한다.
- @Configuration은 Spring이 해당 클래스를 실행 시 설정 객체로 등록하도록 하는 어노테이션이다.
- @EnableWebSecurity는 Spring이 실행 시 Spring security에서 관리되도록 설정하는 어노테이션이다.
public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
- SecurityFilterChain은 위와 같은 인터페이스이다. 위의 두 어노테이션을 붙인 클래스에 해당 인터페이스를 반환하는 메서드를 구현해야 한다. 해당 메서드는 HttpSecurity 타입의 객체를 매개변수로 받는다.
- 해당 메서드는 Spring container가 Bean으로써 관리되도록 @Bean 어노테이션을 메서드 위에 추가한다.
- @Configuratoin, @EnableWebSecurity 어노테이션이 있는 클래스에 Bean으로 관리 되고, SecurityFilterChain 객체를 반환하는 메서드를 filterChain()이라 하겠다.
특정 리소스 마다 권한 설정하기
특정 리소스 마다 접근 권한을 설정하고, 권한이 없는 유저의 접근을 제한할 수 있다. 이를 서비스 입장에서 인가라고 한다. filterChain() 메서드의 매개변수로 받는 httpSecurity 객체의 authorizeRequests() 메서드를 호출해야 한다. 이는 3.1.x 버전 이상의 Spring boot부터는 람다 식을 받아야 한다. 특정 리소스 마다 권한을 설정해볼 것인데 다음 경우에 대한 방법을 찾아볼 것이다.
- 권한 인증이 되어야만 접근 가능한 리소스
- 모두가 접근 가능한 리소스
- 특정 권한이 있는 유저만 접근 가능한 리소스
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(auth -> auth
.requestMatchers(WHITE_LIST).permitAll()
.requestMatchers(ADMIN_LIST).hasRole(ADMIN)
.requestMatchers(LOGIN_LIST).hasAnyRole(ADMIN, USER)
.anyRequest().authenticated()
);
return httpSecurity.build();
}
권한 인증이 되어야만 접근 가능하도록 설정
- 람다 식의 인자로 받은 Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> 타입의 객체 메서드인 anyRequest()는 모든 요청에 대해 권한을 설정할 수 있다. 여기에서 authenticated()라는 메서드를 호출할 것인데, 이는 무조건 인증을 해야만 한다는 의미이다. 때문에 이를 추가하면 Spring security는 모든 리소스 접근 요청을 로그인을 하도록 리다이렉트 시켜준다.
모두가 접근 가능한 권한 설정
private final String[] WHITE_LIST = {
"/",
"/login",
};
- 모두가 접근 가능하도록 할 리소스에 대한 문자열 리스트를 WHITE_LIST로 정의하여 requestMatchers() 메서드의 인자로 넣는다. 하나 이상의 문자열을 받을 수 있기 때문이다. 이렇게 하면 문자열 리스트에 있는 모든 리소스 접근에 대해 특정 권한에 대한 설정이 가능하게 된다. 여기에선 permitAll()이라는 메서드를 통해 접근하는 모든 유저가 인가 받지 않아도 접근 가능하도록 한다.
- "/"와 "/login"을 인가 받지 않아도 접근 가능하도록 한 이유는 서비스의 메인 페이지와 로그인을 하도록 하는 페이지는 별도의 권한이 없어도 모든 사람이 접근할 수 있어야 하기 때문이다.
특정 권한만 접근 가능한 권한 설정
.requestMatchers(ADMIN_LIST).hasRole(ADMIN)
.requestMatchers(LOGIN_LIST).hasAnyRole(ADMIN, USER)
- requestMatchers() 메서드 내에 특정 권한이 있는 유저만 접근 가능하도록 할 리소스를 넣는다. 하나 이상의 문자열을 받을 수 있다.
- hasRole() 메서드는 하나의 권한에 대해 설정할 수 있다. ADMIN_LIST에 있는 리소스는 ADMIN이라는 권한이 있지 않으면 접근할 수 없다.
- hasAnyRole()은 하나 이상의 권한에 대해 설정할 수 있다. LOGIN_LIST에 있는 리소스는 ADMIN, USER에 대한 권한이 있지 않으면 접근할 수 없다.
[결론]
Spring security를 통해 특정 권한이 있어야 접근할 수 있는 리소스와 인가 받지 않아도 무조건 접근 가능할 수 있는 리소스를 설정했다.
'보안(인증, 인가, Spring security)' 카테고리의 다른 글
Spring security architecture 해석 part1 (0) | 2024.02.25 |
---|---|
인증과 인가 (0) | 2024.02.09 |