-
Notifications
You must be signed in to change notification settings - Fork 0
Spring Security
์ ์ฒด์ ์ธ ์คํ๋ง ์ํ๋ฆฌํฐ ํ๋ฆ
- Http Request ์์
- ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ ์ ๋ณด์ ํจ๊ป ์ธ์ฆ ์์ฒญ์ ํ๋ค.
- AuthenticationFilter๊ฐ ์์ฒญ์ ๊ฐ๋ก์ฑ๊ณ , ๊ฐ๋ก์ฑ ์ ๋ณด๋ก UsernamePasswordAuthenticationToken์ ์ธ์ฆ ์ฉ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
- AuthenticationManager์ ๊ตฌํ์ฒด์ธ ProviderManger์๊ฒ ์์ ์์ฑํ UsernamePasswordToken ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๋ค.
- AuthenticationManager๋ ๋ฑ๋ก๋ AuthenticationProvider ๋ฆฌ์คํธ ์ค์์ ์ฒ๋ฆฌํ ์ ์๋ provider์๊ฒ ์ธ์ฆ ์ฒ๋ฆฌ๋ฅผ ์์ํ๋ค.
- ์์ ์ ํ๋ AuthenticationProvider๊ฐ ๋ฑ๋ก๋ UserDetailsService(์ง์ ๊ตฌํ ๊ฐ๋ฅ)์๊ฒ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋๊ฒจ์ฃผ๊ฒ ๋๋ค.
- UserDetailsService๋ ๋๊ฒจ ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํตํด DB์์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฐพ๊ฒ๋๊ณ , ์ฐพ์ ์ ๋ณด๋ก UserDetails ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋๊ฒจ์ค๋ค.(UserDetails ์ง์ ๊ตฌํ ๊ฐ๋ฅ)
- AuthenticationProvider ๋ค์ UserDetails๋ฅผ ๋๊ฒจ ๋ฐ๊ณ , UsernamePasswordAuthenticationToken์ ์ฌ์ฉ์ ์ ๋ณด์ ๋น๊ตํ๋ค.
- ์ธ์ฆ์ด ์๋ฃ๋๋ฉด AuthenticationManager(ProviderManager)๊ฐ ์ฌ์ฉ์ ์ ๋ณด์ ๊ถํ ๋ฑ์ ํฌํจํ๊ณ ์๋ Authentication ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํด์ค๋ค.
- AuthenticationFilter์ Authentication๊ฐ์ฒด๊ฐ ๋ฐํ ๋์ด์ง๋ค.
- SecurityContext์ ์์ญ์ Authentication๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ค.
- ์ฆ, 10๋ฒ๊น์ง ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋์๋ค๋ฉด SecurityContextHolder๋ ์ธ์ ์์ญ์ ์๋ SecurityContext์ Authentication ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
**PICKME์ ์คํ๋ง ์ํ๋ฆฌํฐ ์ ์ฉํ๊ธฐ ~ **
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers(
PathRequest.toStaticResources().atCommonLocations()
);
}
- ์ด๋ถ๋ถ์ css, js, ์ด๋ฏธ์ง ๋ฑ **
์ ์ ๋ฆฌ์์ค
**์ ๋ํ ๋ณด์์ ์ ์ฉํ์ง ์๊ธฐ ์ํด ์ค์ ํ ๋ถ๋ถ
@Bean
public SecurityFilterChain userfilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder managerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
configureAuthenticationManager(managerBuilder, userDetailService);
return commonSecurityFilter(http, "/user/**", "/user/loginForm", "/user/login", "/user/loginForm?error=true");
}
@Bean
public SecurityFilterChain adminfilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder managerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
configureAuthenticationManager(managerBuilder, customosDetailService);
return commonSecurityFilter(http, "/customs/**", "/customs/loginForm", "/customs/login", "/customs/loginForm?error=true");
}
ํ์ฌ ์ฐ๋ฆฌ ํ๋ก์ ํธ์์๋ ๊ด๋ฆฌ์(Customs)์ ์ฌ์ฉ์(User)๊ฐ ๋ฐ๋ก ์๊ธฐ ๋๋ฌธ์
๊ฐ๊ฐ์ ๋ณด์ ์ค์ ์ ๋ณ๋๋ก ๊ตฌ์ฑํ๊ณ ํ๋ค.
- SecurityFilterChain์ ๋น์ผ๋ก ๋ฑ๋กํ์ฌ, ์์ฒญ ๊ฒฝ๋ก๋ณ๋ก ๊ฐ๊ฐ ๋ค๋ฅธ ๋ณด์ ์ค์ ์ ์ ์ฉํ๋ค.
-
userFilterChain
- /user/** ๊ฒฝ๋ก์ ๋ํ ๋ณด์ ์ค์ ์ ์ฉ
- ์ฌ์ฉ์ ์ธ์ฆ์ ์ํด userDetailService๋ฅผ ์ค์
-
adminFilterChain()
- /customs/** ๊ฒฝ๋ก์ ๋ํ ๋ณด์ ์ค์ ์ ์ฉ
- ๊ด๋ฆฌ์ ์ธ์ฆ์ ์ํด customosDetailService๋ฅผ ์ค์
private void configureAuthenticationManager(AuthenticationManagerBuilder managerBuilder, UserDetailsService userDetailsService) throws Exception {
managerBuilder.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
- ๊ณตํต ๋ณด์ ์ค์ ๋ฉ์๋
- ์ฃผ์ด์ง UserDetailService์ BcryptPasswordEncoder๋ฅผ ์ฌ์ฉํ์ฌ ์ธ์ฆ ๊ด๋ฆฌ์(AuthenticationManager)๋ฅผ ๊ตฌ์ฑ
private SecurityFilterChain commonSecurityFilter(HttpSecurity http, String securityMatcher, String loginPage, String loginProcessingUrl, String failureRedirectUrl) throws Exception {
http
.securityMatcher(securityMatcher)
.formLogin(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(securityMatcher).permitAll()
.anyRequest().authenticated())
.formLogin(form -> form
.loginPage(loginPage)
.usernameParameter("id")
.loginProcessingUrl(loginProcessingUrl)
.successHandler(authenticationSuccessHandler())
.failureHandler((request, response, exception) -> {
response.sendRedirect(failureRedirectUrl);
}).permitAll()
)
.sessionManagement(sessionManagementConfigurer ->
sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.sessionFixation(SessionManagementConfigurer.SessionFixationConfigurer::changeSessionId)
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.expiredUrl(loginPage));
return http.build();
}
- ๋ก๊ทธ์ธ ํ์ด์ง, ๋ก๊ทธ์ธ ์ฒ๋ฆฌ, URL ์ฒ๋ฆฌ, ์ฑ๊ณต/์คํจ ํธ๋ค๋ฌ ๋ฑ์ ์ค์
- authenticationSuccessHandler() ์ธ์ฆ ์ฑ๊ณต ํธ๋ค๋ฌ๋ฅผ ๊ตฌํํ์ฌ ์ธ์ฆ์ ์ฑ๊ณตํ ์ฌ์ฉ์์ ๊ถํ์ ๋ฐ๋ผ redirect ํ ์ฑ๊ณต ํ๋ฉด์ ๋ค๋ฅด๊ฒ ๊ตฌํํจ(์ ํํ ๊ตฌํ์ ์ฝ๋ ์ฐธ๊ณ !)
์ฌ๊ธฐ๊น์ง ์ ์ฒด์ ์ธ ํ๋ฆ์
- ์ฌ์ฉ์๊ฐ /user/loginForm URL๋ก GET ์์ฒญ์ ๋ณด๋ธ๋ค.
- Spring Security๋ ์ด ์์ฒญ์ ๋ฐ์ ์ฒ๋ฆฌํ๋ค.
-
SecufityFilterChain ํ์
- Spring Security๋ ์์ฒญ URL์ด /user/** ํจํด๊ณผ ์ผ์นํ๋์ง ํ์ธํ๋ค.
- ์ด ํจํด์ userFilterChain(HttpSecurity http) ๋ฉ์๋์์ ์ค์ ๋ SecurityFilterChain์ ์ํด ์ฒ๋ฆฌ๋๋ค.
- Form Login ์ค์ ํ์ธ
- userFilterChain ๋ฉ์๋์ commonSecuiryFilter ๋ฉ์๋์์ formLogin() ์ค์ ์ ํ์ธํด์ ์ค์ ๋ loginPage์ธ /user/loginForm์ผ๋ก ํ์ด์ง๋ฅผ ์ด๋
- ๋ก๊ทธ์ธ ํผ ์ ๊ณต
- /user/loginForm ์์ฒญ์ด ๋ค์ด์ค๋ฉด ์คํ๋ง ์ํ๋ฆฌํฐ๋ ์ด ์์ฒญ์ ์ฒ๋ฆฌํ์ฌ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ๋ฐํํ๋ค.
- ์ฌ์ฉ์๋ก๋ถํฐ username, password๋ฅผ ์ ๋ ฅ๋ฐ๋ ์ญํ ์ ํ๋ค.
- ๋ก๊ทธ์ธ ํ์ด์ง ์๋
- ์ฌ์ฉ์๋ id ์ password๋ฅผ ์ ๋ ฅํ๊ณ , ๋ก๊ทธ์ธ ๋ฒํผ์ ํด๋ฆญํ์ฌ ํผ์ ์ ์ถ
- ์ด๋ loginProcessingUrl๋ก ์ง์ ๋ /user/login ์ผ๋ก POST ์์ฒญ์ ๋ณด๋ธ๋ค.
- ๋ก๊ทธ์ธ ์ธ์ฆ ์ฒ๋ฆฌ
- /user/login ์์ฒญ์ด ๋ค์ด์ค๋ฉด, Spring Security๋ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ id์ password๋ฅผ userDetailService๋ฅผ ํตํด ๊ฒ์ฆํ๋ค.
- userDetailService๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ ์ ๋ ฅ๋ ๋น๋ฐ๋ฒํธ๊ฐ ๋ง๋์ง ํ์ธํ๋ค.
- ์ธ์ฆ ์ฑ๊ณต/์คํจ ์ฒ๋ฆฌ
- ๋ง์ฝ ์ธ์ฆ์ด ์ฑ๊ณตํ๋ฉด ์์์ ์ค์ ํ .successHandler(authenticationSuccessHandler()) ์ ์ค์ ํ ๋๋ก ์คํ๋๋ค
- ์คํจํ ๊ฒฝ์ฐ .failureHandler ์ค์ ํ ๋๋ก ์คํ๋๋ค.
์ดํ์ ๊ณผ์ ์ ์์์ ์ํ๋ฆฌํฐ ํ๋ฆ์ 8๋ฒ ์ดํ ๊ณผ์ ์ด ์งํ๋๋ค.
8๋ฒ ์ดํ์ ์์ฑ๋ Authenticaition ๊ฐ์ฒด๋ฅผ ํตํด์ @CurrentUser ์ด๋ ธํ ์ด์ ์ ๊ตฌํํ์ฌ ๋ก๊ทธ์ธ ๋ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค!(์ด ๋ถ๋ถ์ ๋ค๋ฅธ ๊ณณ์ ์ ๋ฆฌ)
.sessionManagement(sessionManagementConfigurer ->
sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.sessionFixation(SessionManagementConfigurer.SessionFixationConfigurer::changeSessionId)
.maximumSessions(1) //ํ ์ ์ ๊ฐ ๊ฐ์ง ์ ์๋ ์ต๋ ์ธ์
๊ฐ์
.maxSessionsPreventsLogin(true)
.expiredUrl("/user/loginForm"));
-
maximumSession(1)
: ์ต๋ ํ์ฉ ๊ฐ๋ฅ ์ธ์ ์๋ฅผ ์ค์ - -1๋ก ๋ฃ์ผ๋ฉด ๋ฌด์ ํ ์ธ์ ์์ฑ ํ์ฉ
-
maxSessionPreventsLogin(true)
: ์์์ ์ค์ ํ ์ต๋ ํ์ฉ ์ธ์ ์ ์๊ฐ ๋์์ ๋ ์ถ๊ฐ์ ์ธ ์ธ์ฆ์ด ์์ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ์ค์ - true๋ฉด ํ์ฌ ์ฌ์ฉ์ ์ธ์ฆ ์คํจ, false(default)๋ฉด ๊ธฐ์กด ์ธ์ ๋ง๋ฃ
-
expiredUrl(โ/user/loginFormโ)
: ์ธ์ ์ด ๋ง๋ฃ๋ ๊ฒฝ์ฐ ์ด๋ ํ ํ์ด์ง๋ฅผ ์ค์
maximumSession(1)
์ต๋ ์ธ์
๊ฐ์์ผ ๋ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ
- ์ด์ ์ฌ์ฉ์ ์ธ์ ๋ง๋ฃ
- ์ฌ์ฉ์ 1์ด ๋ก๊ทธ์ธ์ ํ๋ฉด ์๋ฒ์ ํด๋น ๊ณ์ ์ ๋ํ ์ธ์ ์ด ์์ฑ๋๋ค.
- ์ฌ์ฉ์ 2๊ฐ ์ฌ์ฉ์1๊ณผ ๋์ผ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ ์๋ํ๊ฒ ๋๋ฉด ์ฌ๋ฌ filter ์ค SessionManageMentFilter์์ maximumSession()์ ๊ฐ์ด 1์ธ ๊ฒ์ ํ์ธํ๋ค.
- ์๋ฒ๋ ์๋กญ๊ฒ ์ ๊ทผ์ ์๋ํ ์ฌ์ฉ์ 2์ ์ธ์ ์ ์๋ก ์์ฑํ๊ณ ์ธ์ฆ์ ํด์ฃผ๋ฉฐ ์ฌ์ฉ์ 1์์ธ์ ์ session.isExpired() == true๋ก ๋ณ๊ฒฝํ์ฌ ์ธ์ ๋ง๋ฃ ์ค์ ์ ํด์ค๋ค.
- ์ฌ์ฉ์ 1์ด ๋ค์ request๋ฅผ ์์ฒญํ๋ฉด ConcurrentSessionFilter์์ session.isExpired()๊ฐ์ ํ์ธํ์ฌ ์ธ์ ๋ง๋ฃ์ฌ๋ถ๋ฅผ ํ์ธ ํ ์๋ก์ด ์ธ์ ์ ๋ง๋ค๋๋ก ์ธ์ฆ ์์ฒญ์ ํ๊ฒ ๋๋ค.
- ์๋ก์ด ์ฌ์ฉ์ ์ธ์ฆ ์คํจ
- ์ฌ์ฉ์ 1์ด ๋ก๊ทธ์ธ์ ํ๋ฉด ์๋ฒ์ ํด๋น ๊ณ์ ์ ๋ํ ์ธ์ ์ด ์์ฑ๋๋ค.
- ์ฌ์ฉ์ 2๊ฐ ์ฌ์ฉ์1๊ณผ ๋์ผ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ ์๋ํ๊ฒ ๋๋ฉด ์ฌ๋ฌ filter ์ค SessionManageMentFilter์์ maximumSession()์ ๊ฐ์ด 1์ธ ๊ฒ์ ํ์ธํ๋ค.
- ์๋ฒ์์๋ ์ฌ์ฉ์ 2์ ์ธ์ ์ ์์ฑ๋์ง ์๊ณ ์ธ์ฆ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค.
๐ก**์ธ์ ๊ด๋ จ ํํฐ
ConcurrentSessionFilter**
- ๋งค ์์ฒญ๋ง๋ค ์ฌ์ฉ์์ ์ธ์ ์ session.isExpired() ์ฌ๋ถ๋ฅผ ํ์ธํ์ฌ ์ธ์ ์ด ๋ง๋ฃ ๋์์ ๊ฒฝ์ฐ ๋ก๊ทธ์์์ฒ๋ฆฌ(๋ง๋ฃ ์ฒ๋ฆฌ)๋ฅผ ํด์ฃผ๋ ํํฐ
SessionManageMentFilter
- ๋์์ ์ธ์ ์ ์ด, ์ธ์ ๊ณ ์ ๋ณดํธ, ์ธ์ ์์ฑ ์ ์ฑ ๋ฑ์ ์ธ์ ์ ์ ๋ฐ์ ์ธ ๊ด๋ฆฌ๋ฅผ ํด์ฃผ๋ ํํฐ
http.sessionManagement()
.sessionFixation().changeSessionId()
-
changeSesseionId()
: ์ฌ์ฉ์๊ฐ ์ธ์ฆ์ ์๋ํ๊ฒ ๋๋ฉด ์ฌ์ฉ์ ์ธ์ ์ ๊ทธ๋๋ก ๋๊ณ ์ธ์ ์์ด๋๋ง ๋ณ๊ฒฝ ํ๋ค -
migrateSession()
: ์๋ก์ด ์ธ์ ์ ์์ฑํ๊ณ ์ธ์ ์์ด๋๋ ์๋ก ๋ฐ๊ธํ๋ฉฐ migrationํ๋ค.(์๋ธ๋ฆฟ 3.1์ด์ ์์ ๊ธฐ๋ณธ ๊ฐ) -
newSession()
: ์๋ก์ด ์ธ์ ์์ด๋๋ฅผ ์์ฑํ๋ฉฐ ์ด์ ์ ์ค์ ๊ฐ๋ค์ ์ฌ์ฉ ๋ถ๊ฐ -
none()
: ์๋ฌด๋ฐ ๋ณดํธX
chageSessionId(), migrateSession()์ ์ด์ ์ธ์ ์ ์ค์ ๊ฐ๋ค์ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์์ง๋ง newSession()์ ๊ฒฝ์ฐ ์๋ก์ด ์ธ์ ์ ์์ฑํ์ฌ ์ด์ ์ค์ ๊ฐ์ ์ฌ์ฉํ์ง ๋ชปํ๋ค.
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.If_Required)
-
SessionCreationPolicy.Always
: ์คํ๋ง ์ํ๋ฆฌํฐ๊ฐ ํญ์ ์ธ์ ์ ์์ฑํ๋ค. -
SessionCreateionPolicy.If_Required
: ์คํ๋ง ์ํ๋ฆฌํฐ๊ฐ ํ์์ ์์ฑํ๋ค.(default) -
SessionCreateionPolicy.Never
: ์คํ๋ง ์ํ๋ฆฌํฐ๊ฐ ์์ฑํ์ง ์์ง๋ง ์ด๋ฏธ ์กด์ฌํ๋ฉด ์ฌ์ฉํ๋ค. -
SessionCreateionPolicy.Stateless
: ์คํ๋ง ์ํ๋ฆฌํฐ๊ฐ ์์ฑํ์ง ์๊ณ ์กด์ฌํด๋ ์ฌ์ฉํ์ง ์๋๋ค.(JWT์ ๊ฐ์ด ์ธ์ ์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ ์ฌ์ฉํจ)
ํ์ต ๊ณต์ , ํธ๋ฌ๋ธ ์ํ ๊ณต์ ํ์ด์ง~~~