[๐Ÿš€ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…] Spring Security version

Dreamerยท2024๋…„ 4์›” 3์ผ
post-thumbnail

โ“ ๋ฌธ์ œ ์ƒํ™ฉ

: Spring Security Config ํŒŒ์ผ... ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์ง€?

โญ (๋ชฉํ‘œ) ํšŒ์›๊ด€๋ฆฌ API๋ฅผ ๊ตฌํ˜„ โžก๏ธ ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ
JWT๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„
Spring Security ์‚ฌ์šฉ์„ ์œ„ํ•ด configํŒŒ์ผ ์ƒ์„ฑ ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ์žˆ์—ˆ๋‹ค.
๊ฐ•์‚ฌ๋‹˜์˜ SpringBoot ๋ฒ„์ „์€ 2.5.6
๋‚˜์˜ SpringBoot ๋ฒ„์ „์€ 3.2.4... ๋น„๊ทน์˜ ์‹œ์ž‘์ด์—ˆ๋‹ค...๐Ÿ˜‚

SpringBoot ๋ฒ„์ „์— ๋”ฐ๋ผ์„œ ์„ค์ • ํŒŒ์ผ์ด ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ž๋‹ค
(SpringBoot 2.5.x ๋ฒ„์ „๊ณผ SpringBoot 2.6.x ๋ฒ„์ „์˜ ์„ค์ •๋„ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค)

๊ฐ•์‚ฌ๋‹˜์€ WebSecurityConfigurerAdapter๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•œ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ Security ๊ด€๋ จ ์„ค์ • ์ง„ํ–‰ํ•˜์˜€๊ณ , SpringBoot 3.2.4์—์„œ๋Š” ์•„์˜ˆ ์—†๋Š” ํ•จ์ˆ˜๋“ค์ด์—ˆ๋‹ค.


โฌ‡๏ธ Spring Security Config ์ž‘์„ฑ ๊ธฐ์กด ๋ฐฉ์‹ (SpringBoot 2.5.x~)
extends WebSecurityConfigurerAdapter ์ƒ์†๋ฐ›์•„ @Override๋กœ ์ž‘์„ฑ

package zerobase.dividends.security;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@Slf4j
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final JwtAuthenticationFilter authenticationFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                    .authorizeRequests()
                .antMatchers("/**/signup", "/**/signin").permiAll()
                .and()
                    .addFilterBefore(this.authenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(final WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/h2-consol/**");
    }

    // spring boot 2.x
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

โ—ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

: ๋Œ€์ฒด ์ฝ”๋“œ๋ฅผ ์ฐพ์•„๋ผ!!!

SpringBoot 3 Spring Security ์„ค์ •ํ•˜๊ธฐ ํญํ’ ๊ตฌ๊ธ€๋ง
WebSecurityConfigurerAdapter โžก๏ธ SecurityFilterChain ์œผ๋กœ ๋ณ€๊ฒฝ


์ฒซ๋ฒˆ์งธ ์ˆ˜์ • : ์‹คํŒจ... ์—๋Ÿฌ ํญ๋ฐœ ๐Ÿคฏ

500 Error๋„ ๋งŒ๋‚˜๊ณ , ์ค‘๊ฐ„์— parsig์ด ์ด์ƒํ•˜๋‹ค๋Š” ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋„ ๋งŒ๋‚˜๊ณ 
์ง„์งœ ์—„ ~ ์ฒญ ์—๋Ÿฌ ๋‚ด๋ฉด์„œ ๊ฒจ์šฐ ๋ณ€๊ฒฝํ–ˆ๋‹คใ…‹ใ…‹ใ…‹

package zerobase.dividends.security;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@Slf4j
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement((sessionManagement) ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .authorizeHttpRequests((authorizeRequests) ->
                        authorizeRequests
                                .requestMatchers("/**/signup", "/**/signin").permitAll())
                .addFilterBefore(this.jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }


    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/h2-console/**");
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

  • ๋‘๋ฒˆ์งธ ์ˆ˜์ • : 403 Error๋ฅผ ๋งŒ๋‚ฌ๋‹ค.

์ฝ”๋“œ๋ฅผ ์–ด๋А์ •๋„ ์ดํ•ดํ•˜๊ณ  ์กฐ๊ธˆ์”ฉ ์ˆ˜์ •
"/**/signup" โžก๏ธ "/*/signup"
๋žฉํ•‘๋˜์–ด์žˆ๋Š” ๊ฒƒ๋“ค ๋‹ค ๋ฒ—๊ฒจ์ฃผ๊ณ , ๋ณ€์ˆ˜๋ช…๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ!

package zerobase.dividends.security;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@Slf4j
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(sessionManagement ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .authorizeHttpRequests(auth -> auth
                                .requestMatchers("/*/signup", "/*/signin").permitAll())
                .addFilterBefore(this.jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }


    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring().requestMatchers("/h2-console/**");
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

  • ๋งˆ์ง€๋ง‰ ์ˆ˜์ • : ์„ฑ๊ณต

์ด๊ฑฐ ํ•œ์ค„์ด ๋น ์ ธ์žˆ์—ˆ๋‹ค... ์ด๊ฒŒ ์—†์–ด์„œ 403 Error
403์—๋Ÿฌ๋Š” ์ง„์งœ ๊ทน์•…์ธ๊ฒŒ ๋กœ๊ทธ๋„ ์—๋Ÿฌ์ฝ”๋“œ๋„ ์•ˆ๋‚˜์™€์„œ 4์‹œ๊ฐ„์€ ์‚ฝ์งˆํ–ˆ๋‹ค..
์›์ธ ์ฐพ๋Š”๋‹ค๊ณ  ๋กœ๊ทธ๋กœ ๊ธฐ๋ก ๋‹ค ๋‚จ๊ธฐ๊ณ , ๋ฃจํŠธ ๋กœ๊ทธ ๋ ˆ๋ฒจ๋„ debug ๋กœ ๋ณ€๊ฒฝ!
logging.level.root=debug

์ฝ”๋“œ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ๋น ์กŒ๋‚˜๋ณด๋‹ค๐Ÿซ 

.anyRequest().authenticated ํ”„๋กœ์ ํŠธ ๋๋‚˜๋ฉด ํ•œ ์ค„ ํ•œ ์ค„ ๋œฏ์–ด์ฃผ๋งˆ

package zerobase.dividends.security;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@Slf4j
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(sessionManagement ->
                        sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .authorizeHttpRequests(auth -> auth
                                .requestMatchers("/*/signup", "/*/signin").permitAll()
                                .anyRequest().authenticated())
                .addFilterBefore(this.jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }


    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring().requestMatchers("/h2-console/**");
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

๐Ÿ’ก ๋งˆ๋ฌด๋ฆฌ

์ค‘๊ฐ„์— ํฌ๊ธฐํ•˜๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ, ์˜ค๊ธฐ๊ฐ€ ์ƒ๊ฒจ์„œ ๋ฐค์ƒˆ ์ฝ”๋“œ๋ž‘ ์‹ธ์› ๋‹ค๐Ÿซ 
์ฒ˜์Œ ์—๋Ÿฌ๊ฐ€ ์‹œ์ž‘๋˜๊ณ  ๊ฑฐ์˜ 12์‹œ๊ฐ„๋งŒ์— ํ•ด๊ฒฐํ–ˆ๋‹ค....
์—๋Ÿฌ ํ•˜๋‚˜๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉด ๋‹ค์Œ ์—๋Ÿฌ๊ฐ€ ๋‚˜์˜ค๊ณ ,
200๋ณด๊ณ  ๋ฐ•์ˆ˜์น˜๊ณ  ์ข‹์•„ํ•˜๋‹ค ๋‹ค์‹œ ๋งŒ๋‚œ 505...403...

  1. ์—๋Ÿฌ์ฝ”๋“œ๊ฐ€ ๋‹ค์–‘ํ•˜๋‹ค๋Š” ๊ฑธ ๊นจ๋‹ฌ์•˜๋‹ค.
  2. ๋ฒ„์ „์˜ ํ˜ธํ™˜์„ฑ?์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ๋„ ์•Œ๊ฒŒ ๋ฌ๋‹ค.
  3. ํ”„๋กœ์ ํŠธ๊ฐ€ ๋๋‚˜๋ฉด JWT(Json Web Token) ๊ณต๋ถ€ํ•˜๊ธฐ

โฌ‡๏ธ ๊ณต์‹ ์‚ฌ์ดํŠธ

https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter

โฌ‡๏ธ ๋„์›€๋ฐ›์€ ๋ธ”๋กœ๊ทธ
https://velog.io/@hwsa1004/SpringBoot-3.1.0-SpringSecurity-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

https://covenant.tistory.com/277

https://ttmcr.tistory.com/entry/Spring-Security-WebSecurityConfiguration-%EC%B4%9D%EC%A0%95%EB%A6%AC?category=1367905

https://www.inflearn.com/questions/1078794/spring-boot-%EC%B5%9C%EC%8B%A0-%EB%B2%84%EC%A0%84-3-1-5-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC

profile
Moving forward based on records

0๊ฐœ์˜ ๋Œ“๊ธ€