2025-05-20
SecurityConfig.java
โ Spring Security ์ค์ ์ ํต์ฌ@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private CustomSuccessHandler customSuccessHandler;
@Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
private CustomLogoutHandler customLogoutHandler;
@Autowired
private UserRepository userRepository;
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Bean
protected SecurityFilterChain configure(HttpSecurity http) throws Exception {
// โ
CSRF ๋นํ์ฑํ
http.csrf((config) -> config.disable());
// โ
์ธ๊ฐ ์ค์
http.authorizeHttpRequests((auth) -> {
auth.requestMatchers("/", "/join", "/login").permitAll();
auth.requestMatchers("/user").hasRole("USER");
auth.requestMatchers("/manager").hasRole("MANAGER");
auth.requestMatchers("/admin").hasRole("ADMIN");
auth.anyRequest().authenticated();
});
// โ
๋ก๊ทธ์ธ ์ค์
http.formLogin((login) -> {
login.permitAll();
login.loginPage("/login");
login.successHandler(customSuccessHandler); // ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ์ปค์คํ
ํธ๋ค๋ฌ ์คํ
login.failureHandler(new CustomLoginFailureHandler());
});
// โ
๋ก๊ทธ์์ ์ค์
http.logout((logout) -> {
logout.permitAll();
logout.addLogoutHandler(customLogoutHandler);
logout.logoutSuccessHandler(customLogoutSuccessHandler);
});
// โ
์์ธ์ฒ๋ฆฌ ์ค์
http.exceptionHandling((ex) -> {
ex.authenticationEntryPoint(new CustomAuthenticationEntryPoint());
ex.accessDeniedHandler(new CustomAccessDeniedHandler());
});
// โ
OAuth2 ๋ก๊ทธ์ธ ์ค์ (๊ธฐ๋ณธ ๋ก๊ทธ์ธ ํ์ด์ง ๊ณต์ )
http.oauth2Login((oauth2)-> oauth2.loginPage("/login"));
// โ
์ธ์
์ค์ (JWT ๊ธฐ๋ฐ โ ๋ฌด์ํ)
http.sessionManagement((sessionManagerConfigure) ->
sessionManagerConfigure.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
// โ
JWT ์ธ์ฆ ํํฐ ์ถ๊ฐ (LogoutFilter ์ ์ ์คํ๋๋๋ก)
http.addFilterBefore(new JwtAuthorizationFilter(userRepository, jwtTokenProvider), LogoutFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
CustomSuccessHandler.java
โ ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ์ฒ๋ฆฌ ํ๋ฆ@Slf4j
@Component
public class CustomSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Autowired
private JwtTokenRepository jwtTokenRepository;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
log.info("CustomSuccessHandler's onAuthenticationSuccess invoke..." + authentication);
// โ
JWT ๋ฐ๊ธ
TokenInfo tokenInfo = jwtTokenProvider.generateToken(authentication);
// โ
AccessToken์ ์ฟ ํค๋ก ์ ๋ฌ
Cookie cookie = new Cookie(JwtProperties.ACCESS_TOKEN_COOKIE_NAME, tokenInfo.getAccessToken());
cookie.setMaxAge(JwtProperties.REFRESH_TOKEN_EXPIRATION_TIME); // ์ฟ ํค ์ ์ง ์๊ฐ = RefreshToken ์๊ฐ
cookie.setPath("/");
response.addCookie(cookie);
// โ
Access + Refresh Token DB ์ ์ฅ
JwtToken jwtToken = JwtToken.builder()
.accessToken(tokenInfo.getAccessToken())
.refreshToken(tokenInfo.getRefreshToken())
.username(authentication.getName())
.createAt(LocalDateTime.now())
.build();
jwtTokenRepository.save(jwtToken);
// โ
๋ฉ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ
response.sendRedirect(request.getContextPath() + "/");
}
}
๊ตฌ์ฑ ์์ | ์ญํ |
---|---|
SecurityConfig | ์ ์ฒด ๋ณด์ ์ค์ ๋ด๋น (HttpSecurity ๊ธฐ๋ฐ FilterChain ๊ตฌ์ฑ) |
formLogin().successHandler() | ๋ก๊ทธ์ธ ์ฑ๊ณต ์ CustomSuccessHandler ์คํ |
CustomSuccessHandler | AccessToken ๋ฐ๊ธ, ์ฟ ํค์ ์ ์ฅ, DB ์ ์ฅ, ๋ฆฌ๋ค์ด๋ ํธ |
JwtTokenProvider | ์ค์ JWT ์์ฑ ์ฑ ์ |
JwtTokenRepository | Access/RefreshToken ์์ํ (DB ์ ์ฅ์ฉ) |
SecurityConfig
์ ํ๋ฆ์ ์์ ํ ์ดํดํ๊ณ ๋๋, ์ธ์ฆ ํํฐ์ ๋์ ์์๊ฐ ๋ช
ํํด์งAccessToken
๋ง๋ฃ ๋์, RefreshToken
ํ์ฉ ๊ตฌ์กฐ๊ฐ ๋ ์ค์ํ๊ฒ ์์ฉํ ๊ฒ์ด๋ผ ๋๊ปด์ง