일관성을 위해 사용하는 어노테이션.
런타임 예외가 발생할 때 DB 롤백된다.
*예외를 지정하여 롤백되게 만들 수도 있다.
@Transactional(rollbackFor = {
IOException.class, RuntimeException.class})
JWT란? 인증,인가를 위해 사용하는 토큰 방식, 3가지 부분인
Header.Payload.Signature 로 구성되어 있다.
특징 :
stateless(무상태), 빠름.
HTTPS필수
Header : JWT의 타입과 서명 알고리즘이 들어 있다.
{
"alg": "HS256", // 서명 알고리즘 (ex. HS256, RS256 등)
"typ": "JWT"
}
Payload : 실제 담고 싶은 정보 넣기!
{
"sub": "userId123", // PK
"name": "파랑",
"role": "admin",
"exp": 1715241234 // 만료 시간
}
Signature : 토큰 위변조를 방지하기 위해 사용.
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secretKey
)
JWT는 탈취 시 위험하므로 만료 시간을 짧게 쓴다.
스프링에서 웹 애플리케이션에 인증과 권한 기능을 쉽게 적용할 수 있도록 하는 보안 프레임워크.
로그인, 로그아웃, 비밀번호 암호화, 자동 로그인, CSRF 공격 방어 등을 쉽게 설정할 수 있다.
✔ 주요 개념
Authentication (인증) - 사용자가 누구인지 확인 (로그인)
Authorization (인가) - 인증된 사용자가 어떤 권한을 가졌는지 확인
FilterChain - 요청을 처리하는 보안 필터들의 체인
SecurityContext - 현재 인증된 사용자의 정보를 담는 저장소
UserDetailsService - 사용자 인증 정보를 가져오는 인터페이스
PasswordEncoder - 비밀번호를 해시하고 비교하는 기능 (BCrypt)
즉, 스프링시큐리티를 적용하면 어느 페이지를 가더라도 로그인 페이지로 쫒겨나게 된다.

✔ 동작 흐름
클라이언트가 로그인 요청 -> UsernamePasswordAuthenticationFilter가 요청 가로챔 -> UserDetailsService로 사용자 정보 로딩 -> PasswordEncoder로 비밀번호 검증 -> SecurityContext에 클라이언트 정보 저장 -> 인증된 사용자만 접근 가능한 URL 처리 가능 (@PreAuthorize, .antMatchers()...)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // CSRF 비활성화 (API 서버일 경우)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/signup").permitAll() // 비인증 허용
.anyRequest().authenticated() // 나머지는 인증 필요
)
.formLogin(form -> form
.loginPage("/login") // 사용자 정의 로그인 페이지
.defaultSuccessUrl("/") // 로그인 성공 시 이동 경로
)
.logout(logout -> logout
.logoutSuccessUrl("/login")
)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("사용자 없음"));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword()) // 반드시 인코딩된 비밀번호!
.roles(user.getRole()) // "USER", "ADMIN" 등
.build();
}
}
Filter (시큐리티 필터 실행)
DispatcherServlet - MVC의 진입점
Interceptor - 컨트롤러 실행 전,후
Controller
AOP(@Around) - 메서드 실행 전, 후
시큐리티에서 Form Login(UsernamePasswordAuthenticationFilter), Basic Auth(BasicAuthenticationFilter), JWT 커스텀 필터의 인증 방식이 있고, 쓰여진 순서대로 동작한다.