Spring Security를 활용한 인증 및 권한 관리에 대해 알아보기

현대 웹 애플리케이션에서는 보안이 중요한 요소이며, Spring Security는 강력한 인증 및 권한 관리 기능을 제공합니다. 이번 글에서는 Spring Security를 활용하여 사용자 인증(Authentication) 및 **권한 관리(Authorization)**를 구현하는 방법을 심층적으로 분석하고, 실무에서의 활용 방안을 설명하겠습니다.

1. Spring Security란?

Spring Security는 Spring 기반 애플리케이션의 보안을 강화하는 프레임워크로, 다음과 같은 기능을 제공합니다.

  • 사용자 인증(Authentication): 로그인 및 세션 관리합니다.
  • 권한 부여(Authorization): 역할(Role) 기반 접근 제어하게 합니다.
  • 보안 기능 내장: CSRF, CORS, 세션 관리, 암호화 지원합니다.
  • OAuth2 및 JWT 지원: 소셜 로그인 및 토큰 기반 인증을 지원합니다.

Spring Boot 프로젝트에서 손쉽게 적용할 수 있도록 기본적인 보안 설정을 제공합니다.

2. Spring Security 설정 및 기본 적용

Spring Security를 프로젝트에 추가하려면 의존성을 추가해야 합니다.

1) Spring Boot 프로젝트에 Spring Security 추가

pom.xml에 Spring Security 관련 의존성을 추가합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 

2) 기본 보안 설정

Spring Security를 추가하면 기본적인 로그인 인증이 자동 적용됩니다. 기본적으로 /login 페이지가 제공되며, user 계정과 자동 생성된 비밀번호로 로그인할 수 있습니다.

로그인 시 생성된 기본 비밀번호 확인

Using generated security password: a1b2c3d4e5

사용자 정의 보안 설정을 위해 SecurityConfig 클래스를 작성해야 합니다.

3. 사용자 인증(Authentication) 구현

사용자 인증을 위해 Spring Security의 UserDetailsService를 활용하여 사용자 정보를 저장하고 검증할 수 있습니다.

1) 사용자 정보 저장 (UserDetailsService 구현)

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collections;

@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if ("admin".equals(username)) {
            return new User("admin", "{noop}password", Collections.emptyList());
        }
        throw new UsernameNotFoundException("User not found");
    }
}
  • {noop}: 비밀번호를 암호화하지 않음을 의미하며, 실제 환경에서는 BCrypt 등의 암호화를 적용해야 합니다.
  • loadUserByUsername: 사용자의 인증 정보를 데이터베이스에서 가져오는 역할을 합니다.

2) 보안 설정 (SecurityConfig 작성)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin").hasRole("ADMIN")
                .requestMatchers("/user").hasRole("USER")
                .anyRequest().authenticated()
            )
            .formLogin()
            .and()
            .logout();
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  • authorizeHttpRequests(): 특정 URL에 대한 접근 권한을 설정합니다.
  • formLogin(): 기본 로그인 폼을 활성화합니다.
  • logout(): 로그아웃 기능을 활성화합니다.
  • BCryptPasswordEncoder(): 비밀번호를 안전하게 저장하도록 설정합니다.

 

4. 권한(Role) 기반 접근 제어 (Authorization)

Spring Security는 **역할(Role)**을 기반으로 사용자의 접근을 제어할 수 있습니다.

1) 사용자 역할 설정

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.List;

public class CustomUserDetails extends User {
    public CustomUserDetails(String username, String password, String role) {
        super(username, password, List.of(new SimpleGrantedAuthority(role)));
    }
}

2) 권한 확인 예제

컨트롤러에서 @PreAuthorize 애너테이션을 사용하여 역할 기반 접근을 제한할 수 있습니다.

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/admin")
    @PreAuthorize("hasRole('ADMIN')")
    public String adminEndpoint() {
        return "Admin Access";
    }

    @GetMapping("/user")
    @PreAuthorize("hasRole('USER')")
    public String userEndpoint() {
        return "User Access";
    }
}

 

5. 문의 내용 예시 및 답변

1. Spring Security에서 JWT를 활용한 인증을 적용하려면 어떻게 해야 하나요?

답변: JWT(JSON Web Token)를 활용하면 세션을 유지하지 않고 인증할 수 있습니다. spring-security-oauth2jjwt 라이브러리를 활용하여 JWT 인증을 구현할 수 있습니다.

2. OAuth2 기반의 소셜 로그인을 Spring Security에서 어떻게 적용하나요?

답변: Spring Security의 spring-security-oauth2-client 라이브러리를 활용하면 Google, Facebook 등의 OAuth2 인증을 쉽게 구현할 수 있습니다.

3. Spring Security에서 CSRF 보호를 비활성화할 수 있나요?

답변: 기본적으로 Spring Security는 CSRF 보호를 활성화합니다. API 서버에서 CSRF가 필요 없을 경우 http.csrf().disable();을 설정하여 비활성화할 수 있습니다.

6. 마무리
Spring Security를 활용한 인증 및 권한 관리에 대해 알아보았습니다. Spring Security를 활용하면 강력한 인증 및 권한 관리를 적용할 수 있습니다. 실무에서는 JWT 기반 인증, OAuth2 소셜 로그인, 세부적인 접근 제어 등을 활용하여 보안성을 강화할 수 있으니, 제 블로그를 보시고 활용해보시길 바랍니다.

 

Leave a Comment