웹기반어플리케이션

[Spring] Spring Security

햄찌개 2021. 1. 11. 13:53

1) Spring Security란?

  • Spring Security는 Spring 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 Spring 하위 프레임워크입니다.
  • Spring Security는 "인증" 과 "권한" 에 대한 부분을 Filter의 흐름에 따라 처리합니다.
  • Spring Security는 보안과 관련해서 체계적으로 많은 옵션을 제공해주기 때문에 개발자 입장에서는 일일이 보안 관련 로직을 작성하지 않아도 된다는 장점이 있습니다.

2) 인증과 인가란?

인증(Authentication)

  • 해당 사용자가 본인이 맞는지를 확인하는 절차

인가(Authorization)

  • 인증된 사용자가 요청한 자원에 접근 가능한지를 결정하는 절차
  • Spring Security는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지 확인을 하게 됩니다.
  • 이러한 인증과 인가를 위해 Principal 을 아이디로, Credential 을 비밀번호로 사용하는 Credential 기반의 인증 방식 을 사용합니다.
  • Principal(접근 주체) : 보호 받는 리소스에 접근하는 대상
  • Credential(비밀번호) : 리소스에 접근하는 대상의 비밀번호

3) Spring Security의 주요 모듈

Authentication

  • Authentication 은 현재 접근하는 주체의 정보와 권한을 담는 인터페이스입니다.
  • SecurityContext에 저장되며, SecurityContextHolder 를 통해 SecurityContext에 접근하고, SecurityContext 를 통해 Authentication 에 접근할 수 있습니다.

SecurityContext

  • Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication 객체를 꺼내올 수 있습니다.

SecurityContextHolder

  • SecurityContextHolder는 보안 주체의 세부 정보를 포함하여 응용 프로그램의 현재 보안 컨텍스트에 대한 세부 정보가 저장됩니다.

Spring Security에서의 인증 처리 과정

  • username과 password를 조합해서 UsernamePasswordAuthenticationToken 인스턴스를 만듭니다.
  • 이 토큰은 검증을 위해 AuthenticationManager의 인스턴스로 전달됩니다.
  • AuthenticationManager는 인증에 성공하면 Authentication 인스턴스를 리턴합니다.
  •  Authentication 인스턴스는 SecurityContextHolder에 저장됩니다.

UsernamePasswordAuthenticationToken

  • Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로 username이 Principal의 역할을 하고, password가 Credential의 역할을 합니다.
  • 첫번째 생성자는 인증 전의 객체를 생성하고, 두번째 생성자는 인증이 완료된 객체를 생성해줍니다.

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken { // 주로 사용자의 username에 해당함 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 } }

AuthenticationProvider

  • 실제 인증에 대한 부분을 처리하는데, 인증 전의 Authentication 객체를 받아서 인증이 완료된 객체를 반환하는 역할을 합니다.

AuthenticationManager

  • 인증에 대한 부분은 AuthenticationManager를 통해서 처리하게 되는데, 실질적으로는 AuthenticationManager에 등록된 AuthenticationProvider에 의해 처리됩니다.

  • 인증이 성공하면 isAuthenticated=true 인 객체를 생성하여 SecurityContext에 저장합니다.

  • 실패할 경우에는 AuthenticationException을 발생시킵니다.

  • DaoAuthenticationProvider는 AbstractUserDetailsAuthenticationProvider를 상속받아 실제 인증 과정에 대한 로직을 처리합니다.

  • AuthenticationManager에 DaoAuthenticationProvider를 등록하는 방법은 WebSecurityConfigurerAdapter를 상속해 만든 ApplicationSecurityConfig에서 할수 있습니다.

@Configuration @EnableWebSecurity public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter { private final PasswordEncoder passwordEncoder; @Autowired public ApplicationSecurityConfig(PasswordEncoder passwordEncoder,) { this.passwordEncoder = passwordEncoder; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(daoAuthenticationProvider()); } @Bean public DaoAuthenticationProvider daoAuthenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setPasswordEncoder(passwordEncoder); provider.setUserDetailsService(applicationUserService); return provider; } }

UserDetails

  • 인증에 성공하여 생성된 UserDetails 객체는 UsernamePasswordAuthenticationToken을 생성하기 위해 사용됩니다.
  • UserDetails 인터페이스의 경우 직접 개발한 ApplicationUser에 UserDetails를 implements하여 사용하면 됩니다

UserDetailsService

  • UserDetails 객체를 반환하는 단 하나의 메소드를 가지고 있는데, 일반적으로 이를 구현한 클래스의 내부에 UserRepository를 주입받아 DB에 연결하여 처리합니다.

GrantedAuthority

  • 현재 사용자(Principal)가 가지고 있는 권한들입니다.
  • 보통 ROLE_ADMIN, ROLE_USER와 같이 ROLE_의 형태로 사용됩니다.