내부구조
SecurityContext context = SecurityContextHolder.getContext(); // Security Context
Authentication authentication = context.getAuthentication(); // authentication
authentication.getPrincipal();
authentication.getAuthorities();
authentication.getCredentials();
authentication.getDetails();
authentication.isAuthenticated();
- SecurityContextHolder
- SecurityContextHolder는 SecurityContext를 제공하는 static 메소드(getContext)를 지원합니다.
- getContext()에는 현재 로그인한 유저의 security 정보를 전달
- SecurityContext
- SecurityContext 는 접근 주체와 인증에 대한 정보를 담고 있는 Context
- 즉, Authentication 을 담고 있다.
- ThreadLocal에 있는 SecurityContext를 가져온다.
- Authentication
- Principal과 GrantAuthority를 제공합니다.
- 인증이 이루어 지면 해당 Athentication이 저장됩니다.
- Principal
- 유저에 해당하는 정보
- 대부분의 경우 Principal로 UserDetails를 반환함
- GrantAuthority
- ROLE_ADMIN, ROLE_USER등 Principal이 가지고 있는 권한을 나타냄
- prefix로 ‘ROLE_’ 이 붙는다
- 인증 이후에 인가를 할 때 사용
- 권한은 여러개 일수 있기 때문에 Collection<GrantedAuthority>형태로 제공
ex) ROLE_DEVELOPER, ROLE_ADMIN
ThreadLocal
Spring Security의 기본적인 Security Context 관리 전략은 ThreadLocal을 사용하는 ThreadLocalSecurityContextHolderStrategy 이다.
변수는 지역변수, 전역변수와 같은 유효한 Scope을 가진다. 마찬가지로, ThreadLocal은 Thread마다 고유한 영역을 가지고 있는 곳에 저장된 변수로 각각의 Thread안에서 유효한 변수.
일반적인 서버의 경우에는 외부로부터 요청이 오면 그 요청마다 Thread 1개가 할당된다. 따라서 ThreadLocal로 SecurityContext를 관리하게 되면 SecurityContext는 요청마다 독립적으로 관리될 수 있다.
우리가 WebMVC 기반으로 프로젝트를 만든다는 가정하에 대부분의 경우에는 요청 1개에 Thread 1개가 생성됨.
요청 1개 : Thread1개
이때 ThreadLocal을 사용하면 Thread마다 고유한 공간을 만들수가 있고 그곳에 SecurityContext를 저장할 수 있다.
요청1개 : Thread1개 : Security Context1개
그러나 ThreadLocal만 강제로 사용해야하는 것은 아니며 원하면 SecurityContext 공유 전략을 바꿀 수 있다.
더보기 클릭!
- MODE_THREADLOCAL
ThreadLocalSecurityContextHolderStrategy를 사용
ThreadLocal을 사용하여 같은 Thread안에서 SecurityContext를 공유. 기본 설정 모드
- MODE_INHERITABLETHREADLOCAL
InheritableThreadLocalSecurityContextHolderStrategy를 사용
InheritableThreadLocal을 사용하여 자식 Thread까지도 SecurityContext를 공유
- MODE_GLOBAL
GlobalSecurityContextHolderStrategy를 사용.
Global로 설정되어 애플리케이션 전체에서 SecurityContext를 공유
PasswordEncoder
유저의 패스워드 관리 방법에 아래의 두가지가 만족되어야함.
1. 회원가입할 때 Password를 입력받으면 그 값을 암호화해서 저장
2. 로그인할 때 입력받은 Password와 회원가입할 때의 Password를 비교가능해야함
이 두가지를 만족시키기 위해서, 해시 함수라는 알고리즘 방식을 이용
해시 함수는 암호화는 비교적 쉽지만 복호화가 거의 불가능한 방식의 알고리즘
이것을 사용하면 아래와 같은 방식으로 password를 관리할수 있다.
1. 회원가입할 때 password를 해시함수로 암호화해서 저장.
2. 로그인할 때 password가 들어오면 같은 해시함수로 암호화.
3. 저장된 값을 불러와서 2번의 암호화된 값과 비교.
4. 동일하면 같은 암호로 인지한다.
public interface PasswordEncoder {
/**
* @param rawPassword 평문 패스워드
* @return 암호화된 패스워드
*/
String encode(CharSequence rawPassword);
/**
* @param rawPassword 평문 패스워드
* @param encodedPassword 암호화된 패스워드
* @return rawPassword를 암호화한 값과 encodedPassword의 일치 여부
*/
boolean matches(CharSequence rawPassword, String encodedPassword);
}