ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SpringSecurityContextHolder와 Authentication
    Spring/Spring 2020. 7. 23. 16:36

     

    • SecurityContextHolder -> SecurityContext -> Authentication
    • Authentication안에 Principal 정보가 들어가 있다. principal은 인증한 사용자의 정보를 나타낸다.

     

    • 인증한 사용자의 정보란?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Service
    public class AccountService implements UserDetailsService {
     
        @Autowired AccountRepository accountRepository;
        @Autowired
        PasswordEncoder passwordEncoder;
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            Account account = accountRepository.findByUsername(username);
            if(account == null) {
                throw new UsernameNotFoundException(username);
            }
            return User.builder()
                    .username(account.getUsername())
                    .password(account.getPassword())
                    .roles(account.getRole())
                    .build();
        }
    }
     
    cs

     

    • 예를 들어 accountRepository에서 한 계정을 만들었다고 가정하자.
    • 스프링 시큐리티는 인증 관리 시 Dao 인터페이스를 통해 유저 정보를 읽어오고 이 역할이 UserDetailsService다.

     

    • UserDetailsService 인터페이스의 loadUserByUsername을 Override 하여 account 계정으로 User를 생성할 수 있도록 해준다.

    ( 스프링 시큐리티는 기본적으로 모든 API에 접근 제한을 걸게 되고 User로 로그인한 상태만 접근할 수 있다. )

     

    • 이때 User.builder()는 스프링 시큐리티가 우리 계정을 UserDetails 타입으로 편히 바꿀 수 있도록 Spring Security에서 제공하는 타입이다.

     

     

     

    • App에서 인증을 거치게 되고 인증된 사용자 정보를 principal이라고 한다. 
    • 이 principal은 Authentication 객체 안에 담아서 관리하게 되며 콘텍스트와 콘텍스트 홀더로 Authentication을 감싼 형태가 된다 ( 위 그림 참조 )

     

    • 이제 다음과 같이 SecurityContextHolder에서 인증된 사용자 정보 ( principal )을 꺼내올 수 있다.
    • 이 Object는 사실상 UserDetails 타입이라고 볼 수 있다.
    • authorities는 GrantAuthority라는 컬렉션이 들어있고 principal이 사용자라면 사용자에 권한을 나타내는 것이 Authorities 가 된다. 사용자의 권한은 여러 개 가질 수 있으니 컬렉션이 된다.

     

    직접 Debugger을 통해 확인해보자.

     

     

    • principal은 User 타입이다. UserDetailsService에서의 구현체에서 return 한 User 타입이며 이게 곧 Principal이다.

     

    • Authentication에서 authorities를 보면 역시 하나가 들어있는 것을 볼 수가 있는데
    • SimpleGrantedAuthority 타입에 "ROLE_USER"가 들어있다. 이 정보는 Principal의 권한을 나타낸다.

     

    정리 :

     

    1. SpringSecurityContextHolder에는 Authentication이 담겨있다. 이 홀더는 ThreadLocal을 사용하며

    어디서나 접근할 수 있도록 해준다.

     

    ( 어떤 요청이 들어올 때 요청이 처리되는 Thread는 우리가 명시적으로 Async를 사용하지 않는 이상 동일한 Thread가

    처리하게 된다. Request당 하나의 Thread라고 보면 된다. 최종적으로 App안에 들어와서 요청을 처리하는 로직은 대부분의 경우 한 Thread가 처리한다. ex) 스프링 트랜잭션 처리)

     

    2. 컨트롤러 안에서 서비스 쪽으로 principal에 대한 정보를 넘겨주지 않아도 SecurityContextHolder를 통해서 Authentication을 정보를 참조할 수 있다.

     

    3. Authentication에는 크게 2가지 정보로 Principal과 GrantAuthority에 정보를 가지고 있다.

     

    • Principal - 누구에 해당하는 정보이며 UserDetailsService에서 Return 한 객체이다.
    • GrantAuthority - 누구에 해당하는 사용자가 어떤 권한을 가지고 있는지에 대한 정보이다.

     

    4. UserDetailsService는 유저 정보를 UserDetails 타입으로 가져오는 DAO 인터페이스이다. DB에 있는 유저 정보를 Spring Security에 제공하는 역할만 하며 UserDetailsService를 사용해서 실제로 인증하는 역할은 AuthenticationManager가 하게 된다.

     

     

     

     

     

    참고 : 인프런(백기선) - 스프링 시큐리티

     

     

Designed by Tistory.