728x90
BasicAuthenticationFilter
- 따로 로그인이라는 과정을 하지 않았는데도 일회성으로 페이지를 불러올 수 있다. 로그인 데이터를 Base64로 인코딩해서 모든 요청에 포함해서 보내면 BasicAuthenticationFilter는 이걸 인증한다.
- 세션이 필요 없고 요청이 올때마다 인증이 이루어 집니다. (즉 stateless합니다.)
- 이런 방식은 요청할 때마다 아이디와 비밀번호가 반복해서 노출되기 때문에 보안에 취약
BasicAuthenticationFilter를 사용할 때는 반드시 https를 사용하도록 권장됨 - BasicAuthenticationFilter를 사용하지 않을 것이라면 명시적으로 disable시켜주는 것이 좋다
@Override
protected void configure(HttpSecurity http) throws Exception {
// basic authentication
http.httpBasic(); // basic authentication filter 활성화
http.httpBasic().disable(); // basic authentication filter 비활성화
UsernamePasswordAuthenticationFilter
- ProviderManager (AuthenticationManager)
- 인자로 받은 authentication이 유효한지 확인하고 authentication을 반환.
- 인증하면서 계정에 문제가 있는 것이 발견되면 AuthenticationException를 throw 할 수 있다.
- AuthenticationManager를 구현한 것이, ProviderManager
- ProviderManager는 Password가 일치하는지, 계정이 활성화 되어있는지를 확인한 뒤 authentication을 반환한다.
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
result = provider.authenticate(authentication);
}
}
- DaoAuthenticationProvider(AbstractUserDetailsAuthenticationProvider)
- 유저를 인증하기 위해서는 어쨌든 먼저 유저정보를 가져와야함
- DaoAuthenticationProvider는 유저정보를 가져오는 Provider이다.
public abstract class AbstractUserDetailsAuthenticationProvider {
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = determineUsername(authentication);
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
}
}
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
return loadedUser;
}
}
public UserDetailsService userDetailsService() {
return username -> {
User user = userService.findByUsername(username);
if (user == null) {throw new UsernameNotFoundException(username);}
return user;
}
}
CsrfFilter
- CsrfFilter는 CsrfAttack을 방어하는 Filter
- 위조된 페이지를 구분하기 위해서 CSRF토큰 진위여부를 확인하는 방법
- Csrf Token을 사용하여 위조된 페이지의 악의적인 공격을 방어
- 위조된 페이지를 구분하기 위해서 CSRF토큰 진위여부를 확인하는 방법
- 정상적인 페이지는 Csrf Token이 있고, 위조된 페이지는 Csrf Token이 없거나 잘못된 Csrf Token을 가지고 있다.
- Tymeleaf에서는 페이지를 만들때 자동으로 Csrf Token을 넣어준다.
- Csrf Filter는 자동으로 활성화되어있는 Filter지만 명시적으로 On 하기 위해서는 http.csrf(); 코드를 추가
- Off하기 위해서는 http.csrf().disable(); 해줍니다.
RememberMeAuthenticationFilter
- 일반적인 세션보다 훨씬 오랫동안 로그인 사실을 기억할 수 있도록 해줍니다.
- Session의 세션 만료 시간은 기본 설정이 30분이지만 RememberMeAuthenticationFilter의 기본 설정은 2주이다.
// rememberMe() 활성화
http.rememberMe();
<div>
<span>로그인 유지하기</span>
<input type="checkbox" id="remember-me" name="remember-me" class="form-check-input mt-0" autocomplete="off">
</div>
AnonymousAuthenticationFilter
- 인증이 안된 유저가 요청을 하면 Anonymous(익명) 유저로 만들어 Authentication에 넣어주는 필터
- 인증되지 않았다고 하더라도 Null을 넣는게 아니라 기본 Authentication을 만들어 주는 개념
- 다른 Filter에서 Anonymous유저인지 정상적으로 인증된 유저인지 분기 처리를 할 수 있다
Anonymous유저의 SecurityContext
// anonymousAuthenticationFilter 활성화
http.anonymous().principal("anonymousUser");
FilterSecurityInterceptor
- 위의 SecurityContextPersistenceFilter, UsernamePasswordAuthenticationFilter, AnonymousAuthenticationFilter 에서 SecurityContext를 찾거나 만들어서 넘겨주고 있다.
- FilterSecurityInterceptor에서는 위의 Filter로 넘어온 authenticaiton의 내용을 기반으로 최종 인가 판단을 내린다.
- 인증에 문제가 있다면 AuthenticationException를 발생한다.
- 인증에 문제가 없다면 해당 인증으로 인가를 판단한다. 인가가 거절된다면 AccessDeniedException를 발생시킨다.
- 승인된다면 정상적으로 필터가 종료
3. 아키텍처
ExceptionTranslationFilter
- FilterSecurityInterceptor에서 발생할 수 있는 두가지 Exception을 처리해주는 필터
- AuthenticationException : 인증에실패할때발생
- AccessDeniedException:인가에실패할때발생
- 즉, 인증이나 인가에 실패했을 때 어떤 행동을 취해야하는지를 결정해주는 Filter입니다.
- ExceptionTranslationFilter의 handleSpringSecurityException는 Exception의 종류에 따른 로직을 분산함.
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, RuntimeException exception) throws IOException, ServletException {
if (exception instanceof AuthenticationException) {
handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
} else if (exception instanceof AccessDeniedException) {
handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception)
}
}
728x90
'Server🧤 > SpringSecurity' 카테고리의 다른 글
[SpringSecurity] CustomFilter 생성하기 (0) | 2023.07.17 |
---|---|
[SpringSecurity] SecurityConfig 알아보기 (0) | 2023.07.17 |
[SpringSecurity] Security Filter와 SecurityContextPersistenceFilter (0) | 2023.07.13 |
[Spring] SpringSecurity 아키텍처 (내부구조, ThreadLocal, PasswordSecurity) (0) | 2023.07.13 |
[Spring] Spring Security이란 (0) | 2023.07.12 |