스프링은 아래와 같은 로그인 방식들을 지원한다.
Username Password Authentication
Basic Authentication
OAuth2 로그인
JWT 토큰(Bearer 토큰)
스프링에서는 인증 처리는 세션과는 별도로 동작하도록 설계되어 있다. 그래서 session을 사용하던 사용하지 않던 Authentication과 AuthenticationProvider를 사용할 수 있다.
스프링의 인증을 유지시켜주기 위해서는 session을 이용하는 것이 개발자에게는 여러모로 편리하다. 이후 인증은 서버가 메모리를 소모해서 세션객체를 가지고 유지시켜주는 작업을 하도록 할 수 있다. 세션은 브라우저의 쿠키에 JSESSIONID 값을 심어놓고, 브라우저와 서버가 이 값을 주고받으면서 세션을 보장받을 수 있다.
그런데 서버의 세션 정책과 스프링의 인증 체계가 서로 맞물려 동작하도록 하려면 SecurityContextPersistenceFilter와 RememberMeAuthenticationFilter, AnonymousAuthenticationFilter 등과 같이 인증을 보조해 주는 다른 필터들의 도움을 받아야 한다.
SecurityContextRepository에 저장된 SecurityContext를 Request의 LocalThread에 넣어주었다가 뺐는 역할을 한다. doFilter 메소드를 따라가보면 알 수 있다. 세션에 SecurityContext를 보관했다가 다음 request에서 넣어준다.
인증 정보를 세션 관리하는 경우, 세션 timeout이 발생하게 되면 remember-me 쿠키를 이용해 기억했다가 자동으로 재로그인 시켜주는 기능이다.
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher(){
@Override
public void sessionCreated(HttpSessionEvent event) {
super.sessionCreated(event);
System.out.printf("===>> [%s] 세션 생성됨 %s \n", LocalDateTime.now(), event.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
super.sessionDestroyed(event);
System.out.printf("===>> [%s] 세션 만료됨 %s \n", LocalDateTime.now(), event.getSession().getId());
}
@Override
public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) {
super.sessionIdChanged(event, oldSessionId);
System.out.printf("===>> [%s] 세션 아이디 변경 %s:%s \n", LocalDateTime.now(), oldSessionId, event.getSession().getId());
}
});
}
@Bean
RememberMeServices rememberMeServices(){
return new TokenBasedRememberMeServices("hello", spUserService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.rememberMe(rememberme->rememberme
.rememberMeServices(rememberMeServices())
);
}
참고