Java/Spring

[spring] Spring Security

berryberries 2023. 10. 23. 01:42

 

 기존 프로젝트는 로그인 보안은 하나도 안해놨었다. 그래서 스터디를 하면서 알게 된 스프링 시큐리티를 통해 프로젝트 리팩토링을 진행했다. 처음 구현할 때 너무 복잡하다보니까 따라하면서 해보면 알게되겠지 했다가... 개념은 공부하고 가야하할꺼 같아서 정리해보자 한다.

 

1. Spring Security?

 Spring Security는 자바 기반의 어플리케이션에서 인증과 인가 및 웹보안을 제공해주는 프레임워크이다.

프레임워크이기 때문에 이미 짜여져 있는 내부 로직을 통해  인증과 권한 확인 등의 기능을 제공해준다.  그래서 개발자가 따로 보안 로직을 따로 구현하지 않아도 되는 편리함이 ++된다.

 

2. 인증 방식

스프링 시큐리티의 기본적인 인증방식은 credential 방식이다.

credential 방식은 principal과 credential을 사용해서 인증을 하는데  한마디로 아이디 비밀번호 인증을 말한다.

  • principal : username (아이디)
  • credential : password (비밀번호)

이 두 정보는 Authentication객체에 저장되는 사용자의 정보이다. 이 정보는 securityContext에 저장되는데 securityContext는 하단부에 정리할것이다.

 

3. Spring Securtiy의 동작원리

 

 

 

1) Http Request 요청을 받는다.

  •  로그인을 할 때 userid와 password(유저의 정보)를 입력하고 인증요청을 보낸다

2) 유저의 정보를 기반으로 Authentication Token을 생성한다.

  • AuthenticationFilter가 유저의 정보를 가로채서 UsernamePasswordAuthentication Token의 인증용 객체를 생성한다.

3) Filter을 통해서 Authentication Token을 AuthenticationManager에 보내준다. 

  • AuthenticationManager에게 생성된 UsernamePasswordAuthentication Token의 객체를 전달한다.
  • *ProviderManager : 인증처리를 하는 클래스

4) AuthenticationManager의 목록을 조회해서 인증을 시도한다.

  • 유저인증요청이 들어오면 AuthenticationManager는 AuthenticationProvider들에게 순차적으로 인증을 요청한다.

5) UserdetailService를 통해서 유저의 정보를 가져온다.

  • DB에 저장되어 있는 유저정보를 UserDetailsService에게 넘겨준다.
  • *UserDetailsService : DB에 저장된 유저정보를 가져오는 클래스 
  • *loadUserByUsername(String username) : username(아이디)를 입력받아 해당 유저의 정보를 가져온다.

6) UserDetails를 통해서 User객체에 대한 정보를 탐색한다.

  • 넘겨받은 유저정보로 DB에 저장된 유저 정보인 UserDetails 객체를 생성한다.
  • *UserDetails : 반환되는 객체, 인터페이스를 구현한 객체여야한다. 
  •                         상세정보를 담고있다. (유저의 권한정보와 인증정보)

7)  User객체에 저장된 정보를 UserDetails가 UserDetailsService로 전달한다.

  •  AuthenticationProvider들이 UserDetails에서 넘겨받고 유저정보를 비교한다. 
  • 이 과정에서 인증이 완료된다.

8) AuthenticationManager에 유저정보를 담은 Authentication 객체 반환

  •  유저 정보에는 해당 유저의 권한등의 담겨있다.

9) Filter에 Authentication 객체 반환

10) SecurityContext에 Authentication 객체를 저장시킨다.

 

4. SecurityContextHolder

//위치 : 의존성 주입할 때 core를 추가하는데 그곳에 있다.
package org.springframework.security.core.context;

1) SecurityContextHolder 구조

① Authentication

  • 접근주체(유저)의 인증정보와 권한을 담은 인터페이스.
  • 유저의 인증정보를 저장한다.
  • authentication은 securityContext에 저장된다.
  • 구조
principal 유저의 아이디
credientials 유저의 패스워드
authorities 인증된 유저의 접근권한목록
details 인증에 대한 부가정보
authenticated boolean타입의 인증 유무

 

② SecurityContext

Interface defining the minimum security information associated with the current thread of execution. 
The security context is stored in a {@link SecurityContextHolder}.
  • Authentication 객체를 보관하는 저장소
  • Authentication 객체가 필요할 때마다 꺼내 사용할 수 있다.
  • ThreadLocal 를 사용하기 때문에 동일한 스레드를 사용할 땐 어디서나 꺼내 쓸 수 있지만 스레드가 변경되면 사용불가
  • *SecuirtyContext는 ThreadLocal 와 httpSession(인증 완료 후)에 저장되어 있다.

 

③ SecurityContextHolder

  • securityContext를 저장하고 있는 wrapper클래스
  • threadLocal를 가지고 있는 객체
  • ThreadLocal의 전략을 설정할 수 있다. 
    • 라이브러리를 확인해보면 기본 모드는 threadLocal에 저장되는 것을 확인 가능하다.
    • ThreadLocalSecurityContextHolderStrategy()를 호출하는데 SecurityContextHolder는 해당 인스턴스에 위임을 해서 사용한다.
private static void initialize() {
    if (!StringUtils.hasText(strategyName)) {
        // Set default
        strategyName = MODE_THREADLOCAL;
    }

    if (strategyName.equals(MODE_THREADLOCAL)) {
        strategy = new ThreadLocalSecurityContextHolderStrategy();
    }
							...
}

 

 

시큐리티의 기본 개념을 공부하고 생각해보니까 어떻게 적용하고 구현해야하는지 이제서야 감이 잡히는 듯 하다.

간단히 살펴보고만 적용하지 말고 좀 제대로 보고 공부하고 적용시켜야겠다 ㅎ...