728x90
๋ฐ์ํ
@RequiredArgsConstructor
@Configuration
public class WebOAuthSecurityConfig {
// ์คํ๋ง ์ํ๋ฆฌํฐ ๊ธฐ๋ฅ ๋นํ์ฑํ
@Bean
public WebSecurityCustomizer configure() {
return (web) -> web.ignoring()
.requestMatchers(toH2Console())
.requestMatchers("/img/**", "/css/**", "/js/**");
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// ๊ธฐ์กด์ ์ฌ์ฉํ๋ ํผ ๊ณ ๋ฅด์ธ, ์ธ์
๋นํ์ฑํ
http.csrf(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.logout(AbstractHttpConfigurer::disable);
// ์ธ์
์ ์ฌ์ฉํ์ง ์๊ณ , ๋ฌด์ํ(Stateless) ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ๋๋ก ์ค์
http.sessionManagement(sessionManagement -> sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
// ํค๋๋ฅผ ํ์ธํ ์ปค์คํ
ํํฐ ์ถ๊ฐ
http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.authorizeHttpRequests(request -> request
.requestMatchers("/api/token").permitAll()
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll());
// oauth2Login
http.oauth2Login(oauth2Login -> oauth2Login
.loginPage("/login")
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint
.authorizationRequestRepository(oAuth2AuthorizationRequestBasedOnCookieRepository()))
.successHandler(oAuth2SuccessHandler())
.userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint
.userService(oAuth2UserCustomService)));
// ๋ก๊ทธ์์
http.logout(logout -> logout
.logoutSuccessUrl("/login"));
// ์์ธ์ฒ๋ฆฌ
http.exceptionHandling(exceptionHandling -> exceptionHandling
.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
new AntPathRequestMatcher("/api/**")));
return http.build();
}
@Bean
public OAuth2SuccessHandler oAuth2SuccessHandler() {
return new OAuth2SuccessHandler(tokenProvider,
refreshTokenRepository,
oAuth2AuthorizationRequestBasedOnCookieRepository(),
userService
);
}
@Bean
public TokenAuthenticationFilter tokenAuthenticationFilter() {
return new TokenAuthenticationFilter(tokenProvider);
}
@Bean
public OAuth2AuthorizationRequestBasedOnCookieRepository oAuth2AuthorizationRequestBasedOnCookieRepository() {
return new OAuth2AuthorizationRequestBasedOnCookieRepository();
}
// ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํ ํ๋ค.
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
- csrf ๋นํ์ฑํ
CSRF(Cross-Site Request Forgery) ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๊ธฐ ์ํ ๊ธฐ๋ฅ์ Spring Security์์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์๋ค. ํ์ง๋ง ํน์ ์ํฉ์์๋ CSRF ๋ณดํธ๋ฅผ ๋นํ์ฑํํ๋ ๊ฒ์ด ์ข๋ค.
- CSRF ๋ณดํธ๋ ์ฃผ๋ก ์ธ์
์ ์ฌ์ฉํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์
์์ ํ์ํ์ง๋ง, JWT ๊ธฐ๋ฐ ์ธ์ฆ์ด๋ ๋ฌด์ํ API ์๋ฒ์์๋ CSRF ๋ณดํธ๊ฐ ํ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋นํ์ฑํํ๋ค.
REST API, OAuth2, JWT ๋ฑ์ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ CSRF๋ฅผ ๋นํ์ฑํํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ธ ์ด์ .
CSRF ๊ณต๊ฒฉ์ด๋?
: ์ฌ์ฉ์๊ฐ ์์ ์ ์์ง์ ๋ฌด๊ดํ๊ฒ ๊ณต๊ฒฉ์๊ฐ ์๋ํ ํ๋์ ํด์ ํน์ ์นํ์ด์ง๋ฅผ ๋ณด์์ ์ทจ์ฝํ๊ฒ ํ๋ค๊ฑฐ๋ ์์ , ์ญ์ ๋ฑ์ ์์ ์ ํ๊ฒ ๋ง๋๋ ๊ณต๊ฒฉ ๋ฐฉ๋ฒ
- CSRF ๋ณดํธ๋ ์ฃผ๋ก ์ธ์
์ ์ฌ์ฉํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์
์์ ํ์ํ์ง๋ง, JWT ๊ธฐ๋ฐ ์ธ์ฆ์ด๋ ๋ฌด์ํ API ์๋ฒ์์๋ CSRF ๋ณดํธ๊ฐ ํ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋นํ์ฑํํ๋ค.
- addFilterBefore()
ํค๋ ๊ฐ์ ํ์ธํ ์ปค์คํ ํํฐ ์ถ๊ฐ
//์ธ์
์ ์ฌ์ฉํ์ง ์๊ณ , ๋ฌด์ํ(Stateless) ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ๋๋ก ์ค์
http.sessionManagement(sessionManagement -> sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
๋ฌด์ํ(Stateless) ๋ฐฉ์์ ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์ํ ์ ๋ณด๋ฅผ ์ ์ฅํ์ง ์๋ ๋ฐฉ์. ๊ฐ ์์ฒญ์ ๋ ๋ฆฝ์ ์ด๋ฉฐ, ์ด์ ์์ฒญ์ด๋ ์ดํ ์์ฒญ๊ณผ๋ ์๋ก ๊ด๊ณ๊ฐ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ ๋๋ง๋ค ์ธ์ฆ ์ ๋ณด๋ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ํจ๊ป ๋ณด๋ด์ผ ํ๋ฏ๋ก, ์๋ฒ๋ ๋งค๋ฒ ์๋ก์ด ์์ฒญ์ผ๋ก ์ฒ๋ฆฌํ๊ฒ ๋๋ค.
- ์ฅ์ : ์๋ฒ ํ์ฅ์ฑ, ์๋ฒ๊ฐ ์ํ๋ฅผ ๊ด๋ฆฌํ์ง ์๊ธฐ ๋๋ฌธ์, ์ฌ๋ฌ ์๋ฒ์ ์์ฒญ์ ๋ถ์ฐํ๊ฑฐ๋ ์๋ก์ด ์๋ฒ๋ฅผ ์ถ๊ฐํ ๋ ์ฉ์ดํฉ๋๋ค.
๋๋์ ํธ๋ํฝ์ด ๋ฐ์ํ๋๋ผ๋ ์๋ฒ ์์์ ๋ถ๋ด์ด ๋ํ๊ณ ๋์์ด ์์ํ๋ค. - ๋จ์ : ๋ฐ์ดํฐ ์๋ชจ, ๋งค๋ฒ ์์ฒญ ์ ํด๋ผ์ด์ธํธ๊ฐ ์ธ์ฆ ์ ๋ณด๋ ๊ธฐํ ์ํ ์ ๋ณด๋ฅผ ํจ๊ป ๋ณด๋ด์ผ ํจ.
์์ฒญ๋ง๋ค ๋ฐ์ดํฐ ์์ด ๋์ด๋ ๋คํธ์ํฌ ์์์ด ๋ ๋ง์ด ์๋ชจ๋ค.. Stateful ๋ฐฉ์์ ๋นํด ๋ฐ์ดํฐ ์ ์ก ๋ถ๋ด์ด ์ฆ๊ฐํ๋ค.
http.authorizeHttpRequests(request -> request
.requestMatchers("/api/token").permitAll() // "/api/token" ๊ฒฝ๋ก๋ ๋๊ตฌ๋ ์ ๊ทผ ๊ฐ๋ฅ
.requestMatchers("/api/**").authenticated() // "/api/**" ๊ฒฝ๋ก๋ ์ธ์ฆ๋ ์ฌ์ฉ์๋ง ์ ๊ทผ ๊ฐ๋ฅ
.anyRequest().permitAll() // ๊ทธ ์ธ ๋ชจ๋ ๊ฒฝ๋ก๋ ์ธ์ฆ ์ฌ๋ถ์ ๊ด๊ณ์์ด ์ ๊ทผ ๊ฐ๋ฅ
);
- authorizeHttpRequests()
ํ ํฐ ์ฌ๋ฐ๊ธ URL ์ธ์ฆ ์์ด ์ ๊ทผ์ด ๊ฐ๋ฅํ๋๋ก ์ค์ ํ๊ณ ๋๋จธ์ง API๋ค์ ๋ชจ๋ ์ธ์ฆํด์ผ ์ ๊ทผํ๋๋ก ์ค์ - .permitAll() - ๋ชจ๋ ์ ๊ทผ์ ํ์ฉํ๋ค.
- .authenticated() - ํน์ ๊ฒฝ๋ก์ ๋ํด ์ธ์ฆ๋ ์ฌ์ฉ์๋ง ์ ๊ทผํ๋๋ก ํจ
- .anyRequest() - ๋ชจ๋ ์์ฒญ์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ง์ ํ๋ค. ์ค์ ์ธ ์์ฒญ๋ค์ ์ค์
Oauth ๋ก๊ทธ์ธ ์ค์
http.oauth2Login(oauth2Login -> oauth2Login
.loginPage("/login")
// ์ธ์ฆ ์์ฒ์ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ ์ค์
.authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint
.authorizationRequestRepository(oAuth2AuthorizationRequestBasedOnCookieRepository()))
// ์ฑ๊ณตํ์์ ๋ ( ํ ํฐ ๋๋ ๋ฆฌ๋ค์ด๋ ํธ )
.successHandler(oAuth2SuccessHandler())
// ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ๋
.userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint
.userService(oAuth2UserCustomService)));
- OAuth2 ๋ก๊ทธ์ธ ํ์ด์ง ๊ฒฝ๋ก๋ /login ํ์ด์ง๋ก ์ค์
- authorizationRequestRepository()
์ธ์ฆ ์์ฒญ ์ ๋ณด๋ฅผ ์ด๋์ ์ ์ฅํ ์ง ๊ฒฐ์ ,
์ฌ๊ธฐ์๋ oAuth2AuthorizationRequestBasedOnCookieRepository()๋ฅผ ์ฌ์ฉํ์ฌ ์ฟ ํค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ธ์ฆ ์์ฒญ ์ ๋ณด๋ฅผ ์ ์ฅ
= OAuth ๋ก๊ทธ์ธ์ ์ฟ ํค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ธ์ฆ์ ๋ณด๋ฅผ ์ ์ฅํ๋ค. - ์ธ์ฆ ํ ์ฑ๊ณต ์ฒ๋ฆฌ ๋ก์ง(oAuth2SuccessHandler)๊ณผ ์ฌ์ฉ์ ์ ๋ณด ๋ก๋ ๋ก์ง(oAuth2UserCustomService)์ ์ค์
// ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํ ํ๋ค.
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
- BCryptPasswordEncoder()
BCrypt ํด์ ํจ์๋ฅผ ์ฌ์ฉํด ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ๋ ์ญํ
ํด์๋ ๋น๋ฐ๋ฒํธ๋ ๋ณตํธํ๋์ง ์์ผ๋ฉฐ, ๋์ ๋น๋ฐ๋ฒํธ๊ฐ ๋ง๋์ง ํ์ธํ๋ ๊ณผ์ ์์ ๋น๊ต ๊ฒ์ฆ์ ์ํ
ํด๋น ๊ธ์ ์๋ ๋์์ ๋ด์ฉ์ ์ฐธ๊ณ ํ๋ฉฐ ์ ๋ฆฌํ ๊ฐ์ธํ์ต์ฉ ๊ธ์
๋๋ค.
์คํ๋ง ๋ถํธ 3 ๋ฒก์๋ ๊ฐ๋ฐ์ ๋๊ธฐ - ์๋ฐ ํธ, ์ ์ ์
๋ฐ์ํ
'TIL > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Security ํ์ผ ์ค์ ํ๊ธฐ (0) | 2024.10.04 |
---|---|
JWT ํ ํฐ ๊ธฐ๋ฐ ๊ฐ๋ ์์๋ณด๊ธฐ (0) | 2024.08.12 |
thymeleaf layout ์ ์ฉํ๊ธฐ (header, footer, main) (0) | 2024.01.26 |
jre jdk ์ฐจ์ด (0) | 2024.01.18 |
java lombok annotation ์์๋ณด์ (0) | 2024.01.14 |