# [Security] Spring Security란?
Study Repository

[Security] Spring Security란?

by rlaehddnd0422

Spring Security란?

  • Spring Security는 Spring 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크입니다.
  • Spring Security는 '인증' , '권한'에 대한 부분Filter 흐름에 따라 처리합니다.
  • Spring Security는 기본적으로 인증(로그인) 절차를 거친 후 인가(접근 권한) 절차를 진행합니다.
  • 이 때 기본적으로 인증과 인가를 위해 Principal(접근 주체)을 아이디로, Credential(비밀번호)을 비밀번호로 사용하는 Credential 기반의 인증방식을 사용합니다.

Filter VS Interceptor 

필터 : HTTP Request ▶︎ WAS ▶︎ 필터 ▶︎ 서블릿 ▶︎ 컨트롤러 
인터셉터 : HTTP Request ▶︎ WAS ▶︎ 서블릿 ▶︎ 스프링 인터셉터 ▶︎ 컨트롤러
 

Servlet Filter(서블릿 필터)

요구사항을 보면 로그인 한 사용자만 상품 관리 페이지에 들어갈 수 있어야 하는데, 로그인을 하지 않아도 URL을 통해 상품 관리 페이지에 접근할 수 있습니다. http://localhost:8080/items 상품 관리 컨

rlaehddnd0422.tistory.com

 

 

스프링 인터셉터(Interceptor)

스프링 인터셉터 자바 표준스펙이 제공하는 서블릿 필터처럼 웹과 관련된 공통 관심사항을 효과적으로 해결할 수 있는 기술입니다. 인터셉터 특징 인터셉터는 서블릿 필터의 흐름과 비슷한 흐

rlaehddnd0422.tistory.com

 

Filter는 컨트롤러, Dispatcher Servlet에 가기 전에 적용되므로 가장 먼저 URL 요청을 받지만, (웹 컨테이너에서 관리) 

Interceptor는 Dispatcher Servlet과 Controller 사이에 위치한다는 점에서 적용 시기의 차이가 있습니다. (스프링 컨테이너에서 관리)

 

스프링 시큐리티는 보안과 관련해서 많은 옵션을 체계적으로 제공해주기 때문에 개발자 입장에서는 일일이 보안관련 로직을 작성하지 않고 보안 기능들을 사용할 수 있습니다.

 

스프링 시큐리티를 다루기에 앞서 전체적인 인증관련 흐름과 모듈들을 한 번 쭉 살펴봅시다.

전체적인 인증관련 아키텍쳐 Flow

1. HTTP 요청을 하면 AuthenticationFilter가 요청을 가로챕니다.

 

2. Filter에서 UsernamePasswordAuthenticafionToken에게 인증 전 객체를 전달하여 인증용 객체(UsernamePasswordToken)를 생성합니다.  

 

3. 필터에서 AuthenticationManager에 객체(UsernamePasswordToken) 전달

 

4. 구현한 AuthenticationManager에 등록된 AuthenticationProvider를 찾아서 객체(UsernamePasswordToken) 전달

 

5. UserDetailsService에서 실제 DB에 접근하여 인증 절차를 ID와 PASSWORD로 검증

 

6. DB에 있는 유저라면 (인증에 성공)  인증 성공 객체에 대한 정보( 아이디, 비밀번호, 계정만료 여부, 휴면 계정 여부, 계정 잠김 여부, 계정 사용 가능 여부)와 세션을 UserDetails에 담아 리턴

 

7. AuthenticationProvider에서 UserDetails를 넘겨받아 사용자 정보를 비교

 

8. 인증이 완료되면 권한 등의 사용자 정보를 담은 Authentication 객체가 리턴 

 

9. 다시 최초에 AuthenticationFilter에 Authentication 객체가 리턴

 

10. Authentication 객체를 SecurityContext에 저장.

 

주요 모듈 

Spring Security 3 Internals

1. SecurityContextHolder 

public class SecurityContextHolder {

    public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";

    public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";

    public static final String MODE_GLOBAL = "MODE_GLOBAL";

    private static final String MODE_PRE_INITIALIZED = "MODE_PRE_INITIALIZED";

    public static final String SYSTEM_PROPERTY = "spring.security.strategy";
  • 보안 주체의 세부정보 포함, 응용프로그램의 현재 SecurityContext에 대한 세부정보 저장 
  • 기본적으로 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 방법,  SecurityContextHolder.MODE_THREADLOCAL 방법 제공

2. SecurityContext

public interface SecurityContext extends Serializable {

   Authentication getAuthentication();

   void setAuthentication(Authentication authentication);

}
  • Authentication을 보관(setAuthentication) 및 꺼내서 사용 가능(getAuthentication)

3. Authentication

public interface Authentication extends Principal, Serializable {

   Collection<? extends GrantedAuthority> getAuthorities();

   Object getCredentials();

   Object getDetails();

   Object getPrincipal();

   boolean isAuthenticated();

   void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;

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

4. GrantedAuthority

public interface GrantedAuthority extends Serializable {

   String getAuthority();

}
  • 현재 사용자(Principal)이 가지고 있는 권한을 의미하는 인터페이스.
  • 보통 ROLER_*의 형태로 사용하며, 보통 roles라고 합니다. UserDetailsService에 의해 불러올 수 있고 특정 자원에 대한 접근 권한 검사 및 허용 여부 결정

Authentication

1. AuthenticationManager

public interface AuthenticationManager {

   Authentication authenticate(Authentication authentication) throws AuthenticationException;

}
  • 실질적으로 인증에 대한 부분을 처리하는 역할 ( AuthenticationManager에 등록된 AuthenticationProvider에 의해 처리 )
  • 인증이 성공하면 2번째 생성자를 이용해 인증이 성공한(isAuthenticated=true) 객체를 생성하여 SecurityContext에 저장합니다.
  • 인증 실패 시 AuthenticationException 예외를 터뜨림

2. AuthenticationProviders

public interface AuthenticationProvider {
	
    // 인증이 안된 Authentication 객체를 받아 인증된 Authentication 객체로 리턴 
    Authentication authenticate(Authentication authentication) throws AuthenticationException;

    boolean supports(Class<?> authentication);
}
  • 실제 인증에 대한 부분을 처리합니다.
  • 인증 전의 Authentication 객체를 받아서 인증이 완료된 객체를 리턴하는 역할
  • 이 인터페이스를 구현하여 Ioc하여 AuthenticationManager에 등록하여 사용하면 됩니다.

3. UserDetailsService

public interface UserDetailsService {

    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;

}
  • UserDetails 객체를 반환하는 메소드 loadUserByUsername(String var1)를 가짐
  • 이를 구현한 클래스의 내부에 UserRepository를 주입받아 DB와 연결하여 처리합니다.

3-1. UserDetails

public interface UserDetails extends Serializable {


   Collection<? extends GrantedAuthority> getAuthorities();

   String getPassword();

   String getUsername();

   boolean isAccountNonExpired();

   boolean isAccountNonLocked();

   boolean isCredentialsNonExpired();

   boolean isEnabled();

}
  • 인증에 성공 후 생성된 객체 UserDetails는 Authentication 객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용됩니다.
  • 인증에 성공한 객체에 대한 정보를 반환하는 메소드를 가지고 있습니다.
// Security Session => Authentication => UserDetails(PrincipalDetails)

public class PrincipalDetails implements UserDetails {
    private User user;

    public PrincipalDetails(User user) {
        this.user = user;
    }

    // 해당 User의 권한을 리턴하는 곳
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collection = new ArrayList<>();
        collection.add(
                new GrantedAuthority(){
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collection;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    // 계정 만료여부
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // 계정 잠김x 여부
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

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

    // 휴면 계정
    @Override
    public boolean isEnabled() {

        // 1년동안 로그인 안하면 휴면계정으로 하기로함
        // 현재시간 - 마지막로그인날짜 => 1년초과화면 false
        // else true
        return true;
    }
}
  • 보통 이렇게 UserDetails를 implements하여 처리합니다.

4. UsernamePasswordAuthenticationToken

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

   private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

   private final Object principal;

   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
   }

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

 

<참고 자료>

 

 

[SpringBoot] Spring Security란?

대부분의 시스템에서는 회원의 관리를 하고 있고, 그에 따른 인증(Authentication)과 인가(Authorization)에 대한 처리를 해주어야 한다. Spring에서는 Spring Security라는 별도의 프레임워크에서 관련된 기능

mangkyu.tistory.com

 

 

Spring Security의 구조(Architecture) 및 처리 과정 알아보기

시작하기 앞서 스프링 시큐리티에서 어플리케이션 보안을 구성하는 두 가지 영역에 대해 간단히 알아보자. 인증(Authentication)과 인가(Authorization) 대부분의 시스템에서는 회원을 관리하고 있고,

dev-coco.tistory.com

 

 

스프링 시큐리티 기본 API및 Filter 이해

목차

catsbi.oopy.io

 

블로그의 정보

Study Repository

rlaehddnd0422

활동하기