File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package kr.itn.itnhub.config;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.http.HttpStatus;
@Configuration
public class SecurityConfig {
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 관리자 1계정. 값은 환경변수로만 들어온다.
* 운영에서는 APP_ADMIN_PASSWORD에 충분히 긴 무작위 문자열을 넣는다.
*/
@Bean
UserDetailsService userDetailsService(AdminProperties admin, PasswordEncoder encoder) {
return new InMemoryUserDetailsManager(
User.withUsername(admin.username())
.password(encoder.encode(admin.password()))
.roles("ADMIN")
.build());
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// SPA가 읽어서 X-XSRF-TOKEN 헤더로 되돌려 보낸다
.csrf(csrf -> csrf.csrfTokenRepository(
CookieCsrfTokenRepository.withHttpOnlyFalse()))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/login").permitAll()
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll())
.formLogin(form -> form
.loginProcessingUrl("/api/auth/login")
.successHandler((req, res, a) -> res.setStatus(HttpServletResponse.SC_OK))
.failureHandler((req, res, e) ->
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED)))
.logout(logout -> logout
.logoutUrl("/api/auth/logout")
.logoutSuccessHandler((req, res, a) ->
res.setStatus(HttpServletResponse.SC_NO_CONTENT)))
// API는 로그인 페이지로 리다이렉트하지 않고 401을 준다
.exceptionHandling(ex -> ex.authenticationEntryPoint(
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)));
return http.build();
}
}