[spring] Spring Security
기존 프로젝트는 로그인 보안은 하나도 안해놨었다. 그래서 스터디를 하면서 알게 된 스프링 시큐리티를 통해 프로젝트 리팩토링을 진행했다. 처음 구현할 때 너무 복잡하다보니까 따라하면서 해보면 알게되겠지 했다가... 개념은 공부하고 가야하할꺼 같아서 정리해보자 한다.
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();
}
...
}
시큐리티의 기본 개념을 공부하고 생각해보니까 어떻게 적용하고 구현해야하는지 이제서야 감이 잡히는 듯 하다.
간단히 살펴보고만 적용하지 말고 좀 제대로 보고 공부하고 적용시켜야겠다 ㅎ...