Spring Security - Authenication & Authorization
๊ฐ์ธ ํ๋ก์ ํธ ๋ฐ ํ ํ๋ก์ ํธ์์ ์ธ์ฆ ๋ฐ ์ธ๊ฐ๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๊ธํ์์ต๋๋ค. ๊ทธ๋ฌ๋ค๋ณด๋ ์ด๊ฒ ์ด๋ค ์๋ฆฌ๋ก ๋์ํ๋์ง ์ดํด๋ฅผ ์ ๋๋ก ๋ชปํ ์ํ๋ก ๊ตฌํ๋ง ํ์ต๋๋ค. ๋๋ฌธ์ ๊ตฌํ์ด๋ ๋จ๋ค์๊ฒ ์ค๋ช ํ๋ฉด์๋ ๋ฏธ์ํจ์ด ๋ฌป์ด๋์ค๋ ๋ฏ ํ์ต๋๋ค. ์์ผ๋ก ๋ค๋ฃฌ๋คํ๊ณ ๋ฐ์๋ค๋ ํ๊ณ๋ก ์ง๋์ณค๋ ๊ฒ์ ์ ๋๋ก ์ดํดํ๋ ์๊ฐ์ ๊ฐ์ ธ๋ณด๋ คํฉ๋๋ค.
API์ ๊ถํ ๊ธฐ๋ฅ์ด ์์ผ๋ฉด, ์๋ฌด๋ ํ์ ์ ๋ณด๋ฅผ ์กฐํํ๊ณ ์์ ํ๋ฉฐ ์ญ์ ํ ์ ์์ต๋๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ ์ธ์ฆ๋ ์ ์ ์๊ฒ๋ง API๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ํด์ผ๋๋๋ฐ, ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ
Spring Security์
๋๋ค.
์คํ๋ง ํ๋ ์ ์ํฌ์์๋ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ๋ก ๋ฆฌ์์ค ์ฌ์ฉ์ ์ปจํธ๋กค ํ ์ ์๋ Spring Security๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณด์ ์ฒ๋ฆฌ๋ฅผ ์ฝ๊ฒ ์ฌ์ฉ ํ ์ ์์ต๋๋ค.
Spring Security Filter๋ Spring Security์ ํต์ฌ ์ปดํฌ๋ํธ ์ค ํ๋๋ก, ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๋ณด์์ ๋ด๋นํฉ๋๋ค.
Filter๋ Servlet Filter๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ฉฐ, ๋ค์ด์ค๋ ์์ฒญ(request)๊ณผ ๋๊ฐ๋ ์๋ต(response)๋ฅผ ๊ฐ๋ก์ฑ์
๋ณด์ ์ฒ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.
์ฌ์ฉ์(User)๊ฐ ์์ฒญ(Request)๋ฅผ ๋ณด๋ด๋ฉด, ๊ทธ ์์ฒญ์ ํํฐ ์ฒด์ธ์ ํต๊ณผํ๊ฒ ๋ฉ๋๋ค. ํํฐ ์ฒด์ธ์ ์ฌ๋ฌ ๊ฐ์ ์๋ธ๋ฆฟ ํํฐ(Servlet Filter)๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
๊ฐ ์๋ธ๋ฆฟ ํํฐ๋ ์์ฒญ์ ๊ฐ๋ก์ฑ์ ์ ์ฒ๋ฆฌ(pre-processing)์ ์ํํ ์ ์์ต๋๋ค. ์ด ๋, ํํฐ๋ ์์ฒญ์ ๋ณ๊ฒฝํ๊ฑฐ๋ ์ถ๊ฐ ์์ ์ ์ํํ ์ ์์ต๋๋ค. ๊ทธ ํ ํํฐ๋ doFilter() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์์ฒญ์ ๋ค์ ํํฐ ๋๋ ์ต์ข ๋ชฉ์ ์ง์ธ ์๋ธ๋ฆฟ(Servlet)์ผ๋ก ์ ๋ฌํฉ๋๋ค.
์์ฒญ์ด ๋ชจ๋ ํํฐ๋ฅผ ํต๊ณผํ๋ฉด, ์ต์ข ์ ์ผ๋ก ์๋ธ๋ฆฟ์ด ์์ฒญ์ ๋ฐ์ ์ฒ๋ฆฌํฉ๋๋ค. ์๋ธ๋ฆฟ์ ์์ฒญ์ ๋ํ ์๋ต(Response)๋ฅผ ์์ฑํฉ๋๋ค.
์๋ต์ ๋ค์ ํํฐ ์ฒด์ธ์ ์ญ์์ผ๋ก ํต๊ณผํฉ๋๋ค. ๊ฐ ํํฐ๋ ์๋ต์ ๋ํด ํ์ฒ๋ฆฌ(post-processing)๋ฅผ ์ํํ ์์์ต๋๋ค. ํํฐ๋ ์๋ต์ ๋ณ๊ฒฝํ๊ฑฐ๋ ์ถ๊ฐ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
//์ฌ๊ธฐ์ ์ ์ฒ๋ฆฌ
filterChain.doFilter(request, response);
//์ฌ๊ธฐ์ ํ์ฒ๋ฆฌ
}
Spring Web์์ ์ ๊ณตํ๋ ์ถ์ ํด๋์ค๋ก, ์ฌ์ฉ์ ์ ์ ํํฐ๋ฅผ ๋ง๋ค ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํฉ๋๋ค.
์ด ํด๋์ค๋ฅผ ์์๋ฐ์ผ๋ฉด ๋งค ์์ฒญ๋ง๋ค ํ ๋ฒ์ฉ ํํฐ๊ฐ ์คํ๋๋ ๊ฒ์ ๋ณด์ฅํ ์ ์์ต๋๋ค.
1. ํ์ ๊ฐ์
, ๋ก๊ทธ์ธ API ๊ตฌํ
2. ๋ฆฌ์์ค ์ ๊ทผ ๊ฐ๋ฅํ ROLE_USER ๊ถํ์ ๊ฐ์
ํ์์๊ฒ ๋ถ์ฌ
3. Spring Security ์ค์ ์์ ROLE_USER ๊ถํ์ ๊ฐ์ง๋ฉด ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก ์ธํ
4. ๊ถํ์ด ์๋ ํ์์ด ๋ก๊ทธ์ธ ์ฑ๊ณตํ๋ฉด ๋ฆฌ์์ค ์ ๊ทผ ๊ฐ๋ฅํ JWT ํ ํฐ ๋ฐ๊ธ
5. ํด๋น ํ์์ ๊ถํ์ด ํ์ํ API ์ ๊ทผ ์ JWT ๋ณด์ ํ ํฐ์ ์ฌ์ฉ
์ด์ฒ๋ผ ์ ๊ทผ ์ ํ์ด ํ์ํ API์๋ ๋ณด์ ํ ํฐ์ ํตํด์ ์ด ์ ์ ๊ฐ ๊ถํ์ด ์๋์ง ์ฌ๋ถ๋ฅผ Spring Security๋ฅผ ํตํด ํ์ธํ๊ณ ๋ฆฌ์์ค๋ฅผ ์์ฒญํ ์์๋๋ก ๊ตฌ์ฑ ํ ์ ์์ต๋๋ค.
Spring Security 5.7.0-M2 ๋ณด๋ค ๋์ ๋ฒ์ ์ WebSecurityConfigurerAdapter๊ฐ Deprecated๋์๊ธฐ์ ์ฌ์ฉํ์ง์์ต๋๋ค. ๋ฐ๋ผ์ SecurityFilterChain Bean์ ์ง์ ๊ตฌ์ฑํ๋ ๋ฐฉ์์ผ๋ก ์ ํํด์ผ ํฉ๋๋ค.
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
return http.build();
}
}
์ ๋ ์ด๋ฐ ์์ผ๋ก ์ฌ์ฉํ๋ ํธ์ ๋๋ค.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
private final UserDetailsServiceImpl userDetailsService;
public WebSecurityConfig(UserDetailsServiceImpl userDetailsService){
this.userDetailsService = userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception{
return configuration.getAuthenticationManager();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception{
return new JwtAuthenticationFilter(userDetailsService);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http.csrf((csrf) -> csrf.disable());
http.sessionManagement((sessionManagement) ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.authorizeHttpRequests((authorizeHttpRequests) ->
authorizeHttpRequests
.anyRequest().authenticated()); // ๋ชจ๋ ์์ฒญ ์ธ์ฆ ํ์
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
์์ผ๋ก ๊ธฐ์ ๋ฉด์ ์ค๋น๋ ํด์ผํ๋๋ฐ ์ค์ํ ์๊ฐ์ ๊ตฌํ ๋จผ์ ํ๋ฉด ์ต์ํด์ง๊ฒ ์ง๋ผ๋ ์์ผํ ๋ง์์ผ๋ก ์ ๋๋ก ๋ณด์ง์์๋ ๊ฒ๋ค์ด ๋ง์ต๋๋ค. ์ง๋์ณค๋ ๊ฒ๋ค์ ๋ง์ด ๋๋์๋ณด๋ฉฐ ์ ๋ฆฌํ๋ ์๊ฐ์ ๊ฐ์ ธ์ผ๊ฒ ์ต๋๋ค.