일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- if문
- 알고리즘
- java조건문
- 2차원배열
- #java_festival
- for문 369게임
- #알고리즘
- 팩토리얼
- 삼항 연산자
- 증감연산자
- 피보나치수열
- #이차원배열
- 변수의특징
- #Java
- JAVA기초
- 비교연산자
- 논리연산자
- 복합대입연산자
- 데이터타입
- 별찍기
- switch-case문
- #완전수구하기
- 이진수
- 연산자
- 로또 프로그램
- plusgame
- 소인수분해
- else if문
- java
- switch문
- Today
- Total
숭어 개발 블로그
[Spring Security] 아키텍쳐 및 동작원리 본문
Spring Security
Spring Security는 인증, 권한 관리 그리고 데이터 보호 기능을 포함하여 웹 개발 과정에서 필수적인 사용자 관리 기능을 구현하는데 도움을 주는 Spring의 강력한 프레임워크
개발자들이 보안 관련 기능을 효율적이고 신속하게 구현할 수 있도록 도움
Spring Security 아키텍처
1. Http Request 수신
-> 사용자가 로그인 정보와 함께 인증 요청을 한다.
2. 유저 자격을 기반으로 인증토큰 생성
-> AuthenticationFilter가 요청을 가로채고, 가로챈 정보를 통해 UsernamePasswordAuthenticationToken의 인증용 객체를 생성한다.
3. FIlter를 통해 AuthenticationToken을 AuthenticationManager로 위임
-> AuthenticationManager의 구현체인 ProviderManager에게 생성한 UsernamePasswordToken 객체를 전달한다.
4. AuthenticationProvider의 목록으로 인증을 시도
-> AutenticationManger는 등록된 AuthenticationProvider들을 조회하며 인증을 요구한다.
5. UserDetailsService의 요구
-> 실제 데이터베이스에서 사용자 인증정보를 가져오는 UserDetailsService에 사용자 정보를 넘겨준다.
6. UserDetails를 이용해 User객체에 대한 정보 탐색
-> 넘겨받은 사용자 정보를 통해 데이터베이스에서 찾아낸 사용자 정보인 UserDetails 객체를 만든다.
7. User 객체의 정보들을 UserDetails가 UserDetailsService(LoginService)로 전달
-> AuthenticaitonProvider들은 UserDetails를 넘겨받고 사용자 정보를 비교한다.
8. 인증 객체 or AuthenticationException
-> 인증이 완료가되면 권한 등의 사용자 정보를 담은 Authentication 객체를 반환한다.
9. 인증 끝
-> 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환된다.
10. SecurityContext에 인증 객체를 설정
-> Authentication 객체를 Security Context에 저장한다.
최종적으로는 SecurityContextHolder는 세션 영역에 있는 SecurityContext에 Authentication 객체를 저장한다. 사용자 정보를 저장한다는 것은 스프링 시큐리티가 전통적인 세선-쿠키 기반의 인증 방식을 사용한다는 것을 의미한다.
Spring Security가 작동하는 내부 구조
1. 사용자가 자격 증명 정보를 제출하면, AbstractAuthenticationProcessingFilter가 Authentication 객체를 생성합니다.
2. Authentication 객체가 AuthenticationManager에게 전달됩니다.
3. 인증에 실패하면, 로그인 된 유저정보가 저장된 SecurityContextHolder의 값이 지워지고 RememberMeService.joinFail()이 실행됩니다. 그리고 AuthenticationFailureHandler가 실행됩니다.
4. 인증에 성공하면, SessionAuthenticationStrategy가 새로운 로그인이 되었음을 알리고, Authentication 이 SecurityContextHolder에 저장됩니다. 이후에 SecurityContextPersistenceFilter가 SecurityContext를 HttpSession에 저장하면서 로그인 세션 정보가 저장됩니다.
그 뒤로 RememberMeServices.loginSuccess()가 실행됩니다. ApplicationEventPublisher가 InteractiveAuthenticationSuccessEvent를 발생시키고 AuthenticationSuccessHandler 가 실행됩니다.
주요 컴포넌트 : SecurityContextHolder, SecurityContext, Authentication
Authentication 클래스는 현재 접근하는 주체의 정보와 권한을 담는 인터페이스고 SecurityContext 저장되며 SecurityContextHolder를 통해 SecurityContext에 접근하고, SecurityContext를 통해 Authentication에 접근할 수 있다.
Authentication
현재 접근하는 주체의 정보와 권한을 담는 인터페이스이다. Authentication 객체는 SecurityContext에 저장되며,
SecurityContextHolder를 통해 SecurityContext에 접근하고, SecurityContext를 통해 Authentication에 접근할 수 있다.
SecurityContextHolder
SecurityContextHolder는 보안 주체의 세부 정보를 포함하여 응용프로그램의 현재 보안 컨텍스트에 대한 세부 정보가 저장된다.
SecurityContext
Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication을 저장하거나 꺼내올 수 있다.
|
SecurityContextHolder.getContext().setAuthentication(authentication); |
|
SecurityContextHolder.getContext().getAuthentication(authentication); |
UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken은 Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로, User의 ID가 Principal 역할을 하고, Password가 Credential의 역할을 한다. UsernamePasswordAuthenticationToken의 첫 번째 생성자는 인증 전의 객체를 생성하고, 두번째는 인증이 완료된 객체를 생성한다.
|
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer { |
|
} |
|
|
|
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken { |
|
|
|
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; |
|
|
|
// 주로 사용자의 ID에 해당 |
|
private final Object principal; |
|
|
|
// 주로 사용자의 PW에 해당 |
|
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 |
|
} |
|
} |
AuthenticationManager
인증에 대한 부분은 AuthenticationManager를 통해서 처리하게 되는데, 실질적으로는 AuthenticationManager에등록된 AuthenticationProvider에 의해 처리된다. 인증에 성공하면 두번째 생성자를 이용해 객체를 생성하여 SecurityContext에 저장한다.
|
public interface AuthenticationManager { |
|
|
|
Authentication authenticate(Authentication authentication) throws AuthenticationException; |
|
|
|
} |
AuthenticationProvider
AuthenticationProvider에서는 실제 인증에 대한 부분을 처리하는데, 인증 전의 Authentication 객체를 받아서 인증이 완료된 객체를 반환하는 역할을 한다. 아래와 같은 인터페이스를 구현해 Custom한 AuthenticationProvider를 작성하고 AuthenticationManager에 등록하면 된다.
|
public interface AuthenticationProvider { |
|
|
|
Authentication authenticate(Authentication authentication) throws AuthenticationException; |
|
|
|
boolean supports(Class<?> authentication); |
|
|
|
} |
ProviderManager
AuthenticationManager를 implements한 ProviderManager는 AuthenticationProvider를 구성하는 목록을 갖는다.
|
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean { |
|
|
|
public List<AuthenticationProvider> getProviders() { |
|
return this.providers; |
|
} |
|
|
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException { |
|
Class<? extends Authentication> toTest = authentication.getClass(); |
|
AuthenticationException lastException = null; |
|
AuthenticationException parentException = null; |
|
Authentication result = null; |
|
Authentication parentResult = null; |
|
int currentPosition = 0; |
|
int size = this.providers.size(); |
|
|
|
// for문으로 모든 provider를 순회하여 처리하고 result가 나올때까지 반복한다. |
|
for (AuthenticationProvider provider : getProviders()) { ... } |
|
} |
|
} |
UserDetailsService
UserDetailsService는 UserDetails 객체를 반환하는 하나의 메소드만을 가지고 있는데, 일반적으로 이를 implements한 클래스에 UserRepository를 주입받아 DB와 연결하여 처리한다.
|
public interface UserDetailsService { |
|
|
|
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; |
|
|
|
} |
UserDetails
인증에 성공하여 생성된 UserDetails 객체는 Authentication객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용된다. UserDetails를 implements하여 처리할 수 있다.
|
public interface UserDetails extends Serializable { |
|
|
|
// 권한 목록 |
|
Collection<? extends GrantedAuthority> getAuthorities(); |
|
|
|
String getPassword(); |
|
|
|
String getUsername(); |
|
|
|
// 계정 만료 여부 |
|
boolean isAccountNonExpired(); |
|
|
|
// 계정 잠김 여부 |
|
boolean isAccountNonLocked(); |
|
|
|
// 비밀번호 만료 여부 |
|
boolean isCredentialsNonExpired(); |
|
|
|
// 사용자 활성화 여부 |
|
boolean isEnabled(); |
|
|
|
} |
GrantedAuthority
GrantedAuthority는 현재 사용자(Principal)가 가지고 있는 권한을 의미하며, ROLE_ADMIN이나 ROLE_USER와 같이 ROLE_*의 형태로 사용한다. GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지를 검사하여 접근 허용 여부를 결정한다.
출처: https://dev-coco.tistory.com/174 [슬기로운 개발생활:티스토리]
'Spring Boot' 카테고리의 다른 글
[Spring Boot] JPA 이용하여 게시판 구현_페이징 처리(2) (0) | 2022.12.08 |
---|---|
[Spring Boot] DB 테이블 대소문자 오류 (0) | 2022.12.06 |
[Spring Boot] JPA 이용하여 게시판 구현_페이징 처리(1) (1) | 2022.12.02 |