1. Spring Security 란
Spring Security는 인증, 권한 관리, 데이터 보호 기능을 포함하여 웹 개발에 필수적인 사용자 관리 기능을 구현하는데 도움을 주는 Spring의 프레임 워크 이다.
일반적으로 개발 시 가장 먼저 작업하는 부분이 사용자 관리 부분으로 가볍게는 회원가입부터 로그인, 로그아웃, 세션 관리, 권한 관리까지 플랫폼에 맞춰 다양하게 작업되는 인가 & 보안 기능은 개발자에게 많은 시간을 요구한다.
이때 Spring Security는 개발자들이 보안 관련 기능을 효율적이고 빠르게 구현할 수 있게 도와주는 프레임 워크이다.
Spring Security는 인증과 권한에 대한 부분을 Filter 흐름에 따라 처리한다.
Filter는 Dispatcher Servlet으로 가기 전에 적용되므로 먼저 URL 요청을 받지만, (웹 컨테이너에서 관리)
Interceptor는 Dispatcher와 Controller 사이에 위치한다는 점에서 적용 시점의 차이가 있다. (스프링 컨테이너에서 관리)
Client(Request) -> Filter -> Dispatcher Servlet -> Interceptor -> Controller
인증(Authentication) , 인가 (Authorization)
인증과 인가란 무엇일까? 보통의 경우 인증 절차를 거친 후 인가 절차를 진행한다.
인증 : 사용자가 본인이 맞는지 확인하는 절차.
인가 : 인증된 사용자가 요청한 자원에 접근 여부를 결정하는 절차
Spring Security는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행, 인가 과정에서 해당 리소스에 접근 권한이 있는지 확인한다.
Spring Security는 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 Credential 기반의 인증 방식을 사용한다.
- Principal(접근 주체) : 보호받는 Resource에 접근하는 대상
- Credential(비밀번호) : Resource에 접근하는 대상의 비밀번호

Spring Security 구조의 처리 과정을 간단하게 설명하면 다음과 같다.
- 사용자가 로그인 정보와 함게 인증 요청(Http Request)
- AuthenticationFilter가 요청을 가로채고, 가로챈 정보를 통해 UsernamePasswordAuthentication Token의 인증용 객체를 생성
- AuthenticationManager의 구현체인 ProviderManager에게 생성한 Token객체를 전달
- AuthenticationManager는 등록된 AuthenticationProvider(s)을 조회하여 인증을 요구
- 실제 DB에서 사용자 정보를 가져오는 UserDetailsService에 사용자 정보를 넘김.
- 넘겨받은 사용자 정보를 통해 DB에서 찾은 사용자 정보인 UserDetails 객체를 생성.
- AuthenticationProvider(s)은 UserDetails를 받고 사용자 정보를 비교.
- 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체 반환.
- AuthenticationFilter에 Authentication 객체가 반환된다.
- Authentication 객체를 SecurityContextHolder의 SecurityContext 에 저장.
사용자의 정보를 저장한다는 것은 Spring Security가 세션-쿠키 기반의 인증 방식을 사용한다는 것이다.
2. Spring Security의 주요 모듈
먼저 Spring Security 를 사용하기 위한 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-security'
Authentication
현재 접근하는 주체의 정보와 권한을 담은 인터페이스. Authentication 객체는 SecurityContext에 저장되며, SecurityContextHolder를 통해 SecurityContext에 접근, SecurityContext를 통해 Authentication에 접근할 수 있다.
package org.springframework.security.core;
import java.io.Serializable;
import java.security.Principal;
import java.util.Collection;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.context.SecurityContextHolder;
public interface Authentication extends Principal, Serializable {
// 현재 사용자의 권한 목록을 가져옴
Collection<? extends GrantedAuthority> getAuthorities();
// credential(비밀번호)를 가져옴
Object getCredentials();
Object getDetails();
// principal(인증 대상 ID)를 가져옴
Object getPrincipal();
// 인증 여부
boolean isAuthenticated();
// 인증 여부를 설정
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
UsernamePasswordAuthenticationToken
UsernamePasswordAuthentication Token은 Authentication와 CredentialsContainer을 implements 한 AbstractAuthenticationToken의 하위 클래스로, User의 ID가 Principal, Password 가 Credential이다.
UsernamePasswordAuthentication Token의 첫 번째 생성자는 인증 전의 객체를 생성, 두번째는 인증이 완료된 객체를 생성한다.
package org.springframework.security.authentication;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.Assert;
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
}
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
// 사용자 ID
private final Object principal;
// 사용자 Password
private Object credentials;
// 인증 전의 객체 생성
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(false);
}
// 인증 후의 객체 생성
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true); // must use super, as we override
}
}
AuthenticationManager
인증에 대한 부분은 AuthenticationManager를 통해 처리되는데, 실질적으로는 AuthenticationManager에 등록된 AuthenticationProvider에 의해 처리된다. 인증에 성공하면 두번째 생성자를 이용해 객체를 생성한 후 SecurityContext에 저장한다.
package org.springframework.security.authentication;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
AuthenticationProvider
AuthenticationProvider에서는 실제 인증에 대한 부분을 처리하는데, 인증 전의 Authentication 객체를 받아 인증이 완료된 객체를 반환하는 역할을 한다. 아래와 같은 인터페이스를 구현해 Custom한 AuthenticationProvider를 작성하고 AuthenticationManager에 등록하면 된다.
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}
ProviderManager
AuthenticationManager를 implements한 ProviderManager는 AuthenticationProvider를 구성하는 목록을 갖는다.
UserDetailService
UserDetailService는 UserDetails 객체를 반환하는 하나의 메서드만 가지고 있는데, 일반적으로 이를 implements한 클래스에 UserRepository를 주입받아 DB와 연결해 처리한다.
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetails
인증에 성공하여 생성된 UserDetails 객체는 Authentication객체를 구현한 UsernamePasswordAuthenticationToken을 위해 사용됨. UserDetails를 implements하여 처리할 수 있다.
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
public interface UserDetails extends Serializable {
// 권한 목록
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
// 계정 만료 여부
boolean isAccountNonExpired();
// 계정 잠김 여부
boolean isAccountNonLocked();
// 계정 비밀번호 만료 여부
boolean isCredentialsNonExpired();
// 계정 활성화 여부
boolean isEnabled();
}
SecurityContextHolder
SecurityContextHolder는 보안 주체의 세부 정보를 포함하여 응용프로그램의 현재 보안 컨텍스트에 대한 세부 정보가 저장된다.
SecurityContext
Authentication 객체를 보관하는 역할을 하며, SecurityContext를 통해 Authentication을 저장하거나 꺼내올 수 있다.
SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.getContext().getAuthentication(authentication);'언어 공부 > Java_Spring' 카테고리의 다른 글
| [ Java ] Feign 클라이언트 성능 최적화 : HttpUrlConnection의 이슈 (0) | 2025.03.14 |
|---|---|
| [ Java/자바 ] LinkedList 와 ArrayList 시간 차이 (0) | 2025.02.20 |
| [ Spring ] Redis 를 이용한 동시성 이슈 처리 (Lettuce, Redisson) 2/2 (0) | 2024.11.26 |
| [ Spring ] 다양한 방법을 통한 동시성 이슈 처리 (Synchronized, 낙관적 락, 비관적 락) 1/2 (0) | 2024.11.22 |
| [ Java ] 다양한 Garbage Collection 알고리즘 2/2 (0) | 2024.11.18 |