๐ป Spring Security docs ๊ฒ์๊ธ ๋ชฉ์ฐจ
1. [Spring Security] docs : Getting Started
[Spring Security] docs : Getting Started
Spring Security๋ ์ธ์ฆ, ๊ถํ๋ถ์ฌ ๋ฐ ์ผ๋ฐ์ ์ธ ๊ณต๊ฒฉ์ ๋ํ ๋ณดํธ๋ฅผ ์ ๊ณตํ๋ ํ๋ ์์ํฌ์ด๋ค. ๊ฐ๋ฐ์๊ฐ ๋ณด์ ์ค์ ์ ์ถ๊ฐ์ ์ผ๋ก ์ ๊ฒฝ์ฐ์ง ์๋๋ผ๋ ์์ ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ๊ตฌ์ถํ ์ ์๋
kiritoni.tistory.com
2. [Spring Security] docs : Architecture (1) - Filter
[Spring Security] docs : Architecture (1) - Filter
Spring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ ./mvnw spring-boot:run ... INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 8e557245-73e2-4286-969a
kiritoni.tistory.com
3. [Spring Security] docs: Architecture (2) - DelegatingFilterProxy
[Spring Security] docs: Architecture (2) - DelegatingFilterProxy
Spring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ ./mvnw spring-boot:run ... INFO 23689 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration : Using generated security password: 8e557245-73e2-4286-969a
kiritoni.tistory.com
4. [Spring Security] docs: Architecture (3) - FilterChainProxy & SecurityFilterChain
[Spring Security] docs: Architecture (3) - FilterChainProxy & SecurityFilterChain
2024.08.29 - [Spring Boot] - [Spring Security] docs: Architecture (2) - DelegatingFilterProxy [Spring Security] docs: Architecture (2) - DelegatingFilterProxySpring Security docs Hello Spring Security :: Spring SecurityRunning Spring Boot Application $ .
kiritoni.tistory.com
๐ฑ Spring Security docs ๋ฐ๋ก๊ฐ๊ธฐ
Architecture :: Spring Security
The Security Filters are inserted into the FilterChainProxy with the SecurityFilterChain API. Those filters can be used for a number of different purposes, like authentication, authorization, exploit protection, and more. The filters are executed in a spec
docs.spring.io
Spring Security์ ๋ณด์ ํํฐ๋ FilterChainProxy์ ์ฝ์ ๋๋ฉฐ, SecurityFilterChain API๋ฅผ ํตํด ๊ตฌ์ฑ๋๋ค. ์ด ํํฐ๋ค์ ํน์ ์์๋๋ก ์คํ๋์ด์ผ ์ฌ๋ฐ๋ฅธ ํ์ด๋ฐ์ ํธ์ถ๋ ์ ์๋ค. ์๋ฅผ ๋ค์ด, ์ธ์ฆ์ ์ํํ๋ ํํฐ๋ ๊ถํ ๋ถ์ฌ๋ฅผ ์ํํ๋ ํํฐ๋ณด๋ค ๋จผ์ ํธ์ถ๋์ด์ผ ํ๋ค.
ํํฐ์ ์์๋ฅผ ํญ์ ์ธ์ฐ๊ณ ์์ ํ์๋ ์์ง๋ง, ํ์ํ ๋์๋ `FilterOrderRegistration` ์ฝ๋๋ฅผ ํ์ธํ์ฌ ์์๋ฅผ ํ์ ํ ์ ์๋ค.
๐ ๋ณด์ ๊ตฌ์ฑ ๋ฐ ํํฐ ์์ ์์
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(Customizer.withDefaults()) // CSRF ํํฐ ์ถ๊ฐ
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated() // ๋ชจ๋ ์์ฒญ์ ๋ํด ์ธ์ฆ ํ์
)
.httpBasic(Customizer.withDefaults()) // HTTP ๊ธฐ๋ณธ ์ธ์ฆ ํํฐ ์ถ๊ฐ
.formLogin(Customizer.withDefaults()); // ํผ ๋ก๊ทธ์ธ ํํฐ ์ถ๊ฐ
return http.build();
}
}
์ด ๊ตฌ์ฑ์ ๋ค์๊ณผ ๊ฐ์ ์์๋ก ํํฐ๋ฅผ ์ถ๊ฐํ๋ค.
Filter | ์ถ๊ฐ ๋ฐฉ๋ฒ |
CsrfFilter | HttpSecurity#csrf |
UsernamePasswordAuthenticationFilter | HttpSecurity#formLogin |
BasicAuthenticationFilter | HttpSecurity#httpBasic |
AuthorizationFilter | HttpSecurity#authorizeHttpRequests |
1. CsrfFilter
์ฒซ ๋ฒ์งธ๋ก ์คํ๋์ด CSRF(Cross-Site Request Forgery) ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๋ค.
2. ์ธ์ฆ ํํฐ
๋ ๋ฒ์งธ๋ก ์คํ๋์ด ์์ฒญ์ ์ธ์ฆํ๋ค.
`UsernamePasswordAuthenticationFilter`(ํผ ๋ก๊ทธ์ธ์ ํตํ ์ธ์ฆ) ์ `BasicAuthenticationFilter`(HTTP ๊ธฐ๋ณธ ์ธ์ฆ)๊ฐ ์ธ์ฆ ํํฐ์ ํด๋นํ๋ค.
3. AuthorizationFilter
๋ง์ง๋ง์ผ๋ก ์คํ๋์ด ๊ถํ์ ๋ถ์ฌํ๋ค.
์์ฒญ์ด ์ธ์ฆ๋์๋์ง ํ์ธํ ๋ค, ์ฌ์ฉ์๊ฐ ์์ฒญ์ ์ก์ธ์คํ ๊ถํ์ด ์๋์ง ํ์ธํ๋ค.
ํํฐ๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ๊ธฐ์กด ํํฐ์ ๋์์ ๋ณ๊ฒฝํ๋ ค๋ฉด, ํํฐ๊ฐ ์ ํํ ์์๋ก ์คํ๋๋๋ก ๋ณด์ฅํด์ผ ํ๋ค. ๋ฐ๋ผ์ ํํฐ์ ์์๋ฅผ ์์๋๋ ๊ฒ์ด ์ข๋ค.
๋ณด์ ํํฐ ๋ชฉ๋ก์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ INFO ์์ค์์ ์ฝ์์ ์ถ๋ ฅ๋๋ค. ๋ค์๊ณผ ๊ฐ์ด ๋ด์ฉ์ ๋ณผ ์ ์๋ค.
2023-06-14T08:55:22.321-03:00 INFO 76975 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [
org.springframework.security.web.session.DisableEncodeUrlFilter@404db674,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@50f097b5,
org.springframework.security.web.context.SecurityContextHolderFilter@6fc6deb7,
org.springframework.security.web.header.HeaderWriterFilter@6f76c2cc,
org.springframework.security.web.csrf.CsrfFilter@c29fe36,
org.springframework.security.web.authentication.logout.LogoutFilter@ef60710,
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@7c2dfa2,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4397a639,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7add838c,
org.springframework.security.web.authentication.www.BasicAuthenticationFilter@5cc9d3d0,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7da39774,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@32b0876c,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3662bdff,
org.springframework.security.web.access.ExceptionTranslationFilter@77681ce4,
org.springframework.security.web.access.intercept.AuthorizationFilter@169268a7]
๐ ์ปค์คํ ํํฐ
Spring Security๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ํ ๊ธฐ๋ณธ ๋ณด์ ํํฐ๋ค์ ์ ๊ณตํ์ง๋ง, ํน์ ์๊ตฌ์ฌํญ์ ๋ง๋ ์ปค์คํ ํํฐ๋ฅผ ์ถ๊ฐํ ์๋ ์๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ํ์ฌ ์์ฒญ์ tenant ID ํค๋๋ฅผ ํ์ธํ์ฌ ํด๋น ํ ๋ํธ์ ๋ํ ์ ๊ทผ ๊ถํ์ด ์๋์ง ํ์ธํ๋ ํํฐ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์ ์๋ ์๋ค.
๐ป ์ฐธ๊ณ ์๋ฃ: Tenant ๋?
Tenant๋ '์์ฐจ์ธ'์ด๋ผ๋ ๋ป์ ๊ฐ์ง๊ณ ์๋ค. ์ฆ ์์ ์ ๊ฑด๋ฌผ์ด ์๋, ๋ค๋ฅธ ๊ฑด๋ฌผ์ ๋น๋ ค์ ์ฌ์ฉํ๋ ์ฃผ์ฒด์ด๋ค. ์ฌ๊ธฐ์์ ํ ๋ํธ๋ ํด๋ผ์ฐ๋ ์ปดํจํ , Saas(Software as a Service) ์ ํ๋ฆฌ์ผ์ด์ ์์์ ์์ฐจ์ธ์ ๋งํ๋ค. ์์ ์ ์์์ด ์๋ ์๋น์ค ์ ๊ณต์์ ํด๋ผ์ฐ๋ ์์์ ๋น๋ ค์ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ์ฃผ์ฒด๊ฐ Tenant์ด๋ค. ํด๋ผ์ฐ๋ ํ๋์ ์์์ ์ชผ๊ฐ์ tenant๋ค์๊ฒ ์ ๊ณตํ๋ ๊ฒ์ Multi Tenancy๋ผ๊ณ ํ๋ค. ํ ๋ํธ๋ง๋ค ๊ณ ์ ID๊ฐ ์๋ค. ์์ฒญ์ด ๋ค์ด์ฌ ๋ ์์คํ ์ ํ ๋ํธ ID ํค๋ ๋ฑ์ ํตํด ์์ฒญ์๊ฐ ์ด๋ค ํ ๋ํธ์ธ์ง ํ์ ํ๊ณ , ํด๋น ํ ๋ํธ์ ๋ง๋ ๋ก์ง์ ์ํํ๋ค. ํ ๋ํธ์ ์์๋ก๋ ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ ์ด๋ฉ์ผ ์๋น์ค (Microsoft 365, Google Workspace), ERP ์์คํ (SAP, Oracle ERP), ์์ ๋ฏธ๋์ด ๋๋ ํ์ ํด (Slack, Jira) ๋ฑ์ด ์๋ค. ์์ฝํ๋ฉด, ํ ๋ํธ๋ ๋ค์ค ํ ๋ํธ ํ๊ฒฝ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ณต์ ํ๋ ๊ฐ๊ฐ์ ๊ณ ๊ฐ์ด๋ ์ฌ์ฉ์ ๊ทธ๋ฃน์ ๋งํ๋ค. ๊ฐ ํ ๋ํธ๋ ์์ฒด์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ณ , ์ ํ๋ฆฌ์ผ์ด์ ๋ด๋ถ์ ์ผ๋ก๋ ๋ค๋ฅธ ํ ๋ํธ์ ๊ฒฉ๋ฆฌ๋ ์ํ๋ก ์กด์ฌํ๋ค.
1. ์ปค์คํ ํํฐ ์์ฑ (`TenantFilter`)
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
public class TenantFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// ์์ฒญ ํค๋์์ ํ
๋ํธ ID๋ฅผ ๊ฐ์ ธ์ด
String tenantId = request.getHeader("X-Tenant-Id");
// ํ์ฌ ์ฌ์ฉ์๊ฐ ํ
๋ํธ์ ์ ๊ทผํ ์ ์๋์ง ํ์ธ
boolean hasAccess = isUserAllowed(tenantId);
if (hasAccess) {
filterChain.doFilter(request, response); // ๋ค์ ํํฐ๋ก ์์ฒญ์ ์ ๋ฌ
return;
}
// ์ ๊ทผ ๊ถํ์ด ์์ ๊ฒฝ์ฐ ์์ธ๋ฅผ ๋ฐ์์ํด
throw new AccessDeniedException("Access denied");
}
}
2. ์ปค์คํ ํํฐ๋ฅผ ๋ณด์ ํํฐ ์ฒด์ธ์ ์ถ๊ฐํ๊ธฐ
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ๊ธฐ์กด ๋ณด์ ์ค์ ๋ค ...
.addFilterBefore(new TenantFilter(), AuthorizationFilter.class); // AuthorizationFilter ์์ TenantFilter๋ฅผ ์ถ๊ฐ
return http.build();
}
3. ํํฐ๋ฅผ ์คํ๋ง ๋น์ผ๋ก ์ ์ธํ ๋ ์ค๋ณต ํธ์ถ์ ๋ฐฉ์งํด์ผ ํ๋ค!
์ปค์คํ ํํฐ๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ ๋ (`@Component`๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ๊ตฌ์ฑ ํด๋์ค์์ ์ง์ ๋น์ ์ ์ธํ ๋) ์ฃผ์๊ฐ ํ์ํ๋ค.
Spring Boot๋ ๊ธฐ๋ณธ์ ์ผ๋ก Spring ๋น์ผ๋ก ๋ฑ๋ก๋ ํํฐ๋ฅผ ๋ด์ฅ ์ปจํ ์ด๋์ ์๋์ผ๋ก ๋ฑ๋กํ๋ค.
์ด ๊ฒฝ์ฐ, ํํฐ๊ฐ ์ปจํ ์ด๋์ ์ํด ํ ๋ฒ ํธ์ถ๋๊ณ , ์คํ๋ง ์ธํ๋ฆฌํฐ์ ์ํด ์ค๋ณต ํธ์ถ๋ ์ ์๋ค. ํํฐ๊ฐ ๋ ๋ฒ ํธ์ถ๋๋ฉด ์๋ชป๋ ์์๋ก ์คํ๋๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ๊ฐ๋ฅ์ฑ์ด ์๋ค.
์ค๋ณต ํธ์ถ์ ๋ฐฉ์งํ๊ธฐ ์ํด์ `FilterRegistrationBean`์ ์ฌ์ฉํ์ฌ ํํฐ์ ๋ฑ๋ก์ ๋นํ์ฑํํด์ผ ํ๋ค.
@Bean
public FilterRegistrationBean<TenantFilter> tenantFilterRegistration(TenantFilter filter) {
FilterRegistrationBean<TenantFilter> registration = new FilterRegistrationBean<>(filter);
registration.setEnabled(false); // ์ปจํ
์ด๋์ ํํฐ ๋ฑ๋ก ๋นํ์ฑํ
return registration;
}
๊ฒฐ๊ณผ์ ์ผ๋ก `TenantFilter`๋ ์ธ์ฆ ํํฐ๋ค ์ดํ, ๊ถํ ๋ถ์ฌ ํํฐ ์ด์ ์ ํธ์ถ๋๋ค. ์ปค์คํ ํํฐ๋ฅผ ์ถ๊ฐํ์ฌ Spring Security์ ๋ณด์ ์ฒด์ธ์ ํ์ฅํ๊ณ ๋ณด๋ค ์ธ๋ฐํ๊ฒ ์ ์ดํ ์ ์๊ฒ ๋๋ค.