백엔드 20일차 - 스프링 시큐리티, JWT

parang·2025년 5월 13일

LG CNS AM Inspire Camp 2기

목록 보기
31/50

✅ @Transactional

일관성을 위해 사용하는 어노테이션.

런타임 예외가 발생할 때 DB 롤백된다.

*예외를 지정하여 롤백되게 만들 수도 있다.

@Transactional(rollbackFor = {
	IOException.class, RuntimeException.class})

✅ JWT

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()...)

설정

  1. 빈 등록
@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();
    }
}
  1. UserDetailsService 구현
@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();
    }
}
  1. 기타 설정
    user entity 에서 role이 추가된다.

✅ 총 실행 순서

Filter (시큐리티 필터 실행)
DispatcherServlet - MVC의 진입점
Interceptor - 컨트롤러 실행 전,후
Controller
AOP(@Around) - 메서드 실행 전, 후

시큐리티에서 Form Login(UsernamePasswordAuthenticationFilter), Basic Auth(BasicAuthenticationFilter), JWT 커스텀 필터의 인증 방식이 있고, 쓰여진 순서대로 동작한다.

profile
파랑입니다.

0개의 댓글