일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 방어적복사
- java
- RDBMS
- 얕은복사
- 인덱스
- 데이터베이스
- mutable
- 자료구조
- 정규화
- transaction
- NoSQL
- index
- binarySearch
- 깊은복사
- 불변객체
- 알고리즘
- immutable
- ERD
- Database
- reverse프록시
- proxy
- 조인
- acid
- forward프록시
- 프록시서버
- 이진탐색
- Today
- Total
jacketList
[Spring Boot]Spring Security란? 본문
Spring Security란?
spring기반 애플리케이션의 보안(인증 과 인가 등)을 담당하는 스프링 기반 하위 프레임워크
인증(Authentication)은 말 그대로 사용자가 인증하는 과정을 뜻하며
인가(Authorization)는 서버가 사용자에 대한 권한을 부여하는 것
Spring Secruity에서는 principal을 아이디로, Credential을 비밀번호로 사용하는 Credential기반 인증 방식 사용
- principal(접근 주체): 보호받는 Resource에 접근하는 대상
- credential(비밀번호): Resource에 접근하는 대상의 비밀번호
Spring Secruity의 특징과 구조
- 보안과 관련하여 체계적으로 많은 옵션을 제공하여 편리하게 사용 가능
- Filter기반으로 동작하여 MVC와 분리하여 동작 가능
- 기본적으로 세션&쿠키 방식으로 인증
- 인증관리자(Authentication Manager)와 접근 결정 관리자(Access Decision Manager)를 통해 사용자의 리소스 접근 관리
Filter는 Dispatcher Servlet으로 가기 전에 적용되므로 가장 먼저 URL 요청을 받지만, (웹 컨테이너에서 관리)
Interceptor는 Dispatcher와 Controller 사이에 위치한다는 점에서 적용 시기의 차이가 있다. (스프링 컨테이너에서 관리)
Client (request) → Filter → DispatcherServlet → Interceptor → Controller
(실제로 Interceptor가 Controller로 요청을 위임하는 것은 아님, Interceptor를 거쳐서 가는 것)
- 사용자가 Form을 통해 로그인 정보를 입력하고 인증 요청을 보낸다.
- AuthenticationFilter(사용할 구현체UsernamePasswordAuthenticationFilter)가 HttpServletRequest에서 사용자가 보낸 아이디와 패스워드를 인터셉트 한다. -> 꺼내온 사용자 아이디와 패스워드를 진짜 인증을 담당할 AuthenticationManager인터페이스(구현체 ProviderManager)에게 인증용 객체( UsernamePasswordAuthenticationToken)로 만들어줘서 위임한다.
- AuthenticationFilter에게 인증용 객체(UsernamePasswordAuthenticationToken)를 전달받는다.
- 실제 인증을 할 AuthenticationProvider에게 Authentication객체 (UsernamePasswordAuthenticationToken)를 다시 전달한다.
- DB에서 사용자 인증 정보를 가져올 UserDetailService객체에게 사용자 아이디를 넘겨주고 DB에서 인증에 사용할 사용자 정보(사용자 아이디, 암호화된 패스워드, 권한 등)를 UserDetails(인증용 객체와 도메인 객체를 분리하지 않기 위해 실제 사용되는 도메인 객체에 UserDetails를 상속하기도 한다.)라는 객체로 전달 받는다.
- AuthenticaitonProvider는 UserDetails 객체를 전달받은 이후 실제 사용자의 입력정보와 UserDetails 객체를 가지고 인증을 시도한다.
- 인증이 완료되면 사용자 정보를 가진 Authentication 객체를 SecurityContextHolder에 담은 이후 AuthenticationSuccessHandle를 실행한다.
Spring Security 모듈
- SpringContextHolder
보안 주체의 세부 정보를 포함하여 응용프로그램의 현재 보안 컨텍스트에 대한 세부 정보가 저장된다.
- SecurityContext
Authentication을 보관하는 역할을 하며, SecurityContext를 통해 Authentication객체를 가져올 수 있다.
- Authentication
현재 접근하는 주체의 정보와 권한을 담은 인터페이스
Authentication 객체는 Security Context에 저장되며, SecurityContextHolder를 통해 SecurityContext에 접근하고, SecurityContext를 통해 Authentication 객체에 접근할 수 있다.
public interface Authentication extends Principal, Serializable {
// 현재 사용자의 권한 목록을 가져옴
Collection<? extends GrantedAuthority> getAuthorities();
// credential(주로 비밀번호)을 가져옴
Object getCredentials();
Object getDetails();
// Principal 객체를 가져옴
Object getPrincipal();
// 인증 여부를 가져옴
boolean isAuthenticated();
// 인증 여부를 설정함
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
- UsernamePasswordAuthenticationToken
Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로 User의 ID가 Principal역할을 하고, Password가 Credential의 역할을 한다.
UsernamePasswordAuthenticationToken의 첫 번째 생성자는 인증 전의 객체를 생성하고, 두 번째 생성자는 인증이 완료된 객체를 생성한다.
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
// 주로 사용자의 ID
private final Object principal;
// 주로 사용자의 password
private Object credentials;
// 인증 완료 정의 객체 생성
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false); // super.setAuthenticated(false);
}
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
supter.setAuthenticated(true);
}
// .. 생략 ..
}
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
}
- AuthenticationProvider
실제 인증에 대한 부분을 처리하는데, 인증 전의 Authentication객체를 받아서 인증이 완료된 객체를 반환하는 역할을 한다. 아래와 같은 AuthenticationProvider인터페이스를 구현해서 Custom한 AuthenticationProvider를 작성해서 AuthenticationManager에 등록하면 된다.
public interface AuthenticationProvider {
// 인증 전의 Authentication 객체를 받아서 인증된 Authentication 객체를 반환
Authentication authenticate(Authentication var1) throws AuthenticationException;
boolean supports(Class<?> var1);
}
- AuthenticationManager
인증에 대한 부분은 AuthenticationManager를 통해 처리하는데 AuthenticationManager에 등록된 AuthenticationProvider에 의해 처리된다. 인증에 성공하면 2번째 생성자를 이용해 인증이 성공한(isAuthenticated = true) 객체를 생성하여 SecurityContext에 저장한다. 인증 상태를 유지하기 위해 세선에 보관하며, 인증이 실패한 경우에는 AuthenticationException을 발생시킨다.
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
AuthenticationManager를 implements한 ProviderManager는 실제 인증 과정에 대한 로직을 갖고있는 AuthenticationProvider를 List로 가지고 있으며, ProviderManager는 loop를 통해 모든 provider를 조회하면서 authenticate 를 처리한다.
- UserDetails
인증에 성공하여 생성된 UserDetail는 Authentication 객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용된다. UserDetails인턴페이스를 살펴보면 아래와 같은 정보를 반환하는 메소드를 가지고 있다.
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNotExpried();
boolean isAccountNonLocked();
boolean isCrendentailsNotExpired();
boolean isEnabled();
}
- UserDetailsService
UserDetails 객체를 반환하는 단 하나의 메소드를 가지고 있는데 일반적으로 UserRepository에서 주입하여 DB와 연결하여 처리한다.
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException
}
- PasswordEncoding
AuthenticationManagerBuilder.userDetailsService().passwordEncoder()를 통해 패스워드 암호화에 사용될 PasswordEncoder구현체를 지정할 수 있다.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
- GrantedAuthority
GrantAuthority는 현재 사용자(principal)가 가지고 있는 권한을 의미한다.
ROLE_ADMIN이나 ROLE_USER와 같이 ROLE_*의 형태로 사용하며, 보통 "roles"라고 한다. GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지를 검사하여 접근 허용 여부를 결정한다.
Refer: