시큐리티에 대해서 공부하던 중 Authentication 객체를 사용해서 인증 과정을 알아가고 있습니다. 처음 사용해 보는 객체인 만큼 개념에 대해서 알아두고 메모해두기 위해 포스팅을 해보겠습니다.
Authentication 객체란?
Authentication 객체는 Spring Security에서 사용되는 인증 정보를 나타내는 객체입니다. 인증은 사용자의 신원을 확인하고 권한을 부여하는 프로세스를 말합니다.
Authentication 객체는 인증 과정을 통해 생성되며, 사용자의 자격 증명(예: 사용자 이름과 비밀번호)을 기반으로 신원을 확인합니다. 주요한 구성 요소로는 사용자의 식별 정보, 사용자의 권한 정보 및 기타 인증에 필요한 부가적인 정보가 포함됩니다.
일반적으로 인증 프로세스는 다음과 같은 단계를 거칩니다.
- 사용자가 자격 증명(사용자 이름과 비밀번호)을 제공합니다.
- 제공된 자격 증명을 기반으로 사용자의 신원을 확인하기 위해 인증 과정이 시작됩니다.
- 인증 과정은 UserDetailsService를 사용하여 사용자의 신원을 확인하고, 사용자 정보와 권한 정보를 가져옵니다.
- 인증이 성공적으로 완료되면, 인증 객체인 Authentication 객체가 생성됩니다. 이 객체는 사용자의 신원 정보와 부여된 권한 정보를 포함합니다.
- 생성된 Authentication 객체는 인증된 사용자를 나타내며, 이후의 보호된 리소스에 접근할 때 사용됩니다.
그렇다면 인증 과정에서 사용하는 UserDetailsService는 무엇일까 ??
UserDetailsService
UserDetailsService는 Spring Security에서 사용자 정보를 로드하기 위한 인터페이스입니다. 인증 프로세스에서 사용자의 신원을 확인하고 권한을 부여하는 데 사용됩니다.
UserDetailsService는 다음과 같은 주요 메서드를 가지고 있습니다.
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
- 'loadUserByUsername' : 주어진 사용자 이름을 기반으로 사용자 정보를 로드하는 메서드입니다. 일반적으로 데이터베이스나 외부 사용자 저장소와 같은 백엔드 시스템에서 사용자 정보를 가져옵니다. 이 메서드는 UserDetails 인터페이스를 구현한 객체를 반환합니다.
- 'UsernameNotFoundException' : 주어진 사용자 이름을 가진 사용자를 찾을 수 없을 때 발생하는 예외입니다. 사용자가 존재하지 않는 경우에 대한 처리를 수행할 수 있습니다.
UserDetailsService의 구현은 애플리케이션의 요구에 맞게 사용자 정보를 로드하는 방식을 결정합니다.
대부분의 경우, 사용자 정보는 데이터베이스에 저장되어 있으며, UserDetailsService의 구현은 데이터베이스 쿼리를 실행하여 사용자 정보를 가져옵니다.
그러나 다른 백엔드 시스템을 사용하거나 사용자 정보를 외부 서비스로부터 가져오는 방식으로 구현할 수도 있습니다.
UserDetailsService는 Spring Security 구성 클래스에서 구현을 제공해야 합니다. 구성 클래스에서는 UserDetailsService를 구현하고, 'configure' 메서드 내에서 AuthenticationManagerBuilder를 사용하여 인증 프로세스에 사용될 UserDetailsService 를 설정합니다.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
이렇게 설정된 UserDetailsService는 인증 프로세스에서 사용되며, 사용자 인증 시에 주어진 사용자 이름을 기반으로 UserDetailsService의 'loadUserByUsername' 메서드가 호출되어 사용자 정보를 가져옵니다.
이 정보는 인증 과정에서 사용자의 신원을 확인하고 권한 검사 등의 보안 작업에 사용됩니다.
사용자의 신원 확인을 위해 UserDetailsService를 사용하면 데이터베이스나 외부 저장소와 같은 백엔드 시스템으로부터 사용자 정보를 유연하게 가져올 수 있으며, 다양한 인증 및 권한 부여 시나리오를 처리할 수 있습니다.
다시 본론으로 돌아가면 Authentication 객체는 Spring Security에서 중요한 역할을 합니다. 보호된 리소스에 접근하려는 사용자의 신원을 확인하고, 권한 검사 등의 보안 작업에 사용됩니다.
또한, Authentication 객체는 SecurityContextHolder를 통해 전역적으로 액세스 할 수 있으므로, 애플리케이션의 다른 부분에서도 사용자의 신원을 확인할 수 있습니다.
Spring Security는 다양한 인증 제공자와 방식을 지원하며, Authentication 객체는 이러한 다양한 인증 방식을 처리하기 위한 일반적인 인터페이스입니다. 이를 통해 사용자 인증과 관련된 작업을 유연하게 처리할 수 있습니다.
그렇다면 예제 소스를 통해서 Authentication 객체를 사용하는 방법을 알아봅니다.
Authentication 사용 방법
1. 의존성 추가
먼저, build.gradle 파일( 또는 pom.xml 파일)에 Spring Security 의존성을 추가해야 합니다.
dependencies {
// ...
implementation 'org.springframework.boot:spring-boot-starter-security'
// ...
}
2. Spring Security 구성
다음으로, Spring Security를 구성하기 위해 SecurityConfig 클래스를 만들어야 합니다. 이 클래스는 SecurityConfigurerAdapter를 확장하고, configure 메서드를 재정의하여 보안 규칙을 정의합니다.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("{noop}password") // {noop}을 사용하여 암호화되지 않은 비밀번호를 사용
.roles("USER");
}
}
위의 소스에서는 인메모리 사용자 인증을 사용하고 있습니다.
실제 애플리케이션에서는 데이터베이스나 다른 사용자 저장소와 같은 외부 소스에서 사용자 정보를 가져오는 것이 일반적입니다.
3. Controller 작성
마지막으로, 인증이 필요한 Controller를 작성합니다. 예제로는 "/hello" 엔드포인트에 대한 보호된 요청을 처리하고, 인증된 사용자의 정보를 출력하는 간단한 Controller를 작성합니다.
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
return "Hello, " + username + "!";
}
}
위 코드에서는 SecurityContextHolder를 사용하여 현재 인증된 사용자의 Authentication 객체를 가져옵니다. getName() 메서드를 사용하여 인증된 사용자의 이름을 얻을 수 있습니다.
위 코드 기반으로 웹 애플리케이션을 실행하고 "/hello" 엔드포인트에 접속하면 현재 인증된 사용자의 이름이 출력됩니다.
마치며
오늘은 Authentication 객체와 UserDetailsService 인터페이스에 대해서 알아봤습니다.
위 예제는 간단한 인증 관련 작업을 구현했습니다. 실제 애플리케이션에서는 보안 구성과 사용자 저장소에 대한 복잡성이 증가할 수 있습니다. Spring Security는 이러한 복잡성을 처리하기 위한 다양한 기능과 유연성을 제공해 줍니다.
다음 포스팅에서 뵙겠습니다.
'[ Concept ]' 카테고리의 다른 글
[ Concept ] DTO와 VO의 차이점 (0) | 2023.06.22 |
---|---|
[ Concept] Logger의 개념 (0) | 2023.06.18 |
[ Concept ] JSON 이란? (0) | 2023.05.27 |
[ Concept ] 스프링 컨테이너와 스프링 빈 (0) | 2023.05.19 |
[ Concept ] 좋은 객체 지향 설계의 5가지 원칙 (SOLID) (0) | 2023.05.18 |