1. 소개
Spring Security란?
Spring 기반 애플리케이션의 보안을 담당하는 프레임워크
인증(Authentication)과 인가(Authorization)를 중심으로 애플리케이션을 보호하는 역할을 한다.
한마디로 인증, 권한 관리 그리고 데이터 보호 기능을 포함하여 웹 개발 과정에서 필수적인 사용자 관리 기능 ex) 로그인 등을 구현하는데 도움을 주는 프레임워크
주요기능
1. 인증 (Authentication)
사용자가 누구인지 확인하는 과정으로, 일반적으로 로그인 과정을 의미한다.
- 사용자 정보 확인: ID/PW, OAuth2, JWT, LDAP, SAML 등 다양한 인증 방식을 지원
- 인증 관리자(AuthenticationManager): 사용자의 인증 정보를 검증하고 인증 여부를 결정하는 핵심 컴포넌트
- UserDetailService: 사용자 정보를 데이터베이스나 메모리에서 가져오는 역할
2. 인가 (Authorization)
인증된 사용자가 특정 리소스에 접근할 수 있는 권한을 확인하는 과정을 의미한다.
- URL 기반 권한 부여: 특정 URL에 접근할 수 있는 권한을 설정
- 메서드 기반 권한 부여: @PreAuthorize, @Secured 등을 이용해 메서드 수준에서 접근 제어
- RBAC (Role-Based Access Control): 역할 단위로 권한을 관리
3. 보안 필터
Spring Security는 여러 개의 필터 체인을 통해 요청을 검사합니다.
- UsernamePasswordAuthenticationFilter: 기본적인 로그인 처리
- JwtAuthenticationFilter: JWT 토큰을 검증하는 필터
- CsrfFilter: CSRF 공격 방지
2. Security의 작동 흐름
- 사용자가 로그인 요청(http request)을 보냄
- SecurityFilterChain 에서 요청을 가로채고 인증을 진행
- AuthenticationManager가 등록된 Authotication Provider를 조회하며 인증 검사
- Authotication Provider가 실제 데이터를 조회하여 UserDetails 결과를 돌려줌
- 인증이 성공하면 SecurityContextHolder에 인증 정보를 저장
- 권한이 있으면 요청을 허용, 없으면 AccessDeniedException을 발생시킨다.
3. Spring Security 설정
Spring Boot 프로젝트에서 Security 설정하는 법
의존성 추가 - gradle 사용
implementation 'org.springframework.boot:spring-boot-starter-security'
추가하고 프로젝트를 실행하고 접속해보면 원래 들어가지던 페이지에 들어가지지 않고 아래같은 화면이 나온다
서버 로그를 살펴보면 패스워드가 하나 찍혀있다.
아이디는 user, 발급받은 패스워드를 사용해 로그인을 하면 로그인이 된다.
그럼 페이지에 접속이 잘 된다.
이렇게 Spring Security는 웹사이트 보안에 가장 기본적인 기능인 아이디/패스워드 인증을 화면까지 지원한다.
그런데 우리는 이걸 그대로 쓸게 아니니까 상속받아서 필요한 메서드들을 오버라이딩해 입맛에 맞게 쓰면 될 것이다.
그럼 어떻게 사용할까?
1. 기본설정 (SecurityConfig.java)
@EnableWebSecurity 어노테이션으로 간편하게 이용가능하다
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable) // CSRF 보호 비활성화 (테스트용)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults()) // 기본 로그인 폼 사용
.logout(logout -> logout.logoutUrl("/logout").logoutSuccessUrl("/"));
return http.build();
}
}
- /admin/** → ADMIN 권한 필요
- /user/** → USER 또는 ADMIN 권한 필요
- 나머지 모든 요청은 인증된 사용자만 접근 가능
- 기본 로그인 폼 활성화 (/login 경로 자동 생성)
2. 사용자 인증 설정 (UserDetailsService)
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 실제 DB에서 사용자 정보 조회 (예제에서는 하드코딩)
if ("admin".equals(username)) {
return User.withUsername("admin")
.password("{noop}password") // {noop} → 암호화 안 함
.roles("ADMIN")
.build();
} else if ("user".equals(username)) {
return User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build();
}
throw new UsernameNotFoundException("User not found");
}
}
- loadUserByUsername() 메서드는 DB에서 사용자 정보를 조회
- {noop}는 비밀번호 암호화 없이 사용하겠다는 의미 (실제 서비스에서는 BCrypt 사용 권장)
3. JWT 기반 인증 설정
JWT(Json Web Token)를 활용하면 세션 없이 인증을 유지할 수 있음
JWT 토큰 필터 구현
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String token = resolveToken(request);
if (token != null && validateToken(token)) {
Authentication auth = getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
private String resolveToken(HttpServletRequest request) {
return request.getHeader("Authorization");
}
private boolean validateToken(String token) {
// JWT 검증 로직 (예제에서는 단순 true 반환)
return true;
}
private Authentication getAuthentication(String token) {
UserDetails userDetails = new User("user", "", List.of(new SimpleGrantedAuthority("ROLE_USER")));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
}
- 요청에서 Authorization 헤더에서 JWT 토큰을 추출
- 토큰이 유효하면 SecurityContextHolder에 인증 정보 저장
- 이후의 요청은 세션 없이 JWT 토큰으로 인증 유지
JWT 필터 등록
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
- JwtAuthenticationFilter를 UsernamePasswordAuthenticationFilter 앞에 등록하여 JWT 인증 적용
4. 정리
Spring Security는 인증 & 권한 부여를 담당하는 강력한 보안 프레임워크
기본 로그인 기능을 쉽게 설정할 수 있고, 필요에 따라 커스텀 가능
JWT, OAuth2, LDAP 등 다양한 인증 방식을 지원
보안 필터 체인을 활용하여 유연한 보안 정책 적용 가능
인증, 인가와 관련된 부분을 시간을 많이 들이지 않고 깔끔하게 개발하는 걸 도와주는 프레임워크!
'Spring' 카테고리의 다른 글
[Spring] Redis를 이용한 캐싱 기법 (0) | 2025.02.08 |
---|---|
[Spring] Spring Boot Starter 이해하기 (0) | 2025.02.08 |
[Spring] N + 1 문제 (0) | 2025.02.06 |
[Spring] 관계 매핑 어노테이션 (2) | 2025.02.06 |
[Spring] 스프링 부트 구조 정리 (0) | 2025.02.04 |