폼 인증
- HTTP 기반의 폼 로그인 인증 메커니즘을 활성화하는 API
- 사용자 인증을 위한 사용자 정의 로그인 페이지를 쉽게 구현할 수 있음
- 따로 설정하지 않으면 스프링 시큐리티가 제공하는 기본 로그인 페이지 사용함
- 사용자는 웹 폼을 통해 자격 증명(user, password)를 제공하고, Spring Security는 HttpServletRequest에서 이 값을 읽어 옴

- FormLoginConfigurer 설정 클래스에서 API 설정
- 내부적으로 UsernamePasswordAuthenticationFilter 가 생성되어 폼 방식의 인증 처리를 담당함

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.formLogin(form -> form
.loginProcessingUrl("/loginProc")
.defaultSuccessUrl("/", true)
.failureUrl("/failed")
.usernameParameter("userId")
.passwordParameter("password")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("autentication : " + authentication);
response.sendRedirect("/home");
}
})
.failureHandler((request, response, exception) -> {
System.out.println("exception : " + exception.getMessage());
response.sendRedirect("/login");
})
.permitAll()
);
return http.build();
}
폼 인증 필터 - UsernamePasswordAuthenticationFilter
[인증 기본 필터] AbstractAuthenticationProcessingFilter
- 스프링 시큐리티는 해당 클래스를 사용자의 자격 증명을 인증하는 기본 필터로 사용
[인증 수행 필터] UsernamePasswordAuthenticationFilter
- AbstractAuthenticationProcessingFilter 를 확장한 클래스
- HttpServletRequest 에서 제출된 사용자 이름과 비밀번호
로부터 인증을 수행
- 인증 수행 필터는 커스텀해서 다른 걸 사용할 수도 있음
DefaultLoginPageGeneratingFilter/DefaultLogoutPageGeneratingFilter
- 로그인 페이지, 로그아웃 페이지 생성 필터
- 인증 프로세스가 초기화될 때 함께 초기화

기본 인증 – httpBasic()
- HTTP 는 액세스 제어와 인증을 위한 프레임워크를 제공하며 가장 일반적인 인증 방식은 "Basic" 인증 방식임
- RFC 7235 표준이며 인증 프로토콜은 HTTP 인증 헤더에 기술되어 있음
- 클라이언트는 인증정보 없이 서버로 접속을 시도
- 서버가 클라이언트에게 인증요구를 보낼 때 401 Unauthorized 응답과 함께 WWW-Authenticate 헤더를 기술해서 realm(보안영역) 과 Basic 인증방법을 보냄
- 클라이언트가 서버로 접속할 때 Base64 로 username 과 password 를 인코딩하고 Authorization 헤더에 담아서 요청함
- 성공적으로 완료되면 정상적인 상태 코드를 반환
주의 사항
- base-64 인코딩된 값은 디코딩이 가능하기 때문에 인증정보가 노출됨!!!
- HTTP Basic 인증은 반드시 HTTPS 와 같이 TLS 기술과 함께 사용해야 함
httpBasic() API
- HttpBasicConfigurer 설정 클래스를 통해 여러 API 들을 설정할 수 있음
- 내부적으로 BasicAuthenticationFilter 가 생성되어 기본 인증 방식의 인증 처리를 담당
기본 인증 필터 - BasicAuthenticationFilter
BasicAuthenticationFilter
- 이 필터는 기본 인증 서비스를 제공하는 데 사용
- BasicAuthenticationConverter 를 사용해서 요청 헤더에 기술된 인증정보의 유효성을 체크하며 Base64 인코딩된 username 과 password 를 추출
- 인증 이후 세션을 사용하는 경우와 사용하지 않는 경우에 따라 처리되는 흐름에 차이 있음
세션을 사용하는 경우 매 요청 마다 인증과정을 거치지 않으나 세션을 사용하지 않는 경우 매 요청마다 인증과정을 거쳐야 함

기억하기 인증 – rememberMe()
RememberMe 인증
- 사용자가 웹 사이트나 애플리케이션에 로그인할 때 자동으로 인증 정보를 기억하는 기능
- UsernamePasswordAuthenticationFilter 와 함께 사용되며, AbstractAuthenticationProcessingFilter 슈퍼클래스에서 훅을 통해 구현
- 인증 성공 시 RememberMeServices.loginSuccess() 를 통해 RememberMe 토큰을 생성하고 쿠키로 전달
- 인증 실패 시 RememberMeServices.loginFail() 를 통해 쿠키를 지움
- LogoutFilter 와 연계해서 로그아웃 시 쿠키를 지움
토큰 생성
기본적으로 암호화된 토큰으로 생성 되어지며 브라우저에 쿠키를 보내고, 향후 세션에서 이 쿠키를 감지하여 자동 로그인이 이루어지는 방식으로 달성
- base64(username + ":" + expirationTime + ":" + algorithmName + ":" algorithmHex(username + ":" + expirationTime + ":" password + ":" + key))
- username: UserDetailsService 로 식별 가능한 사용자 이름
- password: 검색된 UserDetails 에 일치하는 비밀번호
- expirationTime: remember-me 토큰이 만료되는 날짜와 시간, 밀리초로 표현
- key: remember-me 토큰의 수정을 방지하기 위한 개인 키
- algorithmName: remember-me 토큰 서명을 생성하고 검증하는 데 사용되는 알고리즘(기본적으로 SHA-256 알고리즘을 사용)
RememberMeService 구현제
- TokenBasedRememberMeServices - 쿠키 기반 토큰의 보안을 위해 해싱을 사용
- PersistentTokenBasedRememberMeServices -생성된 토큰을 저장하기 위해 데이터베이스나 다른 영구 저장 매체를 사용
- 두 구현 모두 사용자의 정보를 검색하기 위한 UserDetailsService가 필요
rememberMe() API
- RememberMeConfigurer 설정 클래스를 통해 여러 API 들을 설정할 수 있음
- 내부적으로 RememberMeAuthenticationFilter 가 생성되어 자동 인증 처리를 담당
기억하기 인증 필터 - RememberMeAuthenticationFilter
RememberMeAuthenticationFilter
- SecurityContextHolder에 Authentication이 포함되지 않은 경우 실행되는 필터
- 세션이 만료되었거나 어플리케이션 종료로 인해 인증 상태가 소멸된 경우 토큰 기반 인증을 사용해 유효성을 검사하고 토큰이 검증되면 자동 로그인 처리를 수행
익명 인증 사용자 – anonymous()
- 스프링 시큐리티에서 "익명으로 인증된" 사용자와 인증되지 않은 사용자 간에 실제 개념적 차이는 없으며 단지 액세스 제어 속성을 구성하는 더 편리한 방법을 제공한다고 볼 수 있음
- SecurityContextHolder 가 항상 Authentication 객체를 포함하고 null 을 포함하지 않는다는 것을 규칙을 세우게 되면 클래스를 더 견고하게 작성할 수 있음
- 인증 사용자와 익명 인증 사용자를 구분해서 어떤 기능을 수행하고자 할 때 유용할 수 있으며 익명 인증 객체를 세션에 저장하지 않음
- 익명 인증 사용자의 권한을 별도로 운용할 수 있다. 즉 인증 된 사용자가 접근할 수 없도록 구성이 가능!!
로그 아웃 – logout()
- 스프링 시큐리티는 기본적으로 DefaultLogoutPageGeneratingFilter 를 통해 로그아웃 페이지를 제공하며 “ GET / logout ” URL 로 접근이 가능
- 로그아웃 실행은 기본적으로 “ POST / logout “ 으로만 가능하나 CSRF 기능을 비활성화 할 경우 혹은 RequestMatcher 를 사용할 경우 GET, PUT, DELETE 모두 가능
- 로그아웃 필터를 거치지 않고 스프링 MVC 에서 커스텀 하게 구현할 수 있으며 로그인 페이지가 커스텀하게 생성될 경우 로그아웃 기능도 커스텀하게 구현해야 함
logout() API

LogoutFilter

요청 캐시 RequestCache / SavedRequest
RequestCache
- 인증 절차 문제로 리다이렉트 된 후에 이전에 했던 요청 정보를 담고 있는 'SavedRequest’ 객체를 쿠키 혹은 세션에 저장하고 필요시 다시 가져와 실행하는 캐시 메커니즘
SavedRequest
- SavedRequest 은 로그인과 같은 인증 절차 후 사용자를 인증 이전의 원래 페이지로 안내하며 이전 요청과 관련된 여러 정보를 저장

requestCache() API

RequestCacheAwareFilter
- 이전에 저장했던 웹 요청을 다시 불러오는 역할
- SavedRequest가 현재 Request와 일치하면 이 요청을 필터 체인의 doFilter 메소드에 전달하고, SavedRequest가 없으면 필터는 원래 Request 을 그대로 진행