[Spring] Spring Security

2024. 10. 16. 23:19·🌱 Spring/Spring Boot

Spring Security란? 🤔

Spring Security는 스프링 기반 애플리케이션의 보안(인증, 인가, 권한)을 담당하는 스프링 하위 프레임워크입니다. 인증(Authentication)과 인가(Authorization)를 통해 애플리케이션을 보호하며, CSRF, 세션 고정 공격 등 다양한 보안 공격으로부터 애플리케이션을 방어합니다.

인증(Authentication)과 인가(Authorization)

  • 인증(Authentication): 사용자의 신원을 확인하는 과정입니다. 예를 들어, 사용자가 로그인할 때 그 사용자가 누구인지 확인하는 절차입니다.
  • 인가(Authorization): 사용자가 애플리케이션의 특정 리소스나 기능에 접근할 수 있는지 확인하는 과정입니다. 예를 들어, 관리자만 관리자 페이지에 접근할 수 있도록 제한하는 작업이 인가에 해당합니다.

스프링 시큐리티의 필터 기반 동작 🧑🏻‍⚖️

Spring Security는 필터 기반으로 동작합니다. 다양한 필터들이 순차적으로 인증과 인가 작업을 처리하며, 각 필터는 특정 역할을 수행합니다. 대표적인 필터로는 UsernamePasswordAuthenticationFilter와 FilterSecurityInterceptor가 있습니다.

  • UsernamePasswordAuthenticationFilter: 폼 기반 로그인 시 사용되는 필터로, 아이디와 패스워드를 받아서 인증을 요청합니다. 인증이 성공하면 AuthenticationSuccessHandler가 실행되고, 실패하면 AuthenticationFailureHandler가 실행됩니다.
  • FilterSecurityInterceptor: 권한 부여를 처리하는 필터로, AccessDecisionManager를 통해 사용자가 요청한 리소스에 접근할 권한이 있는지 판단합니다.

스프링 시큐리티의 인증 처리 흐름

  1. 사용자가 폼에 아이디와 패스워드를 입력합니다.
  2. UsernamePasswordAuthenticationFilter가 아이디와 패스워드를 검증하고, UsernamePasswordAuthenticationToken을 생성합니다.
  3. 생성된 인증용 토큰을 AuthenticationManager에게 전달하여 인증을 진행합니다.
  4. AuthenticationProvider가 사용자 아이디를 UserDetailsService로 전달하여 사용자의 정보를 UserDetails 객체로 가져옵니다.
  5. 인증이 성공하면 SecurityContextHolder에 인증 정보를 저장하고, 인증 성공/실패 여부에 따라 AuthenticationSuccessHandler 또는 AuthenticationFailureHandler가 실행됩니다.

Spring Security 구현 예시

다음은 Form 기반의 로그인과 로그아웃을 구현하는 간단한 예시입니다.

1. 의존성 추가 (build.gradle)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
    testImplementation 'org.springframework.security:spring-security-test'
}

2. 엔티티 작성

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Table(name = "users")
public class User implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(new SimpleGrantedAuthority("user"));
    }

    @Override
    public String getUsername() {
        return email;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}
  • UserDetails 인터페이스: 사용자의 인증 정보를 나타내며, 이를 구현하여 사용자 정보를 제공하는 엔티티를 정의합니다.

3. 리포지터리 작성

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

4. 서비스 작성 (UserDetailService)

@Service
@RequiredArgsConstructor
public class UserDetailService implements UserDetailsService {
    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        return userRepository.findByEmail(email).orElseThrow(() -> new IllegalArgumentException(email));
    }
}
  • UserDetailsService 인터페이스를 구현하여 사용자의 정보를 가져오는 메서드를 작성합니다.

5. 시큐리티 설정 (WebSecurityConfig)

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebSecurityConfig {
    private final UserDetailsService userService;

    @Bean
    public WebSecurityCustomizer configure() {
        return (web) -> web.ignoring().requestMatchers(new AntPathRequestMatcher("/static/**"));
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(
                                new AntPathRequestMatcher("/login"),
                                new AntPathRequestMatcher("/signup"),
                                new AntPathRequestMatcher("/user")
                        ).permitAll()
                        .anyRequest().authenticated())
                .formLogin(formLogin -> formLogin
                        .loginPage("/login")
                        .defaultSuccessUrl("/articles")
                )
                .logout(logout -> logout.logoutSuccessUrl("/login")
                        .invalidateHttpSession(true)
                )
                .csrf(AbstractHttpConfigurer::disable)
                .build();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
  • SecurityFilterChain: 인증, 인가, 로그인, 로그아웃 관련 설정을 정의합니다.

6. 회원 가입 구현

서비스 메서드 작성:

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    public Long save(AddUserRequest dto) {
        return userRepository.save(User.builder()
                .email(dto.getEmail())
                .password(bCryptPasswordEncoder.encode(dto.getPassword()))
                .build()).getId();
    }
}

컨트롤러 작성:

@Controller
@RequiredArgsConstructor
public class UserApiController {
    private final UserService userService;

    @PostMapping("/user")
    public String signup(AddUserRequest request) {
        userService.save(request);
        return "redirect:/login";
    }

    @GetMapping("/logout")
    public String logout(HttpServletRequest request, HttpServletResponse response) {
        new SecurityContextLogoutHandler().logout(request, response, SecurityContextHolder.getContext().getAuthentication());
        return "redirect:/login";
    }
}

Spring Security의 활용 🧐

  • 로그인/로그아웃 기능 구현
  • 특정 페이지에 대한 접근 권한 설정 (예: 관리자 페이지 접근 제한)
  • CSRF 방어 및 세션 관리

Spring Security는 필터 기반으로 동작하며, 사용자 인증과 인가 정보를 UserDetails 객체에 담아 관리합니다. 이를 통해 애플리케이션의 보안을 강화하고, 특정 사용자만 리소스에 접근할 수 있도록 제어할 수 있습니다.

'🌱 Spring > Spring Boot' 카테고리의 다른 글

[Spring] JWT  (0) 2024.10.16
[Spring] Spring Batch - Batch와 Job, Step  (1) 2024.10.16
[Spring] Spring MVC  (0) 2024.10.16
[Spring] @Annotation  (0) 2024.10.16
[Spring] Spring AOP  (0) 2024.10.16
'🌱 Spring/Spring Boot' 카테고리의 다른 글
  • [Spring] JWT
  • [Spring] Spring Batch - Batch와 Job, Step
  • [Spring] Spring MVC
  • [Spring] @Annotation
kkongdo
kkongdo
kkongdo 님의 블로그 입니다.
  • kkongdo
    숲을 바라보며 나무를 심는 아이
    kkongdo
  • 전체
    오늘
    어제
    • 분류 전체보기 (32)
      • 🌏 Web (0)
      • ☕ Java (5)
      • 🌱 Spring (9)
        • Spring Boot (7)
        • Spring Data JPA & QueryDSL (2)
      • 🗂️ Database (5)
      • 💻 CS (12)
        • 운영체제 (4)
        • 네트워크 (5)
        • 자료구조 (3)
      • 🗃️Git (1)
      • 🔍 Algorithm (0)
      • 📡 DevOps (0)
        • Docker (0)
      • 🔭 ETC (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • GitHub
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스케줄링
    운영체제
    DI
    springbatch
    @annotation
    자료구조
    네트워크기기
    조인
    java
    QueryDSL
    spring
    OS
    복잡도
    데이터베이스
    JPA
    네트워크
    SpringMVC
    CS
    SpringSecurity
    db
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
kkongdo
[Spring] Spring Security
상단으로

티스토리툴바